Moderation & Kontakt + Game-Server-Monitor

- Modmail: DMs an den Bot landen als Threads im privaten Staff-Kanal,
  Thread-Antworten gehen als DM zurück (Zustell-Feedback per Reaktion)
- Willkommens-Embed für neue Member (GuildMemberAdd; Server-Members-Intent nötig)
- Mod-Log: gelöschte/bearbeitete User-Nachrichten in privaten Log-Kanal
- Server-Monitor: FiveM-kompatible Endpoints (/dynamic.json) alle 2 min,
  persistentes Status-Embed (edit in place) + Spielerzahl als Bot-Presence
- Neue Intents: DirectMessages, GuildMembers; Partials.Channel
- Setup-Seite: Sektionen // Moderation & Kontakt und // Game-Server

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 13:14:18 +02:00
co-authored by Claude Opus 4.8
parent a3c47656c5
commit 075ea36bd2
9 changed files with 402 additions and 5 deletions
+19
View File
@@ -178,6 +178,25 @@ export const listGallery = (limit, offset) => ({
total: countGalleryStmt.get().n,
});
// Modmail: DM-Konversationen ↔ Staff-Threads
db.exec(`
CREATE TABLE IF NOT EXISTS modmail (
user_id TEXT PRIMARY KEY,
thread_id TEXT NOT NULL UNIQUE,
username TEXT,
opened_at TEXT NOT NULL DEFAULT (datetime('now'))
);
`);
const upsertModmail = db.prepare(`
INSERT INTO modmail (user_id, thread_id, username) VALUES (?, ?, ?)
ON CONFLICT(user_id) DO UPDATE SET thread_id = excluded.thread_id, username = excluded.username
`);
const modmailByUserStmt = db.prepare('SELECT * FROM modmail WHERE user_id = ?');
const modmailByThreadStmt = db.prepare('SELECT * FROM modmail WHERE thread_id = ?');
export const saveModmail = (userId, threadId, username) => upsertModmail.run(userId, threadId, username);
export const modmailByUser = (userId) => modmailByUserStmt.get(userId) ?? null;
export const modmailByThread = (threadId) => modmailByThreadStmt.get(threadId) ?? null;
// API-Keys für externe Skripte (/api/v1/*) — nur der SHA-256-Hash wird gespeichert
db.exec(`
CREATE TABLE IF NOT EXISTS api_keys (