# 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](https://discord.com/developers/applications) 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 → **OAuth2** → **URL 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.de` → **DNS** 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 → **Hosts** → **Proxy Hosts** → **Add 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 → **Einstellungen** → **Webhooks** → **Webhook hinzufügen** → **Gitea** 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.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](https://discord.com/developers/applications) → 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 → **Stacks** → **Add 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 variables** → **Advanced 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.