Ueberall, wo ein Emoji nach Discord geht — Rollen-Menues, Ticket-Anliegen,
Wunsch-Bereiche, Portal-Kacheln — stand ein leeres Textfeld, in das man mit
Win+. hineintippen musste. Jetzt sitzt daneben ein Knopf mit einer Tafel:
sieben Gruppen, deutsche Suchbegriffe ("auto", "geld", "warnung"), ein Klick
schreibt ins Feld. Das Feld bleibt daneben stehen, denn Server-Emojis
(<:name:123>) kennt nur Discord.
Bewusst eine eigene Liste statt einer Bibliothek: die vollstaendige
Unicode-Tabelle waere ein halbes Megabyte fuer eine Handvoll Symbole, und die
Suchbegriffe duerfen deutsch sein.
## Forum-Tags
Ist der Voting-Kanal ein Forum, wird jeder Wunsch jetzt ein Forums-Beitrag
statt Nachricht-plus-Thread — und bekommt Tags fuer Bereich und Stand. Damit
laesst sich auch in Discord filtern, wofuer Tags ja da sind. Beim Wechsel des
Stands zieht das Tag mit: der alte fliegt raus, der neue kommt rein, der
Bereich bleibt stehen.
Zugeordnet wird ueber den Namen. Wer im Forum ein Tag "Fahrzeuge" anlegt,
bekommt es automatisch gesetzt; wer keines anlegt, verliert nichts. Bewusst
keine ID-Zuordnung im Panel — das waere eine zweite Liste, die man pflegen
muss und die beim ersten Umbenennen auseinanderlaeuft.
Dabei aufgefallen und mitgefixt: im Forum liegt die Startnachricht im Beitrag
selbst und nicht im Kanal. Der Status-Aktualisierer hat sie vorher im Kanal
gesucht und nicht gefunden — die Begruendung waere im Forum also nie im Post
gelandet. Und der Titel wird jetzt nur um den Stand ergaenzt statt
ueberschrieben, damit "🚗 Fahrzeuge" stehen bleibt.
Geprueft: tagsFuer gegen 20 Faelle — kein Forum, Medien-Kanal, fehlende Tags,
Gross/Kleinschreibung, Deckel bei fuenf (mehr nimmt Discord nicht), und alle
fuenf Staende einzeln. Im Browser die Emoji-Tafel an allen vier Stellen:
Suche, Escape, Klick daneben, Leeren, Uebernehmen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
570 lines
32 KiB
Markdown
570 lines
32 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) · [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. 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, Joins/Leaves, Namens- und Rollen-Änderungen in einem privaten Kanal |
|
|
| 📬 **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** als Auswahlmenü — je eigener Name, Einstiegstext und Rolle, die benachrichtigt wird. 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 |
|
|
|
|
### Server & Technik
|
|
|
|
| Funktion | Beschreibung |
|
|
|---|---|
|
|
| 🎮 **Game-Server-Monitor** | DiscordGSM-Stil: pro Server ein Live-Embed (🟢/🔴, Spieler-Balken, Map, Spieler-Liste, Connect-Link, Ping); **300+ Spiele via gamedig** (Minecraft, Rust, CS2, Valheim, ARK …) + FiveM + HTTP-Check; Down/Up-Alerts mit Ausfalldauer |
|
|
| 🚨 **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, Spieler-Balken, 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 |
|
|
| `/<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/*` | — | Lokal gespeicherte Bilder |
|
|
| `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/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, 300+ Spiele)
|
|
│ │ ├── watchdog.js # URL-Checks, Störungen, DM-Alarm
|
|
│ │ ├── heartbeat.js # Eigene Erreichbarkeit aufzeichnen
|
|
│ │ ├── 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 |
|