Bisher gab es fuer Mods nur einen Link auf das Sammelpaket des Hosters — vier Gigabyte, auch wenn sich zwei Dateien geaendert haben. Jetzt liest der Bot die Modliste aus der Statusabfrage, die er ohnehin holt, und meldet im Kanal, was neu, aktualisiert oder entfernt wurde. Beim ersten Durchlauf bleibt es still, sonst kaeme eine Meldung ueber 110 "neue" Mods. Geaendert heisst: andere Version oder anderer Hash. Beides einzeln reicht nicht — manche Modder bessern nach, ohne die Version zu erhoehen. Dazu die Seite /mods/<server>: jeder Mod mit Version und Groesse, Suche ueber Titel, Dateiname und Autor, und ein Download je Zeile. Der laeuft durch den Bot, damit der Zugangs-Code des Spielservers nicht in einem Link landet — mit dem Code liesse sich auch der ganze Spielstand lesen. Angefragt wird nur, was wirklich in der Modliste steht; ueber den Dateinamen kommt man an nichts anderes heran. Groessen lernt der Bot beim Weiterleiten. Der Spielserver beantwortet kein HEAD (501) und ignoriert Range, es gibt also keinen billigen Weg, sie vorher zu erfahren — und 4 GB nur fuers Anzeigen zu holen waere keiner. Nebenbei gefunden und behoben: 'server.mods' und 'commands.tag' gab es je zweimal in den Sprachdateien. Der spaetere Eintrag gewinnt still, deshalb stand auf dem neuen Knopf woertlich "%s Mods (110)" und auf der Befehlsseite die Beschreibung von /tag statt der Kopfzeile. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
580 lines
34 KiB
Markdown
580 lines
34 KiB
Markdown
# d4rkbot — D4RKST3R // COMMUNITY BOT
|
|
|
|
Discord-Bot mit Webinterface: Devlog-Tagebuch, Commit-Feed, Changelog,
|
|
Moderation und Community-Werkzeuge für die EcoGame-Entwicklung. Alles
|
|
gebrandet, alles zur Laufzeit über die Config-Seite steuerbar — kein Redeploy,
|
|
keine Paywall.
|
|
|
|
**Stack:** Node.js 20+ (ESM) · discord.js v14 · Fastify 5 · React 19 + Vite ·
|
|
SQLite (better-sqlite3, FTS5) · Docker Multi-Stage, deploybar als Portainer-Stack.
|
|
|
|
---
|
|
|
|
## Inhalt
|
|
|
|
* [Zwei Seiten, ein Bot](#zwei-seiten-ein-bot)
|
|
* [Funktionen](#funktionen) — [Inhalte](#inhalte--feeds) · [Community](#community) · [Moderation](#moderation--support) · [Gaming](#gaming) · [Server](#server--technik) · [Plattform](#plattform)
|
|
* [Webinterface](#webinterface)
|
|
* [Config-Seite](#config-seite-settings)
|
|
* [Ersteinrichtung](#ersteinrichtung)
|
|
* [Deployment](#deployment-portainer) · [Lokale Entwicklung](#lokale-entwicklung)
|
|
* [API v1](#api-v1--für-eigene-skripte--dienste) · [HTTP-Endpoints](#http-endpoints)
|
|
* [Projektstruktur](#projektstruktur)
|
|
* [Weitere Dokumentation](#weitere-dokumentation)
|
|
|
|
---
|
|
|
|
## Zwei Seiten, ein Bot
|
|
|
|
Ein Prozess bedient zwei Domains — welche Seite ausgeliefert wird, entscheidet
|
|
der Host:
|
|
|
|
| Domain | Rolle |
|
|
|---|---|
|
|
| **`bot.d4rkst3r.de`** | Produktseite des Bots: was er kann, welche Befehle es gibt, Dashboard fürs Team |
|
|
| **`hub.d4rkst3r.de`** | Community-Hub: Devlogs, Roadmap, Galerie, Level, Events, Status |
|
|
|
|
Beide teilen sich Anmeldung, Datenbank und Design. Solange die beiden Adressen
|
|
in der Config leer bleiben, verhält sich alles wie eine einzige Seite — das
|
|
Umschalten ist jederzeit reversibel. Details:
|
|
[docs/konzept-zwei-seiten.md](docs/konzept-zwei-seiten.md).
|
|
|
|
Die öffentlichen Seiten gibt es auf **Deutsch und Englisch**; die Sprache
|
|
kommt aus dem Browser und lässt sich oben rechts umschalten. Die Config-Seite
|
|
bleibt bewusst deutsch — sie sieht nur das Team.
|
|
|
|
---
|
|
|
|
## Funktionen
|
|
|
|
**39 Module**, einzeln an- und abschaltbar. Ein ausgeschaltetes Modul reagiert
|
|
auf nichts mehr: keine Posts, keine Hintergrund-Prüfungen.
|
|
|
|
### Inhalte & Feeds
|
|
|
|
| Funktion | 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 → Ankündigungs-Embed + Eintrag im Changelog |
|
|
| 📊 **Wochen-Rückblick** | Sonntags automatisch: Commits pro Tag als Balken, Devlogs, Top-Projekte |
|
|
| 📣 **Twitch / YouTube** | 🔴 Live- und ▶️ Neues-Video-Meldungen (YouTube ohne Key via RSS, Twitch mit App-Credentials) |
|
|
| 🔗 **Link-Vorschau** | Jedes Devlog hat einen Permalink (`/devlogs/:id`); geteilte Links zeigen überall gebrandete Open-Graph-Vorschau mit Bild |
|
|
| 📢 **Auto-Publish** | Posts in Ankündigungs-Kanälen werden automatisch veröffentlicht (Follower bekommen sie) |
|
|
|
|
### Community
|
|
|
|
| Funktion | Beschreibung |
|
|
|---|---|
|
|
| 📈 **Level-System** | XP pro Nachricht (Cooldown, MEE6-Formel), `/rank`, Level-Up-Announce, Rollen-Belohnungen, öffentliche Bestenliste |
|
|
| ⭐ **Starboard** | Nachrichten mit genug ⭐-Reaktionen landen im Best-of-Kanal |
|
|
| 📸 **Screenshot-Galerie** | Bilder aus dem Screenshot-Kanal → öffentliche Galerie (lokal gespeichert, weil Discord-CDN-Links ablaufen) |
|
|
| 💡 **Feature-Voting** | `/wunsch-setup` postet den Ideen-Aufruf: Bereich wählen, Formular ausfüllen → Voting-Post mit 👍 und **Thread zum Reden**. Wünsche haben einen **Stand** (wird geprüft · geplant · in Arbeit · umgesetzt · nicht geplant) samt Begründung — auf der Roadmap und im Discord-Post. Wer gestimmt hat, bekommt eine DM, sobald es umgesetzt ist. Die Roadmap filtert nach Stand und Bereich, sortiert nach Top / Bewegung / Neu und zeigt die Zahl der Beiträge im Thread. Ein Klick öffnet die **eigene Seite der Idee** mit der Unterhaltung aus dem Discord-Thread — gespiegelt samt Screenshots, geschrieben wird weiter dort. Fehlende Forum-Tags legt das Panel auf Knopfdruck an. Ist der Voting-Kanal ein **Forum**, wird jeder Wunsch ein Forums-Beitrag mit **Tags** für Bereich und Stand — der Stand zieht beim Ändern automatisch mit. Eine Stimme je Person, egal ob 👍 oder Web-Knopf; Doppler lassen sich zusammenführen |
|
|
| 🗳️ **Umfragen** | `/umfrage` erzeugt eine **native Discord-Poll** — keine Reaktions-Bastelei, Discord zählt selbst |
|
|
| 🎉 **Giveaways** | `/giveaway` (Admin): Teilnahme-Button, automatische Ziehung; am Gewinner-Post 🔁 Neu auslosen + 👥 Teilnehmerliste |
|
|
| 🎂 **Geburtstage** | `/geburtstag` zum Eintragen; morgens Gratulation im Kanal + Tages-Rolle |
|
|
| 📅 **Events** | Neue Discord-Events werden angekündigt + öffentliche Events-Seite |
|
|
| 🧪 **Playtester-Programm** | Aufnahme läuft über ein **Bewerbungs-Formular**: ausfüllen, das Team nimmt an oder lehnt ab. Wer angenommen wird, bekommt Rolle und Listeneintrag. Eigener Panel-Bereich mit Liste, Rolle und Schlüssel-Vorrat — Playtester lassen sich dort auch wieder entfernen (die Rolle geht mit) |
|
|
| 🎟️ **Alpha-Keys** | Schlüssel-Vorrat im Panel: nachlegen, gezielt an eine Person schicken, an alle Wartenden verteilen, zurückziehen oder löschen. Zustellung per Direktnachricht — kommt sie nicht an, bleibt der Schlüssel frei |
|
|
| 🎭 **Rollen-Menüs** | Menüs im Webinterface bauen (Emoji, Label, Rolle, optional exklusiv), Bot postet Button-Embeds; Posts jederzeit editierbar |
|
|
| 📋 **Bewerbungen** | Formulare (bis 5 Fragen) als Discord-Modal, Review mit ✅/❌ im Staff-Kanal, Rolle + DM bei Annahme — z. B. FiveM-Whitelist. Ein Formular lässt sich als **Playtester-Formular** markieren; Angenommene landen dann auch im Playtester-Programm |
|
|
| 🪪 **Verknüpfte Rollen** | Discords *Linked Roles*: Level, Playtester-Status und Dabei-seit werden als geprüfte Kennzahlen an Discord gemeldet — Rollen vergibt dann Discord selbst |
|
|
|
|
### Moderation & Support
|
|
|
|
| Funktion | Beschreibung |
|
|
|---|---|
|
|
| 🛡️ **Moderation** | `/warn` (DM + Historie), `/warns`, `/timeout`, `/purge` — alles im Mod-Log |
|
|
| 🤖 **AutoMod** | Treffer von Discords eigenem Filter landen als Embed im Protokoll (Nutzer, Regel, Auslöser, Maßnahme, getroffenes Wort); Regeln sind im Panel sichtbar und schaltbar. Wortlisten bleiben in Discord |
|
|
| 🚨 **Raid-Schutz** | Erkennt Beitritts-Wellen und sperrt den Server vorübergehend (Prüfstufe hoch, Einladungen aus). `/raid an\|aus\|status` auch von Hand |
|
|
| 📋 **Protokoll** | Gelöschte und bearbeitete Nachrichten, Sammel-Löschungen, Joins/Leaves, Namens- und Rollen-Änderungen in einem privaten Kanal. Damit bei einer Löschung **Verfasser und Wortlaut** dastehen — auch bei alten Posts —, merkt sich der Bot Nachrichten kurz selbst; wie lange, steht unter *Werte* (0 = gar nicht). Wer eine fremde Nachricht gelöscht hat, kommt aus Discords Audit-Log |
|
|
| 📬 **Modmail** | DM an den Bot → Thread im privaten Staff-Kanal; Antworten im Thread gehen als DM zurück |
|
|
| 🎫 **Tickets** | Button öffnet einen privaten Thread (ein offenes Ticket pro User). **Anliegen** zur Auswahl — je eigener Name, Einstiegstext und Rolle, die benachrichtigt wird; bis fünf als Knöpfe, darüber als Menü. Das Team kann ein Ticket **übernehmen**, damit klar ist, wer sich kümmert. Schließen = **Transcript per DM** an den Ersteller + Kopie ins Mod-Log, inklusive Anliegen und Bearbeiter |
|
|
| 👋 **Willkommens-Karten** | Begrüßung als gerendertes Bild (Avatar mit Neon-Ring, Member-Nummer, Brand-Look), konfigurierbar; Fallback aufs Text-Embed |
|
|
| 🪪 **Auto- & Sticky-Roles** | Start-Rolle für neue Member; Rollen werden bei Leave gesichert und bei Rejoin wiederhergestellt |
|
|
| 🐛 **`/bug`** | Eingabefenster (was ist passiert, was war erwartet, wie nachstellen) → Gitea-Issue inkl. Screenshot-Upload; Issue geschlossen → DM an den Reporter |
|
|
|
|
### Gaming
|
|
|
|
| Funktion | Was sie macht |
|
|
|---|---|
|
|
| 🎮 **Game-Server-Monitor** | DiscordGSM-Stil: pro Server ein Live-Embed (🟢/🔴, Name im Spiel, 🔒 bei Passwort oder Whitelist, Spieler-Balken, Map, Version, Mod-Anzahl, Spieler-Liste, Knöpfe für Verbinden, Mod-Download und frei eintragbare Links wie Regeln oder TeamSpeak, Ping); **alle Spiele, die gamedig kennt** — die Auswahl im Panel kommt aus der Bibliothek selbst, inklusive Standard-Port und Hinweis auf nötige Zugangs-Codes (Farming Simulator, Terraria) — plus FiveM + HTTP-Check; Down/Up-Alerts mit Ausfalldauer |
|
|
| 🚜 **LS — Höfe & Preise** | Für Farming-Simulator-Server: Besitzkarte auf dem Luftbild des Servers (Parzellen nach Hof eingefärbt, Fläche = Hektar, Fahrzeuge und Spieler live), die Preiskurven übers Jahr mit „jetzt verkaufen oder warten", dazu **je Hof ein Embed**, das sich selbst aktualisiert: Land, Fuhrpark mit Wert und Betriebsstunden, was in die Werkstatt muss, was gewaschen gehört und was geladen ist. Dazu die **Modliste**: der Bot meldet, was neu, aktualisiert oder entfernt wurde, und auf `/mods/<server>` steht jeder Mod einzeln zum Laden — durch den Bot hindurch, damit der Zugangs-Code des Spielservers nicht in einem Link landet. **Nicht möglich:** welche Frucht auf welchem Feld steht, und Tierställe — beides gibt der Feed nicht her (siehe [docs/ls-feed.md](docs/ls-feed.md)) |
|
|
|
|
### Server & Technik
|
|
|
|
| Funktion | Beschreibung |
|
|
|---|---|
|
|
| 🚨 **Wächter** | Prüft eigene Dienste in einstellbarem Takt, DM-Alarm bei Ausfall + Entwarnung; speist die öffentliche Statusseite |
|
|
| 💓 **Herzschlag** | Der Bot zeichnet sich selbst auf — im Dashboard steht neben der Laufzeit ein Erreichbarkeits-Balken über 7 Tage. Fehlende Stunden sind rot: dass nichts dasteht, *ist* die Aussage |
|
|
| 🔊 **Temp-Voice** | „Join to Create": Hub-Kanal betreten → eigener Voice-Kanal mit Control-Panel (Umbenennen, Sperren, Limit, Löschen — nur für den Besitzer), löscht sich wenn leer |
|
|
| 💬 **Auto-Antworten** | Antworten auf Schlüsselwörter (mit Cooldown), verwaltet im Composer |
|
|
| ⏰ **`/remind`** | Erinnerungen per DM (`/remind dauer:2h text:…`) |
|
|
| 🗓️ **Geplante Posts** | Einmalig, täglich oder wöchentlich — im Composer geplant, vom Bot gepostet |
|
|
| 🏷️ **Textbausteine** | `/tag <name>` (mit Autocomplete) postet gespeicherte Bausteine |
|
|
| 💾 **DB-Backups** | Nächtlich, gzip, rotierend, optional als Upload in einen Discord-Kanal |
|
|
| 📦 **Repo-Backups** | Nachts alle Gitea-Repos als git-Bundle (komplette Historie, direkt wieder klonbar), 14 Tage Rotation |
|
|
| 🚪 **Member-Gate** | Login nur für Server-Mitglieder; wer draußen ist, bekommt den Invite-Link |
|
|
|
|
### Plattform
|
|
|
|
| Funktion | Beschreibung |
|
|
|---|---|
|
|
| 🎨 **Branding** | Bot-Identity-Karte (Avatar-Vorschau, Name, Status, Aktivität), Embed-Farben, Banner-Upload, Guild-ID und Gitea-Token ohne Env-Redeploy |
|
|
| 👥 **Team-Rechte** | Team-Mitglieder bekommen gezielten Web-Zugriff (Composer, Bewerbungen, Rollen, Server …) — Brand, System und API-Keys bleiben Owner-only; **Audit-Log** zeigt dem Owner die letzten Aktionen |
|
|
| 🔑 **Single Sign-On** | Andere Dienste (Kanban, Platform …) nutzen den Discord-Login des Bots mit und bekommen die Discord-Rollen gleich mitgeliefert — [Anleitung](docs/sso.md) |
|
|
| 🎨 **Geteiltes Design** | `/brand.css` + `/brand-nav.js` geben jeder anderen App den D4RKST3R-Look samt Navigation — Farben live aus dem Brand-Tab; dazu ein [Gitea-Theme](docs/gitea-theme/) im selben Look |
|
|
| 🏠 **Portal** | Dienste (Gitea, Kanban, Cloud …) in der Config pflegen → Kacheln auf der Startseite und Links in der geteilten Navigation |
|
|
| 📄 **Seiten-Editor** | Frei anlegbare Markdown-Seiten (Regeln, Über uns, Nutzungsbedingungen …) — im Menü oder nur in der Fußzeile |
|
|
| ⚖️ **Rechtstexte** | Impressum + Datenschutz in der Config gepflegt; Member können ihre Daten selbst löschen (DSGVO Art. 17) |
|
|
| ⚡ **Auto-Deploy** | Push auf `main` → Portainer rollt neu aus; optional mit Code-Prüfung über Gitea Actions — [Anleitung](docs/auto-deploy.md) |
|
|
| 🏓 **Kleinkram** | `/ping` · `/devlog-backfill` und `/galerie-backfill` (Historie nacharchivieren, Admin) |
|
|
|
|
---
|
|
|
|
## Webinterface
|
|
|
|
### Community-Hub (`hub.d4rkst3r.de`)
|
|
|
|
| Seite | Zugriff | Inhalt |
|
|
|---|---|---|
|
|
| `/` | öffentlich | Startseite: Hero, Live-Zahlen (Member/Server/Spieler), Bereichs-Kacheln, neuestes Devlog |
|
|
| `/devlogs` | öffentlich | Devlog-Archiv: Timeline, Bildergalerien, Projekt-Chips, **Volltextsuche**; `/devlogs/:id` als teilbarer Permalink |
|
|
| `/roadmap` | öffentlich | Meilensteine aus Gitea mit Fortschrittsbalken, Community-Wünsche, Contribution-Heatmap |
|
|
| `/server` | öffentlich | Live-Status aller Game-Server: Logo, Auslastungs-Balken, Map/Version/Ping, Wer gerade drauf ist, 24h-Verlauf, Uptime & Peak, Copy-Adresse |
|
|
| `/status` | öffentlich | Betriebsstatus: Lage-Banner, Dienste mit 90-Tage-Balken, Game-Server, Störungs-Historie |
|
|
| `/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 |
|
|
| `/wunsch/:id` | öffentlich | Eine Idee mit Stand, Begründung und der Unterhaltung aus dem Thread |
|
|
| `/<kürzel>` | öffentlich | Frei angelegte Seiten aus dem Seiten-Editor |
|
|
| `/impressum` · `/datenschutz` | öffentlich | Rechtstexte — Angaben aus der Config (Owner-only) |
|
|
| `/profil` | Member | Eigenes Profil: Rang, XP, Rollen (togglebar), Alpha-Key, DSGVO-Löschung |
|
|
| `/commits` | Admin | Archivierte Commits aller Repos (SHA → Gitea-Link) |
|
|
| `/settings` | Team | **Config-Seite** — siehe unten |
|
|
|
|
### Produktseite (`bot.d4rkst3r.de`)
|
|
|
|
| Seite | Zugriff | Inhalt |
|
|
|---|---|---|
|
|
| `/` | öffentlich | Was der Bot ist und kann |
|
|
| `/features` | öffentlich | Alle Funktionen nach Bereichen, mit Symbolen |
|
|
| `/commands` | öffentlich | Befehlsübersicht |
|
|
| `/dashboard` | Team | Dieselbe Config-Seite wie auf dem Hub |
|
|
| `/linked-roles` | Member | Discords Verknüpfungs-Ablauf für *Linked Roles* |
|
|
|
|
Login via Discord-OAuth2 (identify-Scope, signierte Session-Cookies, keine
|
|
Token-Speicherung außer für Linked Roles). Design: D4RKST3R-Brand
|
|
(Neon-Gelb/Orange auf Schwarz, Bebas Neue + Barlow Condensed + Share Tech Mono,
|
|
selbst gehostet).
|
|
|
|
---
|
|
|
|
## Config-Seite (`/settings`)
|
|
|
|
**17 Bereiche**, in der Seitenleiste nach Themen gruppiert:
|
|
|
|
| Gruppe | Bereiche |
|
|
|---|---|
|
|
| Überblick | Status · Module · Texte · Werte |
|
|
| Auftritt | Brand (samt Willkommens-Karte) · Seiten |
|
|
| Inhalte | Feeds · Composer |
|
|
| Community | Community · Rollen · Support · Playtester · Bewerbungen |
|
|
| Technik | Server · System |
|
|
| Zugang | API · Team |
|
|
|
|
### Modul-Seiten
|
|
|
|
Jede Funktion hat **ihre eigene Seite**: ein Klick auf ihre Karte zeigt
|
|
Schalter, Kanäle und Rollen, ihre Texte, ihre Werte und den Weg zum passenden
|
|
Werkzeug — statt alles über vier Bereiche verteilt. Für „Willkommen" also
|
|
Kanal, Karte, Farben, Vorschau und Begrüßungstext an einem Ort. Die Adresse
|
|
merkt sich die Seite (`/settings#module/welcome`).
|
|
|
|
Die Funktionen, die man dauernd anfasst, stehen zusätzlich **oben in der
|
|
Seitenleiste** unter *Meine Funktionen* — ein Klick statt Umweg übers Raster.
|
|
Welche das sind, entscheidet der Stern auf der Modul-Karte (höchstens acht,
|
|
damit die Leiste kurz bleibt).
|
|
|
|
Gebaut wird sie aus den Registern: [`src/modules.js`](src/modules.js) kennt die
|
|
Felder, [`src/templates.js`](src/templates.js) die Texte,
|
|
[`src/tuning.js`](src/tuning.js) die Werte — jeweils über `module` verknüpft.
|
|
Eine neue Funktion bekommt ihre Seite dadurch geschenkt.
|
|
|
|
### Module, Werte, Texte
|
|
|
|
* **Module** — alle 39 Funktionen einzeln schaltbar, gruppiert nach Inhalte,
|
|
Community, Moderation und Server. Jede Karte zeigt, ob das Modul
|
|
einsatzbereit ist oder noch etwas fehlt (z. B. ein Kanal). Funktionen mit
|
|
einem bereits vorhandenen Schalter nutzen weiterhin dieselbe Einstellung —
|
|
es gibt keine zweite Wahrheit.
|
|
* **Werte** — Zahlen, die das Verhalten steuern (XP, Wartezeiten,
|
|
Prüf-Intervalle, Postzeiten, Obergrenzen) mit erlaubtem Bereich und Standard.
|
|
Geänderte Intervalle greifen ab dem nächsten Durchlauf, ohne Neustart.
|
|
Gespeichert wird ganz oder gar nicht: ein ungültiger Wert lässt die anderen
|
|
im selben Formular unverändert.
|
|
* **Texte** — was der Bot nach außen schreibt, als Vorlage. Platzhalter wie
|
|
`{user}` oder `{count}` setzt der Bot beim Senden ein; ein Klick auf den
|
|
Baustein fügt ihn an der Cursor-Position ein. Ein leeres Feld stellt den
|
|
Standard wieder her — der lebt im Code, die Datenbank enthält nur echte
|
|
Abweichungen.
|
|
|
|
### Suchen, Speichern, Einrichten
|
|
|
|
Das Suchfeld über der Leiste findet **Bereiche und einzelne Einstellungen**:
|
|
„geburtstag" führt zu Community, „schwellwert" direkt aufs Starboard-Feld, das
|
|
kurz hervorgehoben wird. Enter nimmt den ersten Treffer. Welche Einstellung wo
|
|
liegt, steht in [`frontend/src/setting-index.js`](frontend/src/setting-index.js).
|
|
|
|
Sobald sich etwas vom gespeicherten Stand unterscheidet, erscheint unten eine
|
|
Leiste mit Anzahl, *Verwerfen* und *Speichern*; beim Verlassen mit offenen
|
|
Änderungen fragt der Browser nach. Der aktive Bereich steht in der Adresse
|
|
(`/settings#texte`), Links und Neuladen landen also wieder dort.
|
|
|
|
Der Status-Bereich ist der Einstieg: Kennzahlen, Erreichbarkeits-Balken und
|
|
**„Noch einzurichten"** — alle eingeschalteten Module, denen noch ein Kanal
|
|
oder eine Rolle fehlt. Daneben steht **„Kanal anlegen"** bzw. **„Rolle
|
|
anlegen"**: der Bot legt sie in Discord an, setzt bei privaten Kanälen die
|
|
Rechte und trägt die Einstellung gleich ein. Gibt es Kanal oder Rolle schon,
|
|
werden sie verknüpft statt doppelt angelegt.
|
|
|
|
**„Alles auf einmal anlegen"** legt das ganze Grundgerüst an: erst eine
|
|
Vorschau (was ist neu, was ist schon da, in welche Kategorie kommt es), dann
|
|
ein Durchlauf mit Ergebnis je Zeile. Ein Fehler bei einem Kanal bricht die
|
|
restlichen nicht ab.
|
|
|
|
Dafür braucht der Bot *Kanäle verwalten* bzw. *Rollen verwalten* — fehlt das
|
|
Recht, sagt das Panel genau das. Gelöscht oder umbenannt wird bewusst nichts:
|
|
ein Fehlklick beim Anlegen kostet einen überflüssigen Kanal, einer beim Löschen
|
|
dessen Verlauf.
|
|
|
|
Team-Mitglieder sehen nur die Bereiche ihrer Rechte. Alles ist zur Laufzeit
|
|
änderbar und liegt in SQLite; Env-Variablen sind nur Fallback.
|
|
|
|
---
|
|
|
|
## Ersteinrichtung
|
|
|
|
### 1. Discord-App ([Developer Portal](https://discord.com/developers/applications))
|
|
|
|
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`
|
|
* `https://hub.d4rkst3r.de/auth/callback` (bei zwei Seiten)
|
|
* `https://bot.d4rkst3r.de/linked-roles/callback` (für Linked Roles)
|
|
* `http://localhost:3080/auth/callback` (lokale Entwicklung)
|
|
5. **OAuth2 → URL Generator:** Scopes `bot` + `applications.commands`;
|
|
Rechte: Send Messages, Embed Links, Attach Files, Read Message History,
|
|
**Create Public Threads**, **Manage Roles** (🔔-Abo-Button, Rollen-Menüs),
|
|
**Manage Server** (AutoMod-Regeln lesen und schalten),
|
|
**Manage Channels** (Kanäle anlegen, Raid-Sperre)
|
|
→ URL öffnen, Bot einladen
|
|
6. In Discord: Entwicklermodus an → Server-ID = `DISCORD_GUILD_ID`,
|
|
eigene User-ID = `ADMIN_DISCORD_ID`
|
|
|
|
> **Linked Roles** brauchen zusätzlich unter *General Information* die
|
|
> *Linked Roles Verification URL* → `https://bot.d4rkst3r.de/linked-roles`.
|
|
> Die Kennzahlen meldet der Bot beim Start selbst an.
|
|
|
|
> **AutoMod-Treffer** kommen nur bei Bots mit *Manage Server* an — der nötige
|
|
> Gateway-Intent (`AutoModerationExecution`) ist nicht privilegiert und muss im
|
|
> Portal nicht freigeschaltet werden.
|
|
|
|
⚠️ **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](.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 + Wächter-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 1 h) |
|
|
| `GITEA_API_TOKEN` | optional | Für `/bug` → Issues (Scope `write:issue`); alternativ im Brand-Tab |
|
|
| `GITEA_URL` | optional | Default `https://git.d4rkst3r.de` |
|
|
| `PUBLIC_URL` | optional | Default `https://bot.d4rkst3r.de` |
|
|
| `DB_PATH` | optional | Default `./data/ecobot.db` |
|
|
| `COMMIT_CHANNEL_ID` / `DEVLOG_CHANNEL_ID` | optional | Fallbacks — Kanäle kommen normal aus der Config |
|
|
| `TZ` | optional | Default `Europe/Berlin` (Postzeiten, Datumsformate) |
|
|
|
|
¹ Generieren:
|
|
```bash
|
|
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
```
|
|
|
|
### 3. Routing
|
|
|
|
Cloudflare: CNAME `bot` und `hub` → Zone, Proxied. Nginx Proxy Manager:
|
|
beide Hosts → `host.docker.internal:3080`, Block Common Exploits, Force SSL.
|
|
Test:
|
|
```bash
|
|
curl https://bot.d4rkst3r.de/health
|
|
```
|
|
|
|
### 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 und
|
|
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).
|
|
Automatisch geht es über [docs/auto-deploy.md](docs/auto-deploy.md).
|
|
|
|
Daten liegen im Volume `ecobot_data` (`/app/data`): SQLite (`ecobot.db`, WAL)
|
|
+ Devlog- und Galerie-Bilder.
|
|
|
|
Manuell statt Portainer:
|
|
|
|
```bash
|
|
git clone git@gitea:D4rkst3r/d4rkbot.git && cd d4rkbot
|
|
cp .env.example .env # Werte eintragen
|
|
docker compose up -d --build
|
|
```
|
|
|
|
---
|
|
|
|
## Lokale Entwicklung
|
|
|
|
```bash
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
Bot + API laufen auf `:3080` mit den Werten aus `.env`. Frontend mit
|
|
Hot-Reload:
|
|
|
|
```bash
|
|
cd frontend && npm install && npm run dev
|
|
```
|
|
|
|
Vite läuft auf `:5173` und leitet `/api` + `/auth` an `:3080` weiter.
|
|
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-Zustellung):
|
|
|
|
```bash
|
|
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 Config-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- und Berechtigungs-Checks |
|
|
| `GET /api/v1/stats` | `read` | Devlog-/Commit-Zahlen, Guilds, Uptime |
|
|
|
|
Beispiel (Python):
|
|
|
|
```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 /api/servers` · `/api/status` | — | Game-Server-Status · öffentlicher Betriebsstatus (Namen, nie Adressen) |
|
|
| `GET /api/pages` · `/api/features` | — | Veröffentlichte Seiten · Funktionsliste für die Produktseite |
|
|
| `GET /feed.xml` | — | RSS |
|
|
| `GET /devlog-assets/*` · `/gallery-assets/*` · `/wish-assets/*` | — | Lokal gespeicherte Bilder (Discord-Links laufen ab) |
|
|
| `GET /brand.css` · `/brand-nav.js` | — | Design-Tokens + Navigation für andere Apps (CORS offen) |
|
|
| `GET /api/legal` · `DELETE /api/profile` | — / Member | Impressums-Angaben · DSGVO-Löschung |
|
|
| `GET /api/profile` · `/api/myroles*` · `POST /api/wishes*` | Member | Profil · Rollen-Selfservice · Wunsch einreichen/voten |
|
|
| `PUT /api/wishes/:id/status` · `POST /api/wishes/:id/merge` | Team (community) | Stand setzen (+ DM an Stimmen-Geber) · Doppler zusammenführen |
|
|
| `GET /api/wishes/:id` · `/api/wishes/suche?q=` | — | Eine Idee mit Beiträgen aus dem Thread · Suche vor dem Einreichen |
|
|
| `GET/POST/PUT/DELETE /api/wish-categories` | Team (community) | Bereiche für Wünsche pflegen |
|
|
| `GET /linked-roles` · `/linked-roles/callback` | Member | Discords Verknüpfungs-Ablauf für Linked Roles |
|
|
| `GET /sso/authorize` · `POST /sso/verify` | App-Secret | **Single Sign-On** für andere Dienste — siehe [docs/sso.md](docs/sso.md) |
|
|
| `POST/GET /api/v1/*` | API-Key (Bearer) | Externe Skripte — siehe „API v1" oben |
|
|
| `GET /api/watchdog` · `/api/automod` | Team | Wächter-Übersicht · AutoMod-Regeln |
|
|
| `PUT /api/automod/:id` · `/api/monitored*` | Team (settings) | Regel schalten · überwachte Dienste pflegen |
|
|
| `GET/PUT /api/settings`, `POST /api/settings/test/:target` | Team | Config-Seite |
|
|
| `GET/PUT /api/modules` · `/api/texts` · `/api/tuning` | Team (settings) | Module · Textvorlagen · Werte |
|
|
| `POST /api/compose` · `GET/PUT/DELETE /api/templates` | Team (content) | Composer senden/bearbeiten · Vorlagen |
|
|
| `GET/POST/PUT/DELETE /api/rolemenus`, `POST /api/rolemenus/:id/publish` | Team (rollen) | Rollen-Menüs |
|
|
| `GET/POST/DELETE /api/apikeys` | Owner | API-Key-Verwaltung |
|
|
| `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.
|
|
|
|
---
|
|
|
|
## Projektstruktur
|
|
|
|
```
|
|
d4rkbot/
|
|
├── src/
|
|
│ ├── index.js # Start: Bot, Webserver, Scheduler
|
|
│ ├── config.js # Env-Konfiguration mit Validierung
|
|
│ ├── db.js # SQLite: Schema, Migrationen, FTS5, alle Queries
|
|
│ ├── runtime-settings.js # Effektive Settings (DB vor Env)
|
|
│ ├── modules.js # Register: welche Funktionen es gibt
|
|
│ ├── templates.js # Register: was der Bot schreibt
|
|
│ ├── tuning.js # Register: welche Zahlen stellbar sind
|
|
│ ├── embeds.js # brandEmbed-Factory (Farbe, Footer, Bot-Icon)
|
|
│ ├── gitea-api.js # Gitea-REST (Issues + Assets für /bug)
|
|
│ ├── backup.js # Nächtliche DB-Backups (gzip, Rotation, Upload)
|
|
│ ├── repo-backup.js # Gitea-Repos als git-Bundle sichern
|
|
│ ├── bot/
|
|
│ │ ├── client.js # Discord-Client, Commands, Listener, Buttons
|
|
│ │ ├── commit-feed.js # Push → Embed
|
|
│ │ ├── release-feed.js # Release → Ankündigungs-Embed
|
|
│ │ ├── devlog-archive.js # Nachricht → SQLite (+ Bild-Download)
|
|
│ │ ├── weekly-recap.js # Sonntags-Zusammenfassung
|
|
│ │ ├── community.js # Starboard + Screenshot-Galerie
|
|
│ │ ├── levels.js # XP, Level-Up, Rollen-Belohnungen
|
|
│ │ ├── mod-tools.js # Modmail, Willkommen, Mod-Log
|
|
│ │ ├── automod.js # Discords Filter spiegeln + Regeln schalten
|
|
│ │ ├── anti-raid.js # Beitritts-Wellen erkennen, Server sperren
|
|
│ │ ├── tickets.js # Private Threads + Transcript
|
|
│ │ ├── app-forms.js # Bewerbungs-Modals + Review
|
|
│ │ ├── role-menus.js # Button-Embeds für Rollen
|
|
│ │ ├── linked-roles.js # Kennzahlen an Discord melden
|
|
│ │ ├── giveaways.js # Ziehung + Reroll
|
|
│ │ ├── birthdays.js # Gratulation + Tages-Rolle
|
|
│ │ ├── server-monitor.js # Game-Server (gamedig — Spielliste, Icons, Abfrage)
|
|
│ │ ├── watchdog.js # URL-Checks, Störungen, DM-Alarm
|
|
│ │ ├── heartbeat.js # Eigene Erreichbarkeit aufzeichnen
|
|
│ │ ├── wishes.js # Ideen: einreichen, Thread, Forum-Tags
|
|
│ │ ├── bilder.js # Bilder aus Discord lokal sichern
|
|
│ │ ├── server-setup.js # Kanäle und Rollen anlegen
|
|
│ │ ├── welcome-card.js # Willkommens-Bild rendern
|
|
│ │ ├── social-notify.js # Twitch + YouTube
|
|
│ │ ├── presence.js # Status des Bots
|
|
│ │ ├── extras.js # Temp-Voice, Trigger, Erinnerungen, Events
|
|
│ │ └── commands/ # 18 Slash-Commands
|
|
│ └── web/
|
|
│ ├── server.js # Fastify: Webhooks, Static, SPA-Fallback, OG-Tags
|
|
│ ├── auth.js # Discord-OAuth2 + Session-Cookies
|
|
│ ├── api.js # REST-API + Settings + RSS
|
|
│ ├── api-v1.js # Öffentliche API mit Bearer-Keys
|
|
│ ├── sso.js # Identity-Provider für andere Dienste
|
|
│ ├── brand.js # /brand.css + /brand-nav.js
|
|
│ ├── linked-roles.js # Verknüpfungs-Ablauf
|
|
│ ├── scheduled-posts.js# Geplante Beiträge
|
|
│ └── devlog-endpoint.js# Devlog: Embed, Bilder, Ping, Thread, Archiv
|
|
├── frontend/ # React + Vite (D4RKST3R-Design)
|
|
│ └── src/
|
|
│ ├── App.jsx # Hub: Layout, Router, Navigation
|
|
│ ├── BotApp.jsx # Produktseite: eigene Navigation
|
|
│ ├── site.js # Welche der beiden Seiten gilt
|
|
│ ├── i18n.jsx # Sprachumschalter + Wörterbücher
|
|
│ ├── locales/ # de.js · en.js (öffentliche Seiten)
|
|
│ ├── markdown.jsx # Mini-Markdown
|
|
│ ├── icons.jsx # Lucide-Symbole
|
|
│ ├── components/ # Composer, Lightbox, UptimeTrack, ModulePage …
|
|
│ └── pages/ # Alle Seiten inkl. Settings
|
|
├── docs/ # Anleitungen und Konzepte
|
|
├── tools/test-webhook.mjs # Lokaler Commit-Feed-Test
|
|
├── .env.example # Vorlage für alle Env-Variablen
|
|
├── Dockerfile # Multi-Stage: Frontend-Build + node:22-slim
|
|
└── docker-compose.yml # Portainer-ready, Volume ecobot_data, TZ
|
|
```
|
|
|
|
**Neuer Slash-Command:** Datei in `src/bot/commands/` (exportiert `data` +
|
|
`execute`) und in `client.js` bei `commandModules` eintragen.
|
|
|
|
**Neue Einstellung:** Key in `db.js` nutzen, Zugriff über
|
|
`runtime-settings.js`, UI in `frontend/src/pages/Settings.jsx`, GET/PUT in
|
|
`src/web/api.js` — und in `setting-index.js` eintragen, damit die Suche sie
|
|
findet.
|
|
|
|
**Neues Modul:** Eintrag in `src/modules.js` (Gruppe, Tab, Schalter,
|
|
Voraussetzungen), Symbol in `frontend/src/module-icons.jsx`, englischer Name
|
|
in `frontend/src/locales/en.js`. Die Modul-Seite entsteht daraus von selbst.
|
|
|
|
---
|
|
|
|
## Weitere Dokumentation
|
|
|
|
| Datei | Inhalt |
|
|
|---|---|
|
|
| [docs/sso.md](docs/sso.md) | Single Sign-On: Ablauf, Endpoints, Anbindung eigener Dienste |
|
|
| [docs/auto-deploy.md](docs/auto-deploy.md) | Push auf `main` → Portainer rollt neu aus |
|
|
| [docs/konzept-zwei-seiten.md](docs/konzept-zwei-seiten.md) | Warum und wie Produktseite und Hub getrennt sind |
|
|
| [docs/brand/README.md](docs/brand/README.md) | Logo-Master, abgeleitete Symbole, Build-Skript |
|
|
| [docs/gitea-theme/README.md](docs/gitea-theme/README.md) | D4RKST3R-Theme für Gitea |
|
|
| [docs/nutzungsbedingungen.md](docs/nutzungsbedingungen.md) | Entwurf für die Nutzungsbedingungen-Seite |
|