Files
Michess/Brain.md
Kroonk 77e30e268b
All checks were successful
Build & Push Docker Image to Gitea Registry / build-and-push (push) Successful in 2m39s
docs: update Brain.md with SSO integration details and troubleshooting hypotheses
2026-05-21 11:42:28 +02:00

8.7 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)

  1. Stockfish AI-Gegner — verschiedene Schwierigkeitsgrade (Level 1-8, ELO-basiert)
  2. Admin-Panel — Nutzerverwaltung, Git-Pull-Button, Statistiken
  3. Freundessystem — Freundschaftsanfragen, Freundesliste, Freunde herausfordern
  4. Branding — Alles auf "MiChess" umbenennen
  5. Docker NAS-Deployment — docker-compose für NAS, Auto-Update-Script
  6. DB-Schema Erweiterungen — admin-Flag, friends-Tabelle, friend_requests-Tabelle
  7. 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) und Depth
  • Pro aktiver AI-Partie: eigener Stockfish-Prozess (oder Pool)

Admin-Rolle

  • role Spalte in user-Tabelle (default: 'user', admin: 'admin')
  • Erster User mit email aus ADMIN_EMAIL env 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 pull im Container-Verzeichnis aus
  • Triggert danach Neustart (via restart-policy des Containers)
  • Update-Script wird ins Docker-Image eingebaut

Docker NAS-Setup

  • docker-compose.yml mit 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.de gesetzt
  • 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 stockfish oder 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-content getriggert ü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-outside via mousedown auf Dokumentenebene) ohne tabIndex={0}.
  • Docker Env Mapping Empty Strings: Im docker-compose.yml sorgt die Syntax SSO_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 wie process.env.SSO_CLIENT_ID fehlschlagen.

🔑 Keycloak SSO Integration & UX Overhaul

1. Backend-Erweiterungen (Server)

  • Paket: openid-client für OIDC-Standard-Interaktionen.
  • Endpunkte (/v1/auth/sso/*):
    • GET /v1/auth/sso/config: Gibt { enabled: boolean } zurück. Erkennt SSO als aktiv, sobald SSO_CLIENT_SECRET gesetzt ist (die optionalen Variablen SSO_CLIENT_ID und SSO_AUTHORITY haben Code-Fallbacks).
    • GET /v1/auth/sso/login: Initiiert den OIDC-Flow und leitet zur Keycloak Realm mischlabs weiter.
    • 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 admin befördert, wenn ihr Benutzername MrDiderot lautet oder wenn die Benutzer-Datenbank leer ist (andernfalls Rolle user).

2. Frontend-Umbau (Client)

  • Popup-Entfernung: AuthModal.tsx wurde komplett gelöscht. Es gibt beim Laden der Seite kein störendes Popup mehr.
  • Avatar-Dropdown: Einbettung von AuthDropdownContent.tsx in Header.tsx fü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/.env eingetragen, 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:
    docker exec -it michess env | grep SSO
    
    Wenn hier SSO_CLIENT_SECRET fehlt 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 wie docker-compose.yml liegt 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 .env existiert:
    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 von https://michess-api.mischlabs.de/v1/auth/sso/config abzufragen. 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:
    1. Öffne die Entwicklerkonsole des Browsers (F12) -> Netzwerk-Tab (Network).
    2. Lade die Seite neu und filtere nach config oder sso.
    3. Prüfe den HTTP-Statuscode und die Antwort von https://michess-api.mischlabs.de/v1/auth/sso/config.
    4. Kommt dort { "enabled": false } zurück (dann ist es Vermutung A/B), oder scheitert der Request komplett (CORS/Netzwerkfehler)?

Nächste Schritte

  1. Prüfe die Browser-Konsole im Netzwerk-Tab, um zu sehen, ob die API-Antwort { enabled: false } liefert oder blockiert wird.
  2. Führe auf dem NAS docker exec -it michess env | grep SSO aus, um die Live-Umgebungsvariablen zu validieren.
  3. Führe einen sauberen Docker-Neustart aus (docker compose down && docker compose up -d).