11 KiB
Brain.md — MiChess Project Memory
Dieses Dokument ist mein aktives Gedächtnis während der Entwicklung von MiChess. Ich denke hier, notiere Entscheidungen, Probleme und Fortschritt.
Projektziel
MiChess = Lichess-inspirierte Schachplattform, self-hosted auf einer NAS, in Docker, mit Stockfish-Engine.
Tech Stack (Entschieden)
| Schicht | Technologie | Grund |
|---|---|---|
| Frontend | Next.js 14 + React + Tailwind + daisyUI | Von chessu geerbt, modern, SSR-fähig |
| Backend | Node.js + Express + Socket.io | Von chessu geerbt, real-time-ready |
| Datenbank | PostgreSQL | Von chessu geerbt, solide |
| Auth | express-session + argon2 | Bereits vorhanden, sicher |
| Schach-Logik | chess.js | Bereits vorhanden |
| Schachbrett UI | react-chessboard | Bereits vorhanden |
| Stockfish | stockfish npm-Paket | Einfache Integration im Backend |
| Container | Docker Compose | NAS-Deployment |
| Package Manager | pnpm Workspaces | Monorepo-Setup |
Basis-Projekt
- Geclont von:
dotnize/chessu(MIT-Lizenz) - Warum: TypeScript, React/Next.js, Express, Socket.io, PostgreSQL, chess.js — perfekter Ausgangspunkt
- Was chessu schon hat:
- User-Accounts (name, email, password, wins/losses/draws)
- Session-Auth mit argon2-Passwort-Hashing
- Real-time Multiplayer via Socket.io
- Spiele mit PGN-Speicherung
- Public Games Liste
- Archiv (gespielte Partien)
- User-Profilseite
Was ich bauen muss (Delta zu chessu)
- Stockfish AI-Gegner — verschiedene Schwierigkeitsgrade (Level 1-8, ELO-basiert)
- Admin-Panel — Nutzerverwaltung, Git-Pull-Button, Statistiken
- Freundessystem — Freundschaftsanfragen, Freundesliste, Freunde herausfordern
- Branding — Alles auf "MiChess" umbenennen
- Docker NAS-Deployment — docker-compose für NAS, Auto-Update-Script
- DB-Schema Erweiterungen — admin-Flag, friends-Tabelle, friend_requests-Tabelle
- E-Mail-basierte Registrierung — (email-Feld schon da, braucht UI-Flow: email → unique username wählen)
Architektur-Entscheidungen
Stockfish im Backend
- Stockfish läuft als Child-Process auf dem Server (NAS)
- Kommunikation über UCI-Protokoll
- Schwierigkeitsgrade via
Skill Level(0-20) undDepth - Pro aktiver AI-Partie: eigener Stockfish-Prozess (oder Pool)
Admin-Rolle
roleSpalte inuser-Tabelle (default: 'user', admin: 'admin')- Erster User mit email aus
ADMIN_EMAILenv var wird automatisch Admin - Admin-Middleware schützt
/v1/admin/*Routen
Friends-System
friends-Tabelle: user_id_1, user_id_2 (symmetrisch)friend_requests-Tabelle: from_id, to_id, status (pending/accepted/rejected)- Nutzer suchen via Username
Git-Auto-Update (Admin-Feature)
- Admin-Route:
POST /v1/admin/update - Führt
git pullim Container-Verzeichnis aus - Triggert danach Neustart (via restart-policy des Containers)
- Update-Script wird ins Docker-Image eingebaut
Docker NAS-Setup
docker-compose.ymlmit Services:michess-app+postgres- Watchtower oder einfaches update-script für automatische Updates
- Alle Credentials via
.env-Datei
Aktueller Status
- Basis-Projekt geclont (chessu)
- Brain.md erstellt
- Plan.md erstellt
- Git remote auf
git.mischlabs.degesetzt - Projekt auf "MiChess" umbenannt
- DB-Schema erweitert (admin, friends, friend_requests)
- Stockfish integriert
- Admin-Panel gebaut
- Friends-System gebaut
- Docker NAS-Deployment finalisiert
- Alles committed & gepusht
Bekannte Probleme / Offene Fragen
- chessu's Dockerfile nutzt
CMD ["start"]— muss für MiChess angepasst werden (Server + Client separat oder zusammen) - Stockfish binary muss im Docker-Image vorhanden sein (Alpine Linux:
apk add stockfishoder npm-Paket) - Admin-Git-Pull: funktioniert nur wenn Container read-write Zugriff auf sein eigenes Verzeichnis hat — besser: Host-Script via webhook triggern
Lessons Learned
- CSS-only Dropdowns vs. Autofill Extensions: Rein CSS-basierte DaisyUI Dropdowns (
dropdown-contentgetriggert über:focus/tabIndex) schließen sich unkontrolliert, wenn Passwort-Manager (z.B. Vaultwarden) Fokus-Events abfangen oder Overlays einblenden. Lösung: Vollständig React-gesteuerter Dropdown-Zustand (useState,useRef,click-outsideviamousedownauf Dokumentenebene) ohnetabIndex={0}. - Docker Env Mapping Empty Strings: Im
docker-compose.ymlsorgt die SyntaxSSO_CLIENT_ID: ${SSO_CLIENT_ID:-}dafür, dass bei Auslassung der Variablen in der.env-Datei ein leerer String ("") in die Node.js-Umgebung gereicht wird. Node.js interpretiert""als falsy, wodurch Abfragen wieprocess.env.SSO_CLIENT_IDfehlschlagen.
🔑 Keycloak SSO Integration & UX Overhaul
1. Backend-Erweiterungen (Server)
- Paket:
openid-clientfür OIDC-Standard-Interaktionen. - Endpunkte (
/v1/auth/sso/*):GET /v1/auth/sso/config: Gibt{ enabled: boolean }zurück. Erkennt SSO als aktiv, sobaldSSO_CLIENT_SECRETgesetzt ist (die optionalen VariablenSSO_CLIENT_IDundSSO_AUTHORITYhaben Code-Fallbacks).GET /v1/auth/sso/login: Initiiert den OIDC-Flow und leitet zur Keycloak Realmmischlabsweiter.GET /v1/auth/sso/callback: Verarbeitet das authorization code grant, erfragt User-Infos und führt Just-In-Time (JIT) Provisionierung durch.
- Option A Permission Mapping: JIT-provisionierte Benutzer werden automatisch zu
adminbefördert, wenn ihr BenutzernameMrDiderotlautet oder wenn die Benutzer-Datenbank leer ist (andernfalls Rolleuser).
2. Frontend-Umbau (Client)
- Popup-Entfernung:
AuthModal.tsxwurde komplett gelöscht. Es gibt beim Laden der Seite kein störendes Popup mehr. - Avatar-Dropdown: Einbettung von
AuthDropdownContent.tsxinHeader.tsxfür unangekündigte Gäste. Bietet Reiter für Gast, Anmelden, Registrieren sowie die Keycloak-Schaltfläche (wenn aktiviert). - Passwort-Manager-Immunisierung: Vollständig React-kontrolliertes Dropdown gegen vorzeitiges Schließen beim Autofill.
🔍 Fehleranalyse: SSO-Schaltfläche fehlt weiterhin
Obwohl das Frontend-Update aktiv ist (Vaultwarden-Anmeldung schließt das Fenster nicht mehr), wird die Schaltfläche "Anmelden mit Keycloak" nicht angezeigt. Das bedeutet, dass der Client ssoEnabled === false setzt, weil der API-Call ${API_URL}/v1/auth/sso/config nicht { enabled: true } zurückgibt.
📋 Vermutungen und Diagnose-Ansätze (für Zweit-KI / Debugging)
Vermutung A: Die Umgebungsvariable SSO_CLIENT_SECRET ist im Backend-Container nicht geladen.
- Grund: Die Variable wurde in
/volume2/docker/mischlabs/.enveingetragen, aber Docker Compose hat den Container nicht vollständig mit der neuen Umgebung neu generiert. - Diagnose: SSH-Zugriff auf das NAS und Ausführen von:
Wenn hier
docker exec -it michess env | grep SSOSSO_CLIENT_SECRETfehlt oder leer ist, lädt der Container die Variable nicht. - Behebung: Den Container zwingend neu erstellen lassen, nicht nur updaten:
docker compose down && docker compose up -d
Vermutung B: Abweichende .env-Pfade oder fehlendes Volume-Mapping.
- Grund: Im Docker-Compose-Setup wird
SSO_CLIENT_SECRETüber${SSO_CLIENT_SECRET:-}zugewiesen. Wenn die.env-Datei nicht im selben Verzeichnis wiedocker-compose.ymlliegt oder Docker Compose sie nicht standardmäßig lädt, bleibt der Wert leer. - Diagnose: Prüfen, ob die Variable auf dem Docker-Host in der
.envexistiert:cat /volume2/docker/mischlabs/.env | grep SSO
Vermutung C: Netzwerkanfrage / CORS / SSL-Fehler beim Config-Call.
- Grund: Die Web-App (
https://michess.mischlabs.de) versucht den Status vonhttps://michess-api.mischlabs.de/v1/auth/sso/configabzufragen. Es könnte sein, dass dieser API-Call fehlschlägt (z.B. durch CORS-Sicherheitsrichtlinien, Cloudflare-Tunnel blockiert Requests mit Credentials, oder Mixed-Content-Fehler). - Diagnose:
- Öffne die Entwicklerkonsole des Browsers (F12) -> Netzwerk-Tab (Network).
- Lade die Seite neu und filtere nach
configodersso. - Prüfe den HTTP-Statuscode und die Antwort von
https://michess-api.mischlabs.de/v1/auth/sso/config. - Kommt dort
{ "enabled": false }zurück (dann ist es Vermutung A/B), oder scheitert der Request komplett (CORS/Netzwerkfehler)?
Nächste Schritte
- Prüfe die Browser-Konsole im Netzwerk-Tab, um zu sehen, ob die API-Antwort
{ enabled: false }liefert oder blockiert wird. - Führe auf dem NAS
docker exec -it michess env | grep SSOaus, um die Live-Umgebungsvariablen zu validieren. - Führe einen sauberen Docker-Neustart aus (
docker compose down && docker compose up -d).
SSO-Fix live geloest am 2026-05-21
Final funktionierende NAS-Umgebung
In /volume2/docker/mischlabs/.env:
SSO_AUTHORITY=https://auth.mischlabs.de/realms/mischlabs
SSO_CLIENT_ID=michess
SSO_CLIENT_SECRET=<keycloak_client_secret>
SSO_REDIRECT_URI=https://michess-api.mischlabs.de/v1/auth/sso/callback
APP_URL=https://michess.mischlabs.de
In docker-compose.yml im Service michess unter environment::
SSO_AUTHORITY: ${SSO_AUTHORITY:-https://auth.mischlabs.de/realms/mischlabs}
SSO_CLIENT_ID: ${SSO_CLIENT_ID:-michess}
SSO_CLIENT_SECRET: ${SSO_CLIENT_SECRET:-}
SSO_REDIRECT_URI: ${SSO_REDIRECT_URI:-https://michess-api.mischlabs.de/v1/auth/sso/callback}
APP_URL: ${APP_URL:-https://michess.mischlabs.de}
Nach Aenderungen:
cd /volume2/docker/mischlabs
docker compose up -d --force-recreate michess
docker exec michess env | grep SSO
curl https://michess-api.mischlabs.de/v1/auth/sso/config
Erwartete API-Antwort:
{"enabled":true}
Keycloak Client michess
Client ID: michess
Valid redirect URI: https://michess-api.mischlabs.de/v1/auth/sso/callback
Web origin: https://michess.mischlabs.de
Client scopes: email Default, profile Default
Fehlerverlauf
-
docker exec michess env | grep SSOwar leer, obwohl.envSSO-Werte enthielt.- Ursache: NAS-Compose reichte die Variablen nicht an den Container weiter.
- Fix:
SSO_*undAPP_URLindocker-compose.ymlunterenvironment:ergaenzt.
-
docker compose configmeldete YAML-Fehler.- Ursache: falsche Einrueckung und ein abgeschnittener langer Wert in
nano. - Fix: Alle Environment-Zeilen mit korrekter Einrueckung im Mapping-Stil (
KEY: value) gesetzt.
- Ursache: falsche Einrueckung und ein abgeschnittener langer Wert in
-
Compose warnte:
The "CMUe..." variable is not set.- Ursache: Das Secret war in Compose als
${ECHTES_SECRET}eingetragen. - Fix:
SSO_CLIENT_SECRET: ${SSO_CLIENT_SECRET:-}verwenden. Das echte Secret gehoert in.env.
- Ursache: Das Secret war in Compose als
-
Button erschien, aber Callback landete auf
https://michess.mischlabs.de/v1/auth/sso/callbackund gab 404.- Ursache:
SSO_REDIRECT_URIzeigte auf die Frontend-Domain. - Fix: Redirect URI auf API-Domain umgestellt.
- Ursache:
-
invalid_scopewurde durch Default Scopesemailundprofileim Keycloak-Client geloest.
Kurzform: SSO_REDIRECT_URI zeigt auf michess-api, APP_URL zeigt auf michess.