- POST /webhooks/devlog/<secret> — Discord-Webhook-kompatibel (JSON + Multipart), devlog.py braucht nur die neue URL in tools/.devlog_webhook - Bot postet Embed in Brand-Gelb mit 'D4RKST3R // DEVLOG'-Footer, bis zu 4 Bilder als Grid (Embed-Gruppierung über gemeinsame URL) - Direkt-Archivierung inkl. Bilder (kein Umweg über den Live-Listener) - Neue Env-Var DEVLOG_POST_SECRET, README-Abschnitt neu geschrieben Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
247 lines
9.5 KiB
Markdown
247 lines
9.5 KiB
Markdown
# 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_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: 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.
|