From eb51be4ebcdf4ec92dafef1f172a39179fcf288a Mon Sep 17 00:00:00 2001 From: D4rkst3r Date: Thu, 23 Jul 2026 11:43:21 +0200 Subject: [PATCH] =?UTF-8?q?README=20komplett=20=C3=BCberarbeitet:=20aktuel?= =?UTF-8?q?ler=20Funktionsumfang,=20Setup,=20Endpoints,=20Struktur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Feature-Tabellen (Discord + Webinterface + Setup-Seite) - Ersteinrichtung gestrafft: Discord-App inkl. aller nötigen Permissions, Env-Tabelle mit Pflicht/Optional, Gitea-Webhook mit allen drei Trigger-Events - Deployment (Portainer inkl. Re-pull-Hinweis), lokale Entwicklung - HTTP-Endpoint-Referenz und aktualisierte Projektstruktur Co-Authored-By: Claude Opus 4.8 --- README.md | 429 +++++++++++++++++++++++------------------------------- 1 file changed, 184 insertions(+), 245 deletions(-) diff --git a/README.md b/README.md index 0c63afb..f163dd9 100644 --- a/README.md +++ b/README.md @@ -1,257 +1,190 @@ -# EcoBot +# EcoBot — D4RKST3R // DEVLOG -Discord-Bot + Webinterface für die EcoGame-Community. +Discord-Bot + Webinterface: Devlog-Tagebuch, Commit-Feed, Changelog und +Community-Tools für die EcoGame-Entwicklung — alles gebrandet, alles über +die Setup-Seite steuerbar. -**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 +**Stack:** Node.js 20+ (ESM), discord.js v14, Fastify 5, React 19 + Vite, +SQLite (better-sqlite3, FTS5), Docker Multi-Stage — deploybar als Portainer-Stack. --- -## Setup: Discord-App anlegen (einmalig) +## Features -### 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 | +### Discord +| Feature | Beschreibung | |---|---| -| `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'))"` | +| 📔 **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 → oranges Ankündigungs-Embed | +| 📊 **Wochen-Rückblick** | Sonntags 20:00 automatisch: Commits pro Tag als Balken, Devlogs, Top-Projekte | +| 🐛 **`/bug`** | Member melden Bugs → Gitea-Issue (inkl. Screenshot-Upload); Issue geschlossen → DM an den Reporter | +| 🚨 **Watchdog** | Prüft eigene Dienste alle 2 min, DM-Alarm bei Ausfall + Entwarnung | +| 🏓 `/ping`, 🗄 `/devlog-backfill` | Lebenszeichen · Kanal-Historie nacharchivieren (Admin) | -### 2. Öffentlicher Host im Nginx Proxy Manager (`bot.d4rkst3r.de`) +### Webinterface (`bot.d4rkst3r.de`) +| Seite | Zugriff | Inhalt | +|---|---|---| +| `/devlogs` | öffentlich | Devlog-Archiv: Timeline, Bildergalerien, Projekt-Chips, **Volltextsuche** | +| `/changelog` | öffentlich | Alle Releases mit Notes, Tag- und Pre-Release-Chips | +| `/feed.xml` | öffentlich | RSS-Feed der Devlogs | +| `/commits` | nur Admin | Archivierte Commits aller Repos (SHA → Gitea-Link) | +| `/settings` | nur Admin | **Setup-Seite** — siehe unten | -**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) +Login via Discord-OAuth2 (identify-Scope, signierte Session-Cookies, keine Token-Speicherung). +Design: D4RKST3R-Brand (Neon-Gelb/Orange auf Schwarz, Bebas Neue + Barlow Condensed + +Share Tech Mono, selbst gehostet). -**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** +### Setup-Seite (`/settings`) +Alles zur Laufzeit änderbar — gespeichert in SQLite, Env-Variablen sind nur Fallback, +kein Redeploy nötig: -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. +- **Kanäle** (Devlog / Commit / Release) als Dropdown + „Test senden"-Button je Kanal +- **Devlog:** Ping-Rolle, Auto-Threads an/aus, Wochen-Rückblick an/aus (+ Sofort-Test) +- **Commit-Feed:** an/aus, Branch-Filter, ignorierte Repos + (gefiltert wird nur das Posten — archiviert wird immer; ignorierte Repos komplett übersprungen) +- **Bug-Reports:** Ziel-Repo für `/bug` +- **Watchdog:** überwachte URLs +- **Status-Panel:** Bot-Account, Uptime, Devlog-/Commit-Zahlen, DB-Größe --- -## Setup: Devlog (Bot postet + archiviert) +## Ersteinrichtung -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. - ---- - -## Bug-Reports, Threads & Watchdog - -**`/bug` (alle Member):** Titel + Beschreibung + optional Screenshot → der Bot -erstellt ein Gitea-Issue im konfigurierten Repo (Setup-Seite), lädt den -Screenshot als Issue-Attachment hoch und merkt sich den Reporter. -Wird das Issue in Gitea **geschlossen**, bekommt der Reporter automatisch -eine DM („Dein Bug ist behoben ✅"). - -Setup: -1. Gitea → Einstellungen → Anwendungen → **Token erzeugen** (Scope `write:issue`) - → als `GITEA_API_TOKEN` in die Env -2. Im Gitea-Webhook zusätzlich das Trigger-Event **„Issues"** aktivieren - (für die Rückkanal-DMs) - -**Auto-Threads:** Unter jedem Devlog-Post öffnet der Bot einen Diskussions-Thread -(„💬 Devlog 23.07.", Auto-Archiv nach 3 Tagen). Abschaltbar auf der Setup-Seite. -Der Bot braucht im Devlog-Kanal die Berechtigung **„Öffentliche Threads erstellen"**. - -**Watchdog:** Auf der Setup-Seite URLs eintragen (kommagetrennt, z. B. -`https://git.d4rkst3r.de, https://bot.d4rkst3r.de/health`) — der Bot prüft sie -alle 2 Minuten und schickt dir bei Ausfall (2 Fehlschläge in Folge) eine -**Discord-DM**, inkl. Entwarnung mit Downtime-Dauer. - ---- - -## 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) +### 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** aktivieren (Devlog-Listener) +4. **OAuth2** → Client Secret = `DISCORD_CLIENT_SECRET`; + unter **Redirects** eintragen: + - `https://bot.d4rkst3r.de/auth/callback` - `http://localhost:3080/auth/callback` (lokale Entwicklung) +5. **OAuth2 → URL Generator:** Scopes `bot` + `applications.commands`; + Permissions: Send Messages, Embed Links, Attach Files, Read Message History, + **Create Public Threads**, **Manage Roles** (für den 🔔-Abo-Button) + → URL öffnen, Bot einladen +6. In Discord: Entwicklermodus an → Server-ID = `DISCORD_GUILD_ID`, + eigene User-ID = `ADMIN_DISCORD_ID` -### 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` | +⚠️ **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. -### 3. Frontend lokal entwickeln +### 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 + Watchdog-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 1h) | +| `GITEA_API_TOKEN` | optional | Für `/bug` → Issues (Scope `write:issue`); ohne Token ist `/bug` aus | +| `GITEA_URL` | optional | Default `https://git.d4rkst3r.de` | +| `PUBLIC_URL` | optional | Default `https://bot.d4rkst3r.de` | +| `COMMIT_CHANNEL_ID` / `DEVLOG_CHANNEL_ID` | optional | Fallbacks — Kanäle kommen normal von der Setup-Seite | +| `TZ` | optional | Default `Europe/Berlin` (Wochen-Rückblick, Datumsformate) | + +¹ Generieren: `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"` + +### 3. Routing (einmalig eingerichtet) +Cloudflare: CNAME `bot` → Zone, Proxied. Nginx Proxy Manager: `bot.d4rkst3r.de` +→ `host.docker.internal:3080`, Block Common Exploits, Force SSL. +Test: `https://bot.d4rkst3r.de/health` → `{"status":"ok"}` + +### 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/ +``` +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 + 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` → Build method **Repository** + - URL `https://git.d4rkst3r.de/D4rkst3r/ecobot`, 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). + +Daten liegen im Volume `ecobot_data` (`/app/data`): SQLite (`ecobot.db`, WAL) ++ Devlog-Bilder (`devlog_images/` — lokal gespeichert, weil Discord-CDN-Links ablaufen). + +Manuell statt Portainer: +``` +git clone git@gitea:D4rkst3r/ecobot.git && cd ecobot +cp .env.example .env # Werte eintragen +docker compose up -d --build +docker logs -f ecobot +``` + +--- + +## Lokale Entwicklung + +``` +npm install +npm run dev # Bot + API auf :3080 (Werte aus .env) +``` + +Frontend mit Hot-Reload: ``` cd frontend npm install -npm run dev # Vite-Dev-Server auf :5173, proxied /api + /auth zum Bot auf :3080 +npm run dev # Vite auf :5173, proxied /api + /auth → :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). +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). ---- - -## 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): +Commit-Feed ohne Gitea testen (signierte Fake-Testzustellung): ``` node tools/test-webhook.mjs ``` -→ Embed erscheint im Commit-Kanal, Commit landet in der lokalen SQLite (`data/ecobot.db`). --- -## Deployment (Docker / Portainer) +## HTTP-Endpoints -### 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** +| 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?page=` | — | Changelog | +| `GET /feed.xml` | — | RSS | +| `GET /devlog-assets/*` | — | Lokal gespeicherte Devlog-Bilder | +| `GET/PUT /api/settings`, `POST /api/settings/test/:target` | Admin | Setup-Seite | +| `GET /api/commits?page=` · `DELETE /api/devlogs/:id` | Admin | Commit-Archiv · Devlog löschen | +| `GET /auth/login` · `/auth/callback` · `/auth/logout` | — | Discord-OAuth2 | -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 -``` +Devlogs, die in Discord gelöscht werden, verschwinden automatisch auch aus dem +Archiv (MessageDelete-Sync) — zusätzlich gibt es den ✕-Button für Admins auf der Webseite. --- @@ -260,30 +193,36 @@ docker logs -f ecobot ``` ecobot/ ├── src/ -│ ├── index.js # Einstiegspunkt (Bot + Webserver) -│ ├── config.js # Env-Konfiguration mit Validierung -│ ├── db.js # SQLite (better-sqlite3), Schema + Queries +│ ├── index.js # Start: Bot, Webserver, Wochen-Rückblick, Watchdog +│ ├── config.js # Env-Konfiguration mit Validierung +│ ├── db.js # SQLite: Schema, Migrationen, FTS5, alle Queries +│ ├── runtime-settings.js # Effektive Settings (DB vor Env) +│ ├── gitea-api.js # Gitea-REST (Issues + Assets für /bug) │ ├── 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) +│ │ ├── client.js # Discord-Client, Commands, Listener (Devlog, Delete, 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 + Scheduler +│ │ ├── watchdog.js # URL-Checks + DM-Alarm +│ │ └── commands/ # ping, devlog-backfill, bug │ └── 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) +│ ├── server.js # Fastify: Webhooks, Static, SPA-Fallback +│ ├── auth.js # Discord-OAuth2 + Session-Cookies +│ ├── api.js # REST-API + Settings + RSS +│ └── devlog-endpoint.js# Devlog-Post: Embed, Bilder, Ping, Thread, Archiv +├── frontend/ # React + Vite (D4RKST3R-Design) │ └── 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 +│ ├── App.jsx # Layout, Router, Nav, Login-Status +│ ├── markdown.jsx # Mini-Markdown (fett/kursiv/Code/Links/Listen/---/##) +│ └── pages/ # Devlogs, Changelog, Commits, Settings +├── tools/test-webhook.mjs # Lokaler Commit-Feed-Test +├── .env.example # Vorlage für alle Env-Variablen +├── Dockerfile # Multi-Stage: Frontend-Build + node:22-slim Runtime +└── docker-compose.yml # Portainer-ready, Volume ecobot_data, TZ ``` -Neue Slash-Commands: Datei in `src/bot/commands/` anlegen (exportiert `data` + `execute`) -und in `src/bot/client.js` bei `commandModules` eintragen. +**Neue Slash-Commands:** Datei in `src/bot/commands/` (exportiert `data` + `execute`) +und in `client.js` bei `commandModules` eintragen. +**Neue Settings:** Key in `db.js`-Settings nutzen, Zugriff über `runtime-settings.js`, +UI in `frontend/src/pages/Settings.jsx`, GET/PUT in `src/web/api.js`.