Files
d4rkbot/README.md
T
D4rkst3randClaude Fable 5 19ec2802ac Tickets: Transcript beim Schließen + Thread-Löschung
- Schließen-Button erstellt jetzt ein Text-Transcript (chronologisch, inkl.
  Attachment-URLs, max 500 Nachrichten) und schickt es dem Ersteller per DM
- Kopie ins Mod-Log (Aufbewahrung fürs Team, mit Hinweis falls DM blockiert)
- Thread wird danach gelöscht statt nur archiviert (Fallback: sperren+archivieren,
  falls dem Bot Lösch-Rechte fehlen)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 01:11:16 +02:00

17 KiB

d4rkbot — D4RKST3R // COMMUNITY BOT

Discord-Bot + Webinterface: Devlog-Tagebuch, Commit-Feed, Changelog und Community-Tools für die EcoGame-Entwicklung — alles gebrandet, alles über die Setup-Seite steuerbar.

Stack: Node.js 20+ (ESM), discord.js v14, Fastify 5, React 19 + Vite, SQLite (better-sqlite3, FTS5), Docker Multi-Stage — deploybar als Portainer-Stack.


Features

Discord

Feature Beschreibung
📔 Devlog-Posts tools/devlog.py (EcoGame-Repo) schickt Prosa + Bilder an den Bot-Endpoint → gebrandetes Embed (Datum-Titel, Author-Zeile, Commit-Zähler im Footer, Bilder-Grid, Link-Buttons)
💬 Auto-Threads Diskussions-Thread unter jedem Devlog-Post („💬 Devlog 23.07.")
🔔 Rollen-Ping Ping-Rolle beim Devlog-Post; Member abonnieren sie selbst über den 🔔-Button
📦 Commit-Feed Gitea-Push-Webhooks → Embeds in den (privaten) Commit-Kanal
🚀 Release-Ankündigungen Neues Gitea-Release → oranges Ankündigungs-Embed
📊 Wochen-Rückblick Sonntags 20:00 automatisch: Commits pro Tag als Balken, Devlogs, Top-Projekte
🐛 /bug Member melden Bugs → Gitea-Issue (inkl. Screenshot-Upload); Issue geschlossen → DM an den Reporter
🚨 Watchdog Prüft eigene Dienste alle 2 min, DM-Alarm bei Ausfall + Entwarnung
🧪 Playtester-Programm /playtester-setup postet den Bewerbungs-Button; Rolle + Liste (Setup-Seite); Alpha-Keys später per DM über die API
Starboard Nachrichten mit genug -Reaktionen landen automatisch im Best-of-Kanal
📸 Screenshot-Galerie Bilder aus dem Screenshot-Kanal → öffentliche /galerie (lokal gespeichert); Historie via /galerie-backfill
📬 Modmail DM an den Bot → Thread im privaten Staff-Kanal; Antworten im Thread gehen als DM zurück
🎫 Tickets /ticket-setup postet den Button; Klick öffnet einen privaten Thread (ein offenes Ticket pro User). Schließen = Transcript per DM an den Ersteller + Kopie ins Mod-Log, Thread wird gelöscht
🎭 Rollen-Menüs Carl-Bot-Ersatz: Menüs im Webinterface bauen (Emoji, Label, Rolle, optional exklusiv), Bot postet Button-Embeds; Klick = Rolle nehmen/abgeben, Posts jederzeit editierbar
🛡️ Moderation /warn (DM + Historie), /warns, /timeout, /purge — alles im Mod-Log; dazu Join/Leave- und Nick-/Rollen-Änderungs-Logging
🪪 Auto- & Sticky-Roles Start-Rolle für neue Member; Rollen werden bei Leave gesichert und bei Rejoin wiederhergestellt
📈 Level-System XP pro Nachricht (60s-Cooldown, MEE6-Formel), /rank, Level-Up-Announce, Rollen-Belohnungen, öffentliche Bestenliste auf /level
🏷️ Tags /tag <name> (mit Autocomplete) postet gespeicherte Text-Bausteine — verwaltet im Composer-Tab
Geplante Posts Einmalig, täglich oder wöchentlich — im Composer-Tab geplant, vom Bot gepostet (bei Carl Premium)
🎨 Branding Brand-Tab mit Bot-Identity-Karte (Avatar-Vorschau, Name, Status online/idle/dnd, Aktivität), Embed-Farben, Banner-Upload, Guild-ID & Gitea-Token ohne Env-Redeploy
🎟️ Alpha-Keys Key-Pool im Community-Tab; Ein-Klick-Verteilung an alle Playtester per DM
📋 Bewerbungen Formulare (bis 5 Fragen) als Discord-Modal, Review mit / im Staff-Kanal, Rolle + DM bei Annahme — z. B. FiveM-Whitelist
📅 Events Neue Discord-Events werden angekündigt + öffentliche /events-Seite
💬 Triggers Auto-Antworten auf Schlüsselwörter (30s-Cooldown), verwaltet im Composer-Tab
/remind Erinnerungen per DM (/remind dauer:2h text:…)
📣 Twitch/YouTube 🔴-Live- und ▶️-Neues-Video-Announcements (YouTube ohne Key via RSS, Twitch mit App-Credentials)
🔊 Temp-Voice „Join to Create": Hub-Kanal betreten → eigener Voice-Kanal, löscht sich wenn leer
📊 Server-Stats Nachrichten/Joins/Leaves pro Tag → Aktivitäts-Chart auf der Level-Seite
👋 Willkommens-Embed Begrüßung neuer Member im Brand-Look (braucht Server-Members-Intent)
📋 Mod-Log Gelöschte/bearbeitete Nachrichten in einen privaten Log-Kanal
🎮 Server-Monitor FiveM-kompatible Game-Server (/dynamic.json): Live-Status-Embed + Spielerzahl in der Bot-Presence
💡 Feature-Voting /wunsch → Voting-Post mit 👍; Top-Wünsche öffentlich auf der Roadmap-Seite
🎉 Giveaways /giveaway (Admin): Teilnahme-Button, automatische Ziehung nach Ablauf
📈 Contribution-Heatmap GitHub-Style-Jahreskalender aus dem Commit-Archiv auf der Roadmap-Seite
🏓 /ping, 🗄 /devlog-backfill Lebenszeichen · Kanal-Historie nacharchivieren (Admin)

Webinterface (bot.d4rkst3r.de)

Seite Zugriff Inhalt
/devlogs öffentlich Devlog-Archiv: Timeline, Bildergalerien, Projekt-Chips, Volltextsuche
/roadmap öffentlich Meilensteine aus Gitea mit Fortschrittsbalken
/galerie öffentlich Community-Screenshots aus dem Discord
/level öffentlich XP-Bestenliste + Server-Aktivitäts-Chart
/events öffentlich Discord-Events (Playtests, Streams …)
/changelog öffentlich Alle Releases mit Notes, Tag- und Pre-Release-Chips
/feed.xml öffentlich RSS-Feed der Devlogs
/commits nur Admin Archivierte Commits aller Repos (SHA → Gitea-Link)
/settings nur Admin Setup-Seite — siehe unten

Login via Discord-OAuth2 (identify-Scope, signierte Session-Cookies, keine Token-Speicherung). Design: D4RKST3R-Brand (Neon-Gelb/Orange auf Schwarz, Bebas Neue + Barlow Condensed + Share Tech Mono, selbst gehostet).

Setup-Seite (/settings)

Aufgeteilt in Tabs mit Sidebar-Navigation (Status · Brand · Feeds · Community · Rollen · Support · Composer · System · API). Alles zur Laufzeit änderbar — gespeichert in SQLite, Env-Variablen sind nur Fallback, kein Redeploy nötig:

  • Allgemein: Öffentliche URL, Gitea-URL
  • Kanäle (Devlog / Commit / Release) als Dropdown + „Test senden"-Button je Kanal
  • Devlog: Ping-Rolle, Auto-Threads, Wochen-Rückblick (+ Sofort-Test)
  • Commit-Feed: an/aus, Branch-Filter, ignorierte Repos (gefiltert wird nur das Posten — archiviert wird immer)
  • Community: Playtester-Rolle (+ Liste), Starboard-Kanal + -Schwellwert, Screenshot-Kanal, Voting-Kanal
  • Moderation & Kontakt: Modmail-, Willkommens-, Mod-Log-Kanal
  • Game-Server: Status-Kanal + Server-Liste (Name=URL, FiveM-kompatibel)
  • Bug-Reports / Roadmap: Ziel-Repos
  • Backups: an/aus, Upload-Kanal, „Backup jetzt"
  • Watchdog: überwachte URLs
  • API-Keys: erstellen (Name + Scopes), widerrufen, last-used
  • Status-Panel: Bot-Account, Uptime, Devlog-/Commit-Zahlen, DB-Größe, letztes Backup

Ersteinrichtung

1. Discord-App (Developer Portal)

  1. New Application → Name vergeben
  2. General Information → Application ID = DISCORD_CLIENT_ID
  3. Bot → Reset Token = DISCORD_TOKEN (wird nur einmal angezeigt!) und Message Content Intent + Server Members Intent aktivieren (Devlog-Listener bzw. Willkommens-Embeds)
  4. OAuth2 → Client Secret = DISCORD_CLIENT_SECRET; unter Redirects eintragen:
    • https://bot.d4rkst3r.de/auth/callback
    • http://localhost:3080/auth/callback (lokale Entwicklung)
  5. OAuth2 → URL Generator: Scopes bot + applications.commands; Permissions: Send Messages, Embed Links, Attach Files, Read Message History, Create Public Threads, Manage Roles (für den 🔔-Abo-Button) → URL öffnen, Bot einladen
  6. In Discord: Entwicklermodus an → Server-ID = DISCORD_GUILD_ID, eigene User-ID = ADMIN_DISCORD_ID

⚠️ Kanal-Overrides: In Kanälen, in denen @everyone nicht schreiben darf, braucht der Bot eigene Overrides (Kanal ansehen, Nachrichten senden, Links einbetten, Dateien anhängen, Threads erstellen). Die Bot-Rolle muss über der Ping-Rolle stehen.

2. Environment-Variablen

Vorlage: .env.example — lokal als .env (gitignored), in Portainer als Stack-Environment-Variables.

Variable Pflicht Zweck
DISCORD_TOKEN Bot-Token
DISCORD_CLIENT_ID Application ID
DISCORD_CLIENT_SECRET OAuth2-Login
SESSION_SECRET Session-Cookies signieren¹
ADMIN_DISCORD_ID Deine User-ID (Admin-Zugriff + Watchdog-DMs)
GITEA_WEBHOOK_SECRET HMAC-Prüfung der Gitea-Webhooks¹
DEVLOG_POST_SECRET Secret im Devlog-Endpoint-Pfad¹
DISCORD_GUILD_ID optional Guild-Commands sofort statt global (bis 1h)
GITEA_API_TOKEN optional Für /bug → Issues (Scope write:issue); alternativ im Brand-Tab hinterlegen
GITEA_URL optional Default https://git.d4rkst3r.de
PUBLIC_URL optional Default https://bot.d4rkst3r.de
COMMIT_CHANNEL_ID / DEVLOG_CHANNEL_ID optional Fallbacks — Kanäle kommen normal von der Setup-Seite
TZ optional Default Europe/Berlin (Wochen-Rückblick, Datumsformate)

¹ Generieren: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

3. Routing (einmalig eingerichtet)

Cloudflare: CNAME bot → Zone, Proxied. Nginx Proxy Manager: bot.d4rkst3r.dehost.docker.internal:3080, Block Common Exploits, Force SSL. Test: https://bot.d4rkst3r.de/health{"status":"ok"}

4. Gitea-Webhook (systemweit oder pro Repo)

  • Typ Gitea, URL https://bot.d4rkst3r.de/webhooks/gitea, Content Type application/json, Geheimnis = GITEA_WEBHOOK_SECRET
  • Trigger-Events: Push, Release, Issues (Push = Commit-Feed · Release = Ankündigungen/Changelog · Issues = Bug-Rückkanal-DMs)

5. devlog.py (EcoGame-Repo)

In tools/.devlog_webhook steht die Bot-Endpoint-URL:

https://bot.d4rkst3r.de/webhooks/devlog/<DEVLOG_POST_SECRET>

Workflow: Prosa nach tools/devlog_today.txt (+ Bilder in devlog_images/, max 4) → python tools/devlog.py (oder Task täglich 21:00) → Bot postet + archiviert, Prosa-Datei und Bilder werden danach gelöscht (gepostet = erledigt). Ohne Prosa postet das Skript nichts (Schutz des öffentlichen Kanals). Der Endpoint versteht das Discord-Webhook-Format (JSON + Multipart) — devlog.py kennt den Bot also gar nicht.


Deployment (Portainer)

  1. Stacks → Add stack → Name ecobot (Bestands-Stack behalten! Der Name steckt im Volume-Prefix) → Build method Repository
    • URL https://git.d4rkst3r.de/D4rkst3r/d4rkbot, Reference refs/heads/main, Compose path docker-compose.yml
    • Privates Repo: Authentication mit Gitea-Token (Scope read:repository)
  2. Environment-Variablen eintragen (Tabelle oben)
  3. Deploy the stack

Updates: Stack öffnen → Pull and redeploy („Re-pull image" aus lassen — das Image wird lokal gebaut, nicht aus einer Registry gezogen).

Daten liegen im Volume ecobot_data (/app/data): SQLite (ecobot.db, WAL)

  • Devlog-Bilder (devlog_images/ — lokal gespeichert, weil Discord-CDN-Links ablaufen).

Manuell statt Portainer:

git clone git@gitea:D4rkst3r/d4rkbot.git && cd d4rkbot
cp .env.example .env   # Werte eintragen
docker compose up -d --build
docker logs -f d4rkbot

Lokale Entwicklung

npm install
npm run dev            # Bot + API auf :3080 (Werte aus .env)

Frontend mit Hot-Reload:

cd frontend
npm install
npm run dev            # Vite auf :5173, proxied /api + /auth → :3080

Alternativ npm run build im frontend/ — der Bot liefert frontend/dist dann selbst unter :3080 aus (so läuft es auch im Container, Multi-Stage-Build).

Commit-Feed ohne Gitea testen (signierte Fake-Testzustellung):

node tools/test-webhook.mjs

API v1 — für eigene Skripte & Dienste

Der Bot ist die zentrale Discord-Brücke der Infrastruktur: devlog.py, Platform, FiveM-Server, CI-Jobs … reden alle mit einer API statt mit zig Discord-Webhooks.

Auth: API-Keys auf der Setup-Seite erstellen (Name + Scopes, Key wird einmalig angezeigt, Widerruf jederzeit). Jeder Request:

Authorization: Bearer d4rk_<key>
Endpoint Scope Body / Antwort
POST /api/v1/message message { channel_id, content?, embed? } → postet als Bot (Embed: title, description, color, url, image, thumbnail, footer, fields)
PATCH /api/v1/message message { channel_id, message_id, content?, embed? } → eigenen Bot-Post bearbeiten
POST /api/v1/dm dm { user_id, content } → Direktnachricht
POST /api/v1/roles roles { user_id, role_id, action: "add"|"remove" } → Rolle vergeben (z. B. Shop-Kauf → Kunden-Rolle)
GET /api/v1/member/:id read Member-Info: Name, Rollen, Beitritt — für Login-/Berechtigungs-Checks
GET /api/v1/stats read Devlog-/Commit-Zahlen, Guilds, Uptime

Beispiel (Python):

import urllib.request, json
req = urllib.request.Request(
    "https://bot.d4rkst3r.de/api/v1/message",
    data=json.dumps({"channel_id": "123", "embed": {"title": "Build fertig ✅", "color": 0xF5C518}}).encode(),
    headers={"Content-Type": "application/json",
             "Authorization": "Bearer d4rk_...",
             "User-Agent": "mein-script/1.0"})
urllib.request.urlopen(req)

HTTP-Endpoints

Route Auth Zweck
GET /health Healthcheck
POST /webhooks/gitea HMAC-Signatur Push / Release / Issues von Gitea
POST /webhooks/devlog/:secret Secret im Pfad Devlog von devlog.py (JSON/Multipart)
GET /api/devlogs?page=&q= Archiv + FTS5-Volltextsuche
GET /api/releases · /api/roadmap · /api/gallery · /api/wishes · /api/heatmap Changelog · Milestones · Galerie · Wunsch-Ranking · Commit-Heatmap
GET /feed.xml RSS
GET /devlog-assets/* · /gallery-assets/* Lokal gespeicherte Bilder
GET /api/playtesters Admin Playtester-Liste
POST/GET /api/v1/* API-Key (Bearer) Externe Skripte — siehe „API v1" oben
GET/POST/DELETE /api/apikeys Admin API-Key-Verwaltung
GET/POST/PUT/DELETE /api/rolemenus, POST /api/rolemenus/:id/publish Admin Rollen-Menüs
GET/PUT /api/settings, POST /api/settings/test/:target Admin Setup-Seite
GET /api/commits?page= · DELETE /api/devlogs/:id Admin Commit-Archiv · Devlog löschen
GET /auth/login · /auth/callback · /auth/logout Discord-OAuth2

Devlogs, die in Discord gelöscht werden, verschwinden automatisch auch aus dem Archiv (MessageDelete-Sync) — zusätzlich gibt es den ✕-Button für Admins auf der Webseite.


Projektstruktur

d4rkbot/
├── src/
│   ├── index.js              # Start: Bot, Webserver, Wochen-Rückblick, Watchdog
│   ├── config.js             # Env-Konfiguration mit Validierung
│   ├── db.js                 # SQLite: Schema, Migrationen, FTS5, alle Queries
│   ├── runtime-settings.js   # Effektive Settings (DB vor Env)
│   ├── gitea-api.js          # Gitea-REST (Issues + Assets für /bug)
│   ├── backup.js             # Nächtliche DB-Backups (gzip, Rotation, Upload)
│   ├── bot/
│   │   ├── client.js         # Discord-Client, Commands, Listener, Button-Handler
│   │   ├── commit-feed.js    # Push → Embed
│   │   ├── release-feed.js   # Release → Ankündigungs-Embed
│   │   ├── devlog-archive.js # Nachricht → SQLite (+ Bild-Download)
│   │   ├── community.js      # Starboard + Screenshot-Galerie
│   │   ├── mod-tools.js      # Modmail, Willkommens-Embed, Mod-Log
│   │   ├── server-monitor.js # Game-Server-Status (FiveM-kompatibel)
│   │   ├── giveaways.js      # Giveaway-Ziehung (Scheduler)
│   │   ├── weekly-recap.js   # Sonntags-Zusammenfassung + Scheduler
│   │   ├── watchdog.js       # URL-Checks + DM-Alarm
│   │   └── commands/         # ping, devlog-backfill, bug, playtester-setup,
│   │                         #   galerie-backfill, wunsch, giveaway
│   └── web/
│       ├── server.js         # Fastify: Webhooks, Static, SPA-Fallback
│       ├── auth.js           # Discord-OAuth2 + Session-Cookies
│       ├── api.js            # REST-API + Settings + RSS
│       └── devlog-endpoint.js# Devlog-Post: Embed, Bilder, Ping, Thread, Archiv
├── frontend/                 # React + Vite (D4RKST3R-Design)
│   └── src/
│       ├── App.jsx           # Layout, Router, Nav, Login-Status
│       ├── markdown.jsx      # Mini-Markdown (fett/kursiv/Code/Links/Listen/---/##)
│       └── pages/            # Devlogs, Roadmap, Galerie, Changelog, Commits, Settings
├── tools/test-webhook.mjs    # Lokaler Commit-Feed-Test
├── .env.example              # Vorlage für alle Env-Variablen
├── Dockerfile                # Multi-Stage: Frontend-Build + node:22-slim Runtime
└── docker-compose.yml        # Portainer-ready, Volume ecobot_data, TZ

Neue Slash-Commands: Datei in src/bot/commands/ (exportiert data + execute) und in client.js bei commandModules eintragen. Neue Settings: Key in db.js-Settings nutzen, Zugriff über runtime-settings.js, UI in frontend/src/pages/Settings.jsx, GET/PUT in src/web/api.js.