Bug-Reports, Devlog-Threads und Watchdog

- /bug (alle Member): erstellt Gitea-Issue inkl. Screenshot-Upload als Asset;
  bug_reports-Tabelle für den Rückkanal — Issue geschlossen (issues-Webhook)
  → DM an den Reporter
- Auto-Thread '💬 Devlog <Datum>' unter jedem Devlog-Post (Setting, Default an)
- Watchdog: prüft Setting watchdog_urls alle 2 min, DM an Admin nach 2 Fails
  in Folge + Entwarnung mit Downtime-Dauer
- Setup-Seite: Bug-Repo, Threads-Toggle, Watchdog-URLs; Env GITEA_API_TOKEN/GITEA_URL

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 11:29:01 +02:00
co-authored by Claude Opus 4.8
parent 4fb3a6d02c
commit 07c3bf47d0
15 changed files with 359 additions and 4 deletions
+75
View File
@@ -0,0 +1,75 @@
// /bug — Bug-Report aus Discord: erstellt ein Gitea-Issue (inkl. Screenshot-Upload)
import { SlashCommandBuilder, MessageFlags } from 'discord.js';
import { config } from '../../config.js';
import { bugReportRepo } from '../../runtime-settings.js';
import { createIssue, uploadIssueAsset } from '../../gitea-api.js';
import { saveBugReport } from '../../db.js';
export const data = new SlashCommandBuilder()
.setName('bug')
.setDescription('Bug melden — landet direkt beim Entwickler')
.addStringOption((o) =>
o.setName('titel').setDescription('Kurze Zusammenfassung').setRequired(true).setMaxLength(120)
)
.addStringOption((o) =>
o.setName('beschreibung')
.setDescription('Was ist passiert? Was hast du erwartet?')
.setRequired(true)
.setMaxLength(1500)
)
.addAttachmentOption((o) =>
o.setName('screenshot').setDescription('Optional: Screenshot des Problems')
);
export async function execute(interaction) {
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
if (!config.giteaApiToken) {
await interaction.editReply('❌ Bug-Reports sind gerade nicht konfiguriert (kein Gitea-Token).');
return;
}
const repo = bugReportRepo();
const titel = interaction.options.getString('titel');
const beschreibung = interaction.options.getString('beschreibung');
const screenshot = interaction.options.getAttachment('screenshot');
const body = `${beschreibung}\n\n---\n🎮 Gemeldet via Discord von **${interaction.user.tag}**`;
try {
const issue = await createIssue(repo, `[Bug] ${titel}`, body);
// Screenshot als Issue-Attachment hochladen (Discord-CDN-Links laufen ab)
if (screenshot?.contentType?.startsWith('image/')) {
try {
const res = await fetch(screenshot.url);
if (res.ok) {
await uploadIssueAsset(
repo,
issue.number,
screenshot.name ?? 'screenshot.png',
Buffer.from(await res.arrayBuffer())
);
}
} catch (error) {
console.error('[bug] Screenshot-Upload fehlgeschlagen:', error.message);
}
}
// Für den Rückkanal merken: Issue geschlossen → DM an den Reporter
saveBugReport({
repo,
issue_number: issue.number,
discord_user_id: interaction.user.id,
title: titel,
});
await interaction.editReply(
`✅ Danke! Dein Bug ist erfasst als [#${issue.number}](${issue.html_url}) — ` +
`du bekommst eine DM, sobald er behoben ist.`
);
} catch (error) {
console.error('[bug] Issue-Erstellung fehlgeschlagen:', error);
await interaction.editReply('❌ Konnte das Issue nicht anlegen — bitte später nochmal versuchen.');
}
}