Betreiber am 04.09.2026: "koennen wir das nicht mit in die webseite einbauen,
das er sich das ueber das acp holt?" - das ist der bessere Entwurf, und der
Grund ist das geringste Recht.
WAS DER ERSTE ANLAUF FALSCH GEMACHT HAETTE
Er haette dem Bot das Geheimnis von d4rk_web gegeben. Dann haetten ZWEI
Dienste den Schluessel zu allem gehabt: Rechtematrix, Spielerliste, Protokoll,
Schreibweg. Ein Bot, der nur wissen soll, ob jemand die Whitelist verwalten
darf, braucht davon nichts.
Jetzt bleibt das Panel der einzige, der mit dem Spielserver redet, und der Bot
bekommt einen eigenen Schluessel (BOT_TOKEN), der genau eine Tuer oeffnet:
/bot/person.
EIGENER PFAD, EIGENER WAECHTER
/bot/ statt /api/bot/, weil der Sitzungswaechter dort Discord-Anmeldung und
Rolle prueft - beides hat eine Maschine nicht. Der Botwaechter vergleicht den
Schluessel zeichenweise (dieselbe Ueberlegung wie in d4rk_web) und antwortet
bei fehlendem oder falschem Schluessel mit 404, nicht 401: wer von aussen
probiert, soll nicht erfahren, dass es hier einen Maschinenzugang gibt.
Unter 32 Zeichen gibt es den Weg gar nicht - eine halbe Konfiguration darf
keine Tuer aufmachen.
DURCHGEREICHT, NICHT AUSGEWERTET. Das Panel entscheidet an dieser Stelle
nichts; sonst waere es die zweite Rechteverwaltung, die ADR-0012 ausschliesst.
NEBENBEI ZWEI FALLEN VERMIEDEN
Dem Bot fehlt extra_hosts - host.docker.internal haette gar nicht aufgeloest,
und der Fehler haette wie "Spielserver antwortet nicht" ausgesehen. Ueber das
oeffentliche Panel braucht er es nicht.
Und das Panel nennt seine zwei Werte D4RK_WEB_URL/D4RK_WEB_TOKEN; mein
Botmodul hiess erst SPIELSERVER_*. Zwei Vokabeln fuer eine Sache bedeuten,
dass man beim Umzug an zwei Stellen sucht und eine vergisst. Die Datei heisst
jetzt panel.js - ein Modul namens spielserver.js, das mit dem Panel redet,
waere ein Name, der luegt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zwei falsche Diagnosen hintereinander, beide aus einem Zwischenstand
geschlossen, waehrend der Vorgang noch lief. Was wirklich passiert ist:
12:48:18 Push 93156e5
12:48 Portainer hat die Dateien im Stack-Verzeichnis
12:57 hier gemessen: Abbild 15 h alt, Container von gestern
-> daraus "er baut nicht" geschlossen. FALSCH.
13:01:02 Abbild neu gebaut
13:01:14 Container neu gestartet
13:02 pruefeSicherung im Container: 2, melden.js da, Panel HTTP 200
Zwischen Push und laufendem neuen Code liegen rund DREIZEHN MINUTEN -- Portainer
fragt in Intervallen nach, nicht sofort. Die Messung um 12:57 fiel mitten in
dieses Fenster: die Dateien waren schon da, das Abbild noch nicht neu. Aus dem
Schnappschuss habe ich einen Systemfehler gemacht.
Das ist genau der Fehler, gegen den der Bericht geschrieben ist -- eine
plausible Erklaerung, die zum Schnappschuss passt, behauptet, bevor der Vorgang
zu Ende war.
pull_policy: build bleibt drin, aber NICHT mehr aus dem Grund im Commit davor.
Es repariert nichts; es macht das Neubauen nur ausdruecklich, damit ein
handgetipptes `docker compose up -d` dasselbe tut wie die Automatik. Folgenlos
entfernbar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der erste Verdacht ("kein Runner") war die halbe Wahrheit. Portainers
GitOps-Weg funktioniert, nachgemessen in seinem eigenen Datenverzeichnis:
/d/compose/1/src/melden.js 12:48 <- die Uhrzeit des Pushes
/d/compose/1/stack.env 12:57 <- Portainer hat neu geschrieben
docker images d4rkbot:latest 00:21 <- das Abbild 15 Stunden alt
Portainer holt den neuen Stand also brav ins Stack-Verzeichnis und ruft dann
docker compose up -d. UND DAS BAUT NUR, WENN DAS ABBILD FEHLT. d4rkbot:latest
gab es -- also kein Bau, kein neuer Container, und der Bot lief weiter mit dem
Code von vorgestern.
Kein Runner, kein Webhook, keine Fehlermeldung: es sah nach "nichts zu tun"
aus. Das ist die unangenehme Sorte Fehler -- man pusht, hakt es ab, und der
Fehler, den man gerade behoben hat, laeuft weiter.
pull_policy: build laesst compose bei jedem Ausrollen neu bauen. Geprueft mit
docker compose config (v5.3.1 nimmt es an und gibt es aufgeloest zurueck).
Einmal noch von Hand, denn die Zeile wirkt erst, wenn sie selbst ausgerollt
ist: Portainer -> Stack ecobot -> Pull and redeploy.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- /bug (alle Member): erstellt Gitea-Issue inkl. Screenshot-Upload als Asset;
bug_reports-Tabelle für den Rückkanal — Issue geschlossen (issues-Webhook)
→ DM an den Reporter
- Auto-Thread '💬 Devlog <Datum>' unter jedem Devlog-Post (Setting, Default an)
- Watchdog: prüft Setting watchdog_urls alle 2 min, DM an Admin nach 2 Fails
in Folge + Entwarnung mit Downtime-Dauer
- Setup-Seite: Bug-Repo, Threads-Toggle, Watchdog-URLs; Env GITEA_API_TOKEN/GITEA_URL
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Scheduler (5-Minuten-Check, dedupe über last_weekly_recap-Setting)
- Embed: Commits pro Tag als Balken-Grafik, Commit-/Devlog-Zahlen, Top-Projekte
- Setting weekly_recap_enabled + 'Rückblick jetzt testen'-Button auf der Setup-Seite
- TZ Europe/Berlin im Compose (Scheduler + Datumsformate)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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>
- Discord-OAuth2-Login (identify-Scope, CSRF-State, signierte Session-Cookies, keine Token-Speicherung)
- REST-API: /api/devlogs (öffentlich), /api/commits (nur ADMIN_DISCORD_ID), /api/me
- React + Vite Frontend: Devlog-Archiv mit Mini-Markdown-Renderer, Commit-Tabelle, dunkles EcoGame-Theme
- Fastify liefert frontend/dist mit SPA-Fallback aus; Vite-Dev-Proxy für lokale Entwicklung
- Multi-Stage-Dockerfile (Frontend-Build im Image), neue Env-Vars in Compose + .env.example
- README: OAuth2-Setup (Redirect-URLs, Client Secret) und Frontend-Workflow
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Webhook-Nachrichten im Devlog-Kanal werden automatisch in SQLite archiviert
(devlog.py im EcoGame-Repo bleibt unverändert)
- /devlog-backfill (Admin): scannt die komplette Kanal-Historie in 100er-Blöcken
- Dedupe über Discord-Message-ID, Embeds werden mit Titel+Beschreibung erfasst
- Neue Intents: GuildMessages + MessageContent, neue Env-Var DEVLOG_CHANNEL_ID
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- docker-compose.yml: Variablen per Interpolation (lokal aus .env, in Portainer aus Stack-Env)
- tools/test-webhook.mjs: signierte Fake-Testzustellung gegen die lokale Instanz
- README: Portainer-Anleitung präzisiert (Git-Auth für privates Repo, Pull and redeploy)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Fastify-Webserver mit /health und /webhooks/gitea (HMAC-SHA256-Signaturprüfung, timing-safe)
- Push-Commits werden in SQLite gespeichert (Dedupe per SHA) und als Embed gepostet
- Dockerfile auf node:22-slim (glibc-Prebuilds für better-sqlite3), Port 3080 published
- README: Anleitung für Cloudflare-DNS, Nginx Proxy Manager (bot.d4rkst3r.de) und Gitea-Webhook
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- discord.js v14 Bot mit Slash-Command-Registry (Guild oder global)
- Konfiguration über .env mit Validierung (config.js)
- Dockerfile + docker-compose.yml für Portainer-Deployment
- README mit Schritt-für-Schritt-Anleitung (Discord Developer Portal)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>