···11+# CLAUDE.md
22+33+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
44+55+## Project
66+77+Turn-based management game with a card-based UI (Magic: The Gathering style), playable in a web browser. This is a learning project — the user is discovering game development, Rust, and Svelte simultaneously. Prioritize explanations and trade-offs over raw code output.
88+99+## Learning mode (important)
1010+1111+This is a learning project. Do NOT write implementation code on the user's behalf when they could learn by writing it themselves. Instead, leverage the Learning output style to orient them: explain concepts, compare trade-offs, point at the relevant patterns, and use the "Learn by Doing" request format to hand off meaningful code decisions. Scaffolding, configuration, and boilerplate are fair game to write directly — but core logic (game engine, state transitions, business rules, component architecture) should come from the user, with Claude guiding.
1212+1313+## Architecture
1414+1515+- **`backend/`** — Rust (Axum + SQLx + Tokio). Serves the game API and owns the game state machine. Game state is stored as JSONB in PostgreSQL.
1616+- **`frontend/`** — Svelte 5 + TypeScript SPA (Vite, no SvelteKit). Communicates with the backend via REST.
1717+- **`infra/`** — Kubernetes manifests (deployment target). Not used for local dev.
1818+- **`docker-compose.yml`** — Local dev: PostgreSQL 17 only.
1919+2020+## Development
2121+2222+### Prerequisites
2323+- Rust toolchain, Node.js, Docker
2424+- `cargo install sqlx-cli --no-default-features --features postgres`
2525+2626+### Start local environment
2727+```bash
2828+docker compose up -d # PostgreSQL
2929+cd backend && cargo run # API on :3000 (runs migrations automatically)
3030+cd frontend && npm run dev # Svelte dev server
3131+```
3232+3333+### Backend commands (from `backend/`)
3434+```bash
3535+cargo run # build + run (migrations auto-applied)
3636+cargo build # compile only
3737+cargo sqlx prepare # generate offline query metadata for CI builds
3838+RUST_LOG=tower_http=debug cargo run # verbose HTTP request logging
3939+```
4040+4141+### Frontend commands (from `frontend/`)
4242+```bash
4343+npm run dev # vite dev server with HMR
4444+npm run build # production build
4545+npm run check # svelte-check + tsc type checking
4646+```
4747+4848+### Database
4949+```bash
5050+sqlx database create # create the dyfc database
5151+sqlx migrate run # apply migrations (also done on cargo run)
5252+docker compose down -v # full DB reset (destroys volume)
5353+```
5454+5555+### SQLx compile-time checking
5656+SQLx macros (`query!`, `query_scalar!`) verify SQL against the live database at compile time. PostgreSQL must be running and migrations applied before `cargo build` will succeed. Set `SQLX_OFFLINE=true` to build against cached metadata instead (run `cargo sqlx prepare` first).
5757+5858+## Key conventions
5959+6060+- Backend environment variables live in `backend/.env` (loaded by dotenvy). Required: `DATABASE_URL`, `RUST_LOG`.
6161+- SQL migrations go in `backend/migrations/` with numeric prefix ordering.
6262+- Game state is serialized as a single JSONB column via serde. The game engine logic (state machine) should remain pure — no HTTP or DB concerns — for testability.
···1111use tower_http::trace::TraceLayer;
1212use tracing_subscriber;
13131414+mod game;
1515+use crate::game::Gauges;
1616+1417// === App State ===
1518// Ce qui est partage entre tous les handlers (clone-able, passe via State)
1619
+72
todo.md
···11+# TODO — Moteur de jeu (première itération)
22+33+Suivi de ce qu'il reste à implémenter pour avoir un moteur de jeu minimal:
44+jauges + action simple, vérifiable par `cargo check` puis testable via l'API.
55+66+---
77+88+## 1. Créer la structure du module `game`
99+1010+- [x] Créer le dossier `backend/src/game/`.
1111+- [x] Créer `backend/src/game/mod.rs` — déclare les sous-modules (`pub mod state;`,
1212+ `pub mod action;`) et re-exporte les types publics (`pub use state::...;`).
1313+- [x] Ajouter `mod game;` au début de `backend/src/main.rs` pour que le compilateur
1414+ découvre le module.
1515+1616+## 2. Définir les types d'état (`backend/src/game/state.rs`)
1717+1818+- [x] `Gauges` — struct avec `money: i32`, `internal_support: i32`, `mental_load: i32`.
1919+ Dérive `Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq`.
2020+- [ ] `Gauges::starting()` — valeurs de départ (`money: 1000`, `internal_support: 50`,
2121+ `mental_load: 20`).
2222+- [ ] `GameOverReason` — enum unitaire: `Bankruptcy`, `LostSupport`, `Burnout`.
2323+- [ ] `GameStatus` — enum: `Running` | `Lost(GameOverReason)`. Utiliser
2424+ `#[serde(tag = "kind", content = "reason")]` pour un JSON propre.
2525+- [ ] `GameState` — struct: `turn: u32`, `gauges: Gauges`, `status: GameStatus`.
2626+- [ ] `GameState::new()` — construit l'état initial en utilisant `Gauges::starting()`
2727+ et `GameStatus::from_gauges(...)`.
2828+2929+## 3. Règle de fin de partie (`backend/src/game/state.rs`)
3030+3131+- [ ] `GameStatus::from_gauges(Gauges) -> GameStatus`.
3232+ - `money <= 0` → `Lost(Bankruptcy)`
3333+ - `internal_support <= 0` → `Lost(LostSupport)`
3434+ - `mental_load >= 100` → `Lost(Burnout)`
3535+ - sinon → `Running`
3636+ - Attention: inégalités strictes côté règles (`0` et `100` sont déjà perdants).
3737+ - Décision à faire: ordre de priorité si plusieurs conditions sont vraies en même temps.
3838+3939+## 4. Actions et transition (`backend/src/game/action.rs`)
4040+4141+- [ ] `GaugeDelta` — même forme que `Gauges`. Dérive `Default` pour construire avec
4242+ `..Default::default()`.
4343+- [ ] `Action` — struct: `id: String`, `label: String`, `effect: GaugeDelta`.
4444+- [ ] `GameError` — enum avec au moins `GameOver` pour l'instant.
4545+- [ ] `apply_action(&GameState, &Action) -> Result<GameState, GameError>`.
4646+ - Si `state.status` n'est pas `Running` → `Err(GameOver)`.
4747+ - Sinon: additionner `effect` à `gauges`, `turn + 1`, recalculer `status`.
4848+ - Cœur de la boucle de jeu — état immuable en entrée, nouvel état en sortie.
4949+5050+## 5. Câblage dans `main.rs`
5151+5252+- [ ] Supprimer les anciens `struct GameState` et `struct Resources` (placeholders
5353+ `gold/food/population`) devenus obsolètes.
5454+- [ ] Adapter `create_game` pour utiliser le nouveau `game::GameState::new()`.
5555+- [ ] Vérifier que `cargo build` passe (SQLx a besoin de Postgres lancé).
5656+5757+## 6. Tests unitaires (optionnel mais recommandé)
5858+5959+- [ ] Dans `state.rs`, module `#[cfg(test)]` qui vérifie `from_gauges` sur chaque
6060+ condition de fin + cas de coexistence (money ET support à 0 en même temps).
6161+- [ ] Dans `action.rs`, test qui applique une action et vérifie le nouvel état
6262+ (gauges, turn, status).
6363+6464+---
6565+6666+## Plus tard (hors scope de cette itération)
6767+6868+- Endpoint `POST /games/{id}/actions` qui charge l'état, appelle `apply_action`,
6969+ resauvegarde le JSONB.
7070+- Catalogue d'actions côté backend (ou côté frontend?) — à décider.
7171+- Système d'événements (3 choix par tour, tirés d'un pool).
7272+- Résultats de matchs et leur influence sur les jauges.