# 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 - [x] Basis-Projekt geclont (chessu) - [x] Brain.md erstellt - [x] 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: ```bash 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: ```bash 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: ```bash 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`).