D4rkst3randClaude Opus 4.8 be1fc227d0 Release-Ankündigungen + öffentliche Changelog-Seite
- Gitea-Release-Webhook: Releases werden archiviert (releases-Tabelle) und neue
  'published'-Releases als oranges 🚀-Embed mit Buttons angekündigt
- Release-Kanal auf der Setup-Seite wählbar (leer = Feature aus) + Test-Button
- /changelog: öffentliche Seite mit Tag-Chips, Pre-Release-Badge, Release-Notes
- /api/releases öffentlich; Updates/Redeliveries posten nicht doppelt

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 10:37:28 +02:00

EcoBot

Discord-Bot + Webinterface für die EcoGame-Community.

Features (Roadmap):

  1. Bot online + /ping Slash-Command
  2. Commit-Feed: Gitea-Push-Webhooks → Discord-Embeds + SQLite-Archiv
  3. Devlog-Archiv: Devlog-Kanal live archivieren + /devlog-backfill für die Historie
  4. Webinterface: Devlog-Archiv (öffentlich) + Commit-Feed (Discord-Login, nur Admin)

Stack: Node.js 20+, discord.js v14, Fastify, React + Vite, SQLite (better-sqlite3), Docker


Setup: Discord-App anlegen (einmalig)

1. App erstellen

  1. Öffne das Discord Developer Portal
  2. New Application → Name: EcoBot → Create
  3. Unter General Information die Application ID kopieren → das ist DISCORD_CLIENT_ID

2. Bot-Token holen

  1. Linke Seitenleiste → Bot
  2. Reset Token → Token kopieren → das ist DISCORD_TOKEN ⚠️ Der Token wird nur einmal angezeigt — direkt in die .env eintragen!
  3. Auf der Bot-Seite weiter unten: Message Content Intent aktivieren (brauchen wir ab Feature 3 zum Lesen der Devlog-Nachrichten)

3. Bot auf den Server einladen

  1. Linke Seitenleiste → OAuth2URL Generator
  2. Scopes ankreuzen: bot und applications.commands
  3. Bot Permissions ankreuzen:
    • Send Messages
    • Embed Links
    • Read Message History
  4. Generierte URL unten kopieren, im Browser öffnen, deinen Server auswählen → Autorisieren

4. Server-ID holen (für sofortige Slash-Commands)

  1. In Discord: Einstellungen → Erweitert → Entwicklermodus aktivieren
  2. Rechtsklick auf deinen Server → Server-ID kopieren → das ist DISCORD_GUILD_ID

5. .env anlegen

cp .env.example .env

Dann die Werte eintragen. Die .env ist in .gitignore und landet nie im Repo.


Setup: Commit-Feed (Gitea → Discord)

1. Neue .env-Werte

Variable Woher
COMMIT_CHANNEL_ID Rechtsklick auf den Ziel-Kanal in Discord → Kanal-ID kopieren
GITEA_WEBHOOK_SECRET Generieren: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

2. Öffentlicher Host im Nginx Proxy Manager (bot.d4rkst3r.de)

Cloudflare (DNS):

  1. Cloudflare-Dashboard → Zone d4rkst3r.deDNS
  2. Neuen Record anlegen: Typ CNAME, Name bot, Ziel wie bei den bestehenden Hosts (z. B. d4rkst3r.de), Proxy-Status Proxied (orange Wolke)

Nginx Proxy Manager:

  1. NPM öffnen → HostsProxy HostsAdd Proxy Host
  2. Tab Details:
    • Domain Names: bot.d4rkst3r.de
    • Scheme: http
    • Forward Hostname / IP: host.docker.internal (NPM läuft im Container, der Bot published Port 3080 auf dem Windows-Host)
    • Forward Port: 3080
    • Block Common Exploits
  3. Tab SSL:
    • SSL Certificate: Request a new SSL Certificate (Let's Encrypt) — oder das vorhandene Wildcard-Zertifikat auswählen
    • Force SSL
  4. Save

Test: https://bot.d4rkst3r.de/health im Browser → {"status":"ok"}

3. Webhook in Gitea eintragen

  1. Gitea → EcoGame-Repo → EinstellungenWebhooksWebhook hinzufügenGitea
  2. Ziel-URL: https://bot.d4rkst3r.de/webhooks/gitea
  3. HTTP-Methode: POST, POST Content Type: application/json
  4. Geheimnis: exakt der Wert aus GITEA_WEBHOOK_SECRET
  5. Trigger: Push-Events, Branch-Filter leer (= alle)
  6. Speichern → auf den Webhook klicken → Testzustellung senden → im Discord-Kanal erscheint ein Embed 🎉

Den alten direkten Discord-Webhook im Repo danach löschen, sonst gibt's Doppel-Posts.

Bereits gepostete Commits werden per SHA dedupliziert — ein erneuter Push derselben Commits erzeugt keine doppelten DB-Einträge.


Setup: Devlog (Bot postet + archiviert)

Der Bot ist das Tagebuch: tools/devlog.py (EcoGame-Repo) schickt sein Devlog an den Bot-Endpoint (Discord-Webhook-kompatibel), der Bot postet ein gebrandetes Embed (Gelb, „D4RKST3R // DEVLOG"-Footer, bis zu 4 Bilder als Grid) in den Devlog-Kanal und archiviert Text + Bilder in SQLite.

  1. .env / Portainer-Stack:
    • DEVLOG_CHANNEL_ID = Kanal-ID des Devlog-Kanals
    • DEVLOG_POST_SECRET = generieren: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
  2. Im EcoGame-Repo in tools/.devlog_webhook statt der Discord-URL eintragen:
    https://bot.d4rkst3r.de/webhooks/devlog/<DEVLOG_POST_SECRET>
    
    devlog.py selbst bleibt unverändert — der Endpoint versteht das Discord-Webhook-Format (JSON + Multipart mit Bildern).
  3. Den alten Discord-Webhook im Devlog-Kanal löschen (wird nicht mehr gebraucht)

Zusätzlich liest der Bot den Kanal live mit und archiviert auch fremde Webhook-/Bot-Posts (dafür: Message Content Intent im Developer Portal aktiv). /devlog-backfill (Admin) archiviert die Kanal-Historie nach. Dedupe läuft über die Discord-Message-ID — alles beliebig wiederholbar. Bilder werden lokal gespeichert (data/devlog_images/), weil Discord-CDN-Links ablaufen.


Setup-Seite im Webinterface (Admin)

Unter /settings (Nav: „Setup", nur als Admin sichtbar) lassen sich zur Laufzeit ändern — gespeichert in SQLite, Env-Variablen sind nur noch der Fallback, Änderungen greifen sofort ohne Redeploy:

  • Devlog-Kanal und Commit-Kanal als Dropdown (alle Textkanäle, die der Bot sieht) — mit Test senden-Button pro Kanal
  • Commit-Feed an/aus (aus = Commits werden weiter archiviert, nur nicht gepostet)
  • Branch-Filter (kommagetrennt, leer = alle) — gefilterte Branches werden archiviert, aber nicht gepostet
  • Ignorierte Repos (kommagetrennt, z. B. D4rkst3r/ecobot) — komplett übersprungen
  • Status-Panel: Bot-Account, Uptime, Anzahl Devlogs/Commits, DB-Größe

COMMIT_CHANNEL_ID und DEVLOG_CHANNEL_ID sind damit optional geworden.


Setup: Webinterface

Zugriffsmodell: Devlog-Archiv ist öffentlich (wie der Discord-Kanal), die Commit-Seite erfordert Discord-Login und ist auf deine Discord-ID beschränkt.

1. OAuth2 im Developer Portal konfigurieren

  1. Developer Portal → deine App → OAuth2
  2. Client Secret kopieren (ggf. „Reset Secret") → DISCORD_CLIENT_SECRET
  3. Unter Redirects BEIDE URLs eintragen:
    • https://bot.d4rkst3r.de/auth/callback (Produktion)
    • http://localhost:3080/auth/callback (lokale Entwicklung)

2. Neue .env-Werte

Variable Woher
DISCORD_CLIENT_SECRET Developer Portal → OAuth2 (Schritt 1)
SESSION_SECRET Generieren: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
ADMIN_DISCORD_ID Discord: Rechtsklick auf deinen Namen → Benutzer-ID kopieren
PUBLIC_URL Produktion: https://bot.d4rkst3r.de · lokal: http://localhost:3080

3. Frontend lokal entwickeln

cd frontend
npm install
npm run dev        # Vite-Dev-Server auf :5173, proxied /api + /auth zum Bot auf :3080

Für den „Produktions-Look" lokal: npm run build im frontend/-Ordner — der Bot liefert frontend/dist dann selbst unter http://localhost:3080 aus. Im Docker-Image wird das Frontend automatisch mitgebaut (Multi-Stage).


Lokal starten (Entwicklung)

npm install
npm run dev

Erwartete Ausgabe:

[bot] Eingeloggt als EcoBot#1234
[bot] 1 Slash-Command(s) registriert (Guild)

Dann in Discord: /ping → Bot antwortet mit Latenz. 🎉

Commit-Feed lokal testen (ohne Gitea — simuliert eine signierte Testzustellung):

node tools/test-webhook.mjs

→ Embed erscheint im Commit-Kanal, Commit landet in der lokalen SQLite (data/ecobot.db).


Deployment (Docker / Portainer)

Variante A: Portainer-Stack aus Git (empfohlen)

  1. Portainer → StacksAdd stack → Name: ecobot
  2. Build method: Repository
    • Repository URL: https://git.d4rkst3r.de/D4rkst3r/ecobot
    • Repository reference: refs/heads/main
    • Compose path: docker-compose.yml
    • Falls das Repo privat ist: Authentication aktivieren — Username: D4rkst3r, Password: ein Gitea-Token (Gitea → Einstellungen → Anwendungen → Token erzeugen, Scope read:repository)
  3. Unter Environment variablesAdvanced mode die Werte aus der lokalen .env eintragen (DISCORD_TOKEN, DISCORD_CLIENT_ID, DISCORD_GUILD_ID, COMMIT_CHANNEL_ID, GITEA_WEBHOOK_SECRET)
  4. Deploy the stack

Updates später: Stack öffnen → Pull and redeploy (holt den neuesten Stand von main).

Variante B: Manuell auf dem Server

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

Logs prüfen:

docker logs -f ecobot

Projektstruktur

ecobot/
├── src/
│   ├── index.js            # Einstiegspunkt (Bot + Webserver)
│   ├── config.js           # Env-Konfiguration mit Validierung
│   ├── db.js               # SQLite (better-sqlite3), Schema + Queries
│   ├── bot/
│   │   ├── client.js       # Discord-Client, Command-Registry, Interactions, Devlog-Listener
│   │   ├── commit-feed.js  # Push → Discord-Embed
│   │   ├── devlog-archive.js # Webhook-Nachricht → SQLite
│   │   └── commands/
│   │       ├── ping.js     # /ping — Lebenszeichen
│   │       └── devlog-backfill.js # /devlog-backfill — Historie archivieren (Admin)
│   └── web/
│       ├── server.js       # Fastify: Webhook, Static-Serving, SPA-Fallback
│       ├── auth.js         # Discord-OAuth2-Flow + Session-Cookies
│       └── api.js          # REST-API: /api/me, /api/devlogs, /api/commits
├── frontend/               # React + Vite (Devlogs öffentlich, Commits admin-only)
│   └── src/
│       ├── App.jsx         # Layout, Router, Login-Status
│       ├── markdown.jsx    # Mini-Markdown-Renderer für Devlog-Prosa
│       └── pages/          # Devlogs.jsx, Commits.jsx
├── .env.example            # Vorlage für Secrets (nach .env kopieren)
├── Dockerfile              # Multi-Stage: Frontend-Build + Runtime
├── docker-compose.yml
└── README.md

Neue Slash-Commands: Datei in src/bot/commands/ anlegen (exportiert data + execute) und in src/bot/client.js bei commandModules eintragen.

S
Description
No description provided
Readme
7.4 MiB
Languages
JavaScript 90.4%
CSS 8.7%
PowerShell 0.7%
Dockerfile 0.2%