diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..5109bed --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,32 @@ +# Codex Instructions – helldivers + +## Pflichtlektüre vor dem ersten Code-Zugriff +Lies **PROJECT_MAP.md** in diesem Verzeichnis – sie enthält alle Funktionen, API-Routen, WebSocket-Message-Types, State-Struktur und Datenbank-Details. + +## Projekt-Überblick +- **Port:** 3012 +- **Typ:** Authenticated Multiplayer App (WebSocket, SQLite, ELO-Rating) +- **Stack:** Node.js / Express, WebSocket (ws), SQLite (better-sqlite3), bcrypt, Helmet, rate-limit, Vanilla JS +- **Features:** Stratagem-Trainer (Timed/Endless/Drill/Speedrun), 1v1-Multiplayer-Matches, ELO-Rangliste, Tages-Challenge, Admin-Panel + +## Struktur +``` +helldivers/ +├── server.js # Express + WebSocket + SQLite (~650 Zeilen) +├── public/app.js # Gesamte Client-Logik (~1840 Zeilen) +├── public/styles.css +├── public/index.html +├── scripts/ # DB-Migrations / Seed +└── data/helldivers.db # SQLite (Scores, Users, History, Sessions) +``` + +## Git-Workflow +1. Branch: immer `bugfixes-features` für Änderungen +2. Commit: `type: kurze Beschreibung` – **keine Co-Authored-By-Zeile** +3. Vor Commit: `CHANGELOG.md` aktualisieren +4. Vor Commit: `PROJECT_MAP.md` aktualisieren, falls Funktionen/Routen/WS-Types geändert wurden +5. `git add` nur einzelne Dateien – kein `git add -A` +6. Merge nach `main` nur auf explizite Anweisung + +## Sicherheit +- Niemals `data/helldivers.db` committen diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c1a9a80 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,42 @@ +# CLAUDE.md – helldivers + +## Overview +Port: 3012 +Type: Authenticated Multiplayer App (WebSocket, SQLite, ELO-Rating, Bcrypt, Helmet) + +## Running +```bash +node server.js # Produktion +npm run dev # Entwicklung +``` + +## Structure +``` +helldivers/ +├── server.js # Express + WebSocket (ws) + SQLite (better-sqlite3) +├── public/app.js # Gesamte Client-Logik (~1840 Zeilen) +├── public/styles.css +├── public/index.html +├── scripts/ # DB-Migrations / Seed +└── data/helldivers.db +``` + +## Deployment +- Runs under PM2 on the host +- Nginx reverse-proxies to port 3012 + +## Branches +- `main` – stable, production-ready code +- `bugfixes-features` – active development + +## Commit Convention +`type: short description` +Types: `feat`, `fix`, `refactor`, `docs`, `chore` + +## PROJECT_MAP.md – Pflege + +Falls Funktionen, API-Routen, WebSocket-Message-Types oder State-Variablen **hinzugefügt, geändert oder entfernt** werden, muss `PROJECT_MAP.md` **vor dem Commit** aktualisiert werden. Gilt für beide KIs (Claude und Codex) gleichermaßen. + +## Changelog +- Nach jeder Änderung `CHANGELOG.md` aktualisieren +- Format: `## [Unreleased]` für laufende Änderungen diff --git a/PROJECT_MAP.md b/PROJECT_MAP.md new file mode 100644 index 0000000..8d678dd --- /dev/null +++ b/PROJECT_MAP.md @@ -0,0 +1,134 @@ +# Project Map – helldivers + +## Files +| File | Purpose | +|---|---| +| `server.js` | Express + WebSocket (ws) + SQLite (better-sqlite3) – Auth, Scores, Matchmaking | +| `public/app.js` | Gesamte Client-Logik (WebSocket-Client, Practice/Match/Lobby) | +| `public/styles.css` | Alle Styles | +| `public/index.html` | App-Shell | +| `data/helldivers.db` | SQLite-Datenbank (Scores, Users, Sessions, History) | +| `scripts/` | Migrations / Seed-Skripte | + +--- + +## app.js + +### State Object +```js +state = { + user, currentView, stratagems, + settings: { timerDuration, difficulty }, + practice: { + active, mode, current, queue, progress, timeLeft, timerHandle, startTime, + score, streak, selectedCats, dailyTarget, + lives, // Endless mode + drillPool, drillCompleted, drillTotal, // Drill mode + speedrunStart, speedrunPool, speedrunElapsed, // Speedrun mode + sessionStats: { completed, missed, bestTime, stratagems, mistakes, maxStreak } + }, + lobby: { online, incoming, pendingChallenge }, + match: { roomId, opponent, matchScores, current, myProgress, oppProgress, roundActive, roundHistory }, + leaderboard: { activeTab }, + history: { page, total }, + ws, wsReconnectTimer +} +``` + +### Constants +| Constant | Purpose | +|---|---| +| `RING_CIRCUMFERENCE` | `219.9` – Kreis-Umfang für Timer-Ring-Canvas (r=35) | +| `ELO_RANKS` | Array `{ min, label, color }` – ELO-Rangstufen | +| `STRATAGEMS` | Array aller Stratagems mit `name`, `category`, `icon`, `sequence` | + +### Key Functions – Settings & Navigation +| Function | Purpose | +|---|---| +| `loadSettings() / saveSettings()` | localStorage-Persistenz für Settings | +| `applySettingsToUI()` | Settings auf UI-Elemente anwenden | +| `showView(name)` | Ansicht wechseln (login/dashboard/practice/leaderboard/history/admin) | +| `connectWS() / wsSend(type, payload)` | WebSocket-Verbindung + Nachrichten senden | +| `handleWSMessage({ type, payload })` | Eingehende WS-Nachrichten dispatchen | + +### Key Functions – Practice +| Function | Purpose | +|---|---| +| `initPracticeView()` | Practice-View initialisieren | +| `getPool()` | Stratagem-Pool nach Filter + Modus aufbauen | +| `buildQueue() / renderQueue(queue)` | Warteschlange aufbauen und rendern | +| `nextStratagem()` | Nächstes Stratagem anzeigen | +| `handlePracticeInput(dir)` | Pfeilrichtung auswerten (Treffer/Fehler) | +| `startPracticeTimer() / stopPracticeTimer()` | Timer für Timed-Modus | +| `startSpeedrunTimer()` | Timer für Speedrun-Modus | +| `renderPracticeStratagem()` | Aktuelles Stratagem + Pfeile rendern | +| `renderArrows(containerId, sequence, progress)` | Pfeil-Sequenz rendern | +| `updateScoreDisplay() / updateStreakDisplay() / updateLivesDisplay()` | Score-UI | +| `openSessionSummary() / closeSessionSummary()` | Sitzungs-Zusammenfassung Modal | + +### Key Functions – Lobby & Match +| Function | Purpose | +|---|---| +| `updateLobbyView()` | Online-Nutzer-Liste aktualisieren | +| `sendChallenge(target) / acceptChallenge(from) / declineChallenge(from)` | Herausforderungen verwalten | +| `openChallengeModal(from, elo) / closeChallengeModal()` | Challenge-Dialog | +| `renderMatchRound()` | Aktive Match-Runde rendern | +| `handleMatchInput(dir)` | Match-Eingabe auswerten | +| `renderRoundResult(winner)` | Rundensieger anzeigen | +| `openMatchResultModal({ winner, eloChanges, roundHistory })` | Match-Ergebnis-Modal | + +### Key Functions – Admin & History +| Function | Purpose | +|---|---| +| `renderAdminOverview(data)` | Admin-Dashboard: Nutzer, Scores, Aktivität | +| `renderAdminUsers(users)` | Nutzertabelle im Admin-Bereich | +| `renderAdminActivity(data)` | Aktivitätslog rendern | +| `renderHistoryChart(sessions)` | Verlaufs-Diagramm (Canvas) | +| `renderHistoryPagination(limit)` | Pagination-Buttons | +| `renderDashboard({ stats, rank, elo, ... })` | Haupt-Dashboard-Kacheln | + +--- + +## server.js + +### Besonderheiten +- **SQLite** (better-sqlite3) statt JSON-Dateien +- **WebSocket** (ws-Library) für Multiplayer: Lobby, Challenges, Live-Matches +- **ELO-Rating-System** für 1v1-Matches + +### Server-Side State +| Variable | Purpose | +|---|---| +| `userSockets` | `Map` – aktive WebSocket-Verbindungen | +| `pendingChallenges` | `Map` | +| `rooms` | `Map` – aktive Match-Räume | + +### API Routes +| Route | Purpose | +|---|---| +| `POST /api/login` | Login (rate-limited) | +| `POST /api/logout` | Logout | +| `GET /api/me` | Session-Info | +| `POST /api/change-password` | Passwort ändern | +| `GET /api/users` | Alle Nutzer (Admin) | +| `POST /api/users` | Nutzer erstellen (Admin) | +| `DELETE /api/users/:username` | Nutzer löschen (Admin) | +| `POST /api/users/:username/reset-password` | Temp-Passwort (Admin) | +| `PATCH /api/users/:username` | Nutzerdaten ändern (Admin) | +| `GET /api/admin/overview` | Admin-Dashboard-Daten | +| `GET /api/admin/activity` | Aktivitätslog (Admin) | +| `GET /api/dashboard` | Dashboard-Daten (Stats, Rank, ELO, Daily) | +| `POST /api/scores/practice` | Practice-Session speichern | +| `GET /api/scores/leaderboard` | Gesamt-Leaderboard | +| `GET /api/scores/leaderboard/elo` | ELO-Rangliste | +| `GET /api/scores/leaderboard/speedrun` | Speedrun-Rangliste | +| `GET /api/scores/me` | Eigene Statistiken | +| `GET /api/history` | Session-Verlauf (paginiert) | +| `GET /api/stats/stratagems` | Stratagem-Trefferquoten | +| `GET /api/stratagems` | Stratagem-Liste (für Client-Sync) | + +### WebSocket Message Types (Client → Server) +`join`, `challenge`, `accept_challenge`, `decline_challenge`, `ready`, `input`, `leave_match` + +### WebSocket Message Types (Server → Client) +`lobby_update`, `challenge_received`, `challenge_declined`, `match_start`, `round_start`, `round_result`, `match_end`, `opponent_progress`, `error`