feat: Discord-Bot über die Oberfläche konfigurierbar

Bisher kam die Discord-Konfiguration (Token, Server-ID, Kanal-ID,
erlaubte Nutzer-IDs) ausschließlich aus Umgebungsvariablen. Jetzt
unter Einstellungen > Discord einstellbar, inkl. Schritt-für-Schritt-
Anleitung zum Einrichten einer Discord-Anwendung/eines Bots (Token
erzeugen, einladen, IDs ermitteln).

- Migration 026: discord_settings (Token verschlüsselt, wie SMTP/IMAP).
- apps/worker/src/discord.ts liest die Einstellungen jetzt aus der DB
  statt aus process.env; syncDiscord() läuft periodisch (60s) und
  verbindet automatisch neu, wenn sich Token/Server/Aktivierung
  geändert haben (Trennung von Verbindungs- und Laufzeitdaten: Kanal-ID
  und erlaubte Nutzer werden bei jeder Nutzung frisch aus der DB
  gelesen, ohne Neuverbindung).
- Neues API-Modul apps/api/src/modules/discord: Einstellungen lesen/
  schreiben, Token- und Testnachricht-Prüfung direkt über die Discord-
  REST-API (unabhängig vom laufenden Bot-Prozess im Worker).
- Rechte discord.read (Admin+) / discord.write (Superadmin), wie beim
  E-Mail-Modul.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Kundencenter 2026-09-28 23:28:24 +02:00
parent 8616e51adc
commit c8da9362a7
8 changed files with 222 additions and 20 deletions

View file

@ -1,7 +1,7 @@
import http from 'node:http';
import { env } from './env.js';
import { pool } from '@kc/platform/db';
import { discordEnabled, discordReady, startDiscord, stopDiscord } from './discord.js';
import { discordEnabled, discordReady, syncDiscord, stopDiscord } from './discord.js';
import { recoverStale, runOnce } from './jobs.js';
import { enqueue } from '@kc/platform/jobs';
import { processContractLifecycle, scheduleDueSyncs } from '@kc/connectors';
@ -21,7 +21,8 @@ http.createServer(async (req, res) => {
}).listen(env.healthPort, '127.0.0.1');
await recoverStale(log);
startDiscord(log).catch((e) => log(`Discord-Start fehlgeschlagen: ${(e as Error).message}`));
void syncDiscord(log);
setInterval(() => void syncDiscord(log), 60_000); // erkennt geänderte Einstellungen (Einstellungen > Discord) und verbindet bei Bedarf neu
setInterval(() => recoverStale(log).catch(() => undefined), 60_000);
// Regelmäßiger Abgleich: fällige Connector-Instanzen als Aufträge einplanen (idempotent pro Zeitfenster)
const schedule = () => scheduleDueSyncs((t, p, o) => enqueue(t, p, o)).catch((e) => log(`Planung fehlgeschlagen: ${(e as Error).message}`));