# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. # Krafttrainer Einzelnutzer-Webapplikation zur Verwaltung und Protokollierung von Kraftübungen. ## Tech Stack - **Backend:** Go 1.22+ mit `net/http` stdlib Router, SQLite (`go-sqlite3`), `golang-migrate` - **Frontend:** React 19, Vite 8, TypeScript (strict), Tailwind CSS 4 (`@tailwindcss/vite`), Zustand, Recharts - **Paketmanager:** pnpm (Version in `packageManager` field fixiert) - **Produktion:** Single Binary via `embed` (Frontend in `backend/static/` eingebettet) ## Build & Run ```bash make dev-backend # Go-Server auf :8090 make dev-frontend # Vite Dev-Server auf :5173 (Proxy → :8090) make build # Single Binary ./krafttrainer (Frontend-Build + Go-Build mit CGO_ENABLED=1) make clean # Binary + Dist-Ordner entfernen ``` Frontend TypeScript-Typecheck (ohne Build): ```bash cd frontend && pnpm exec tsc --noEmit ``` Es gibt keine automatisierten Tests (weder Go-Tests noch Frontend-Tests). ## Deployment - Läuft auf `192.168.1.118:8090` als systemd-Service (`krafttrainer.service`) - User: `christoph`, Binary: `/home/christoph/krafttrainer/krafttrainer` - DB: `/home/christoph/krafttrainer/krafttrainer.db` - Deploy: `scp krafttrainer christoph@192.168.1.118:~/krafttrainer/`, dann `sudo systemctl restart krafttrainer` ## Architektur ### Backend-Flow `Handler → Store → DB`. Jeder Handler folgt exakt diesem Muster: 1. `decodeJSON()` mit `DisallowUnknownFields()` 2. `model.Validate()` aufrufen 3. Store-Methode aufrufen 4. Fehler differenzieren und `writeJSON()` / `writeError()` aufrufen Store-Methoden geben nach Mutationen immer **frisch aus der DB gelesene Objekte** zurück (kein Rekonstruieren aus Input). ### Fehlerbehandlung (Backend) - Store-Fehler → 500 (generisch, kein DB-Leak) - Validierungsfehler → 400 - Nicht gefunden (`sql.ErrNoRows`) → 404 - UNIQUE-Verletzung → 409 Sentinel-Strings im Error-Message für Handler-Differenzierung: `"UNIQUE_VIOLATION:"`, `"SESSION_CLOSED"`. Diese werden mit `strings.Contains()` geprüft — kein custom error type. ### Routing Go 1.22+ Pattern-Matching im stdlib ServeMux mit `{id}`-Platzhaltern. Middleware-Chain: `Recoverer → RequestLogger → CORS`. SPA-Fallback in `main.go`: prüft zuerst ob statische Datei existiert, serviert sonst `index.html`. ### Frontend-Stores (Zustand) Stores sind **flach und unabhängig** — keine direkte Store-zu-Store-Kommunikation. Feedback läuft ausschließlich über `useToastStore.getState().addToast()`. `activeSessionStore` verwaltet einen Timer-Interval manuell (kein React-Effect-Cleanup — beim `stopTimer()` explizit clearen). Alle HTTP-Aufrufe gehen über `src/api/client.ts`. `ApiError` (extends Error) hat `status`-Property für HTTP-Statuscodes. ### Datenbank - SQLite mit WAL-Mode und Foreign Keys (via Connection-String-Parameter in `store.go`) - Migrations auto-run beim Start via embedded FS (`backend/migrations/embed.go`) - `exercise_name` in `session_logs` **denormalisiert** gespeichert (damit gelöschte Übungen historische Daten nicht verwaisen lassen) - UNIQUE-Constraint auf `(session_id, exercise_id, set_number)` - Soft-Delete bei Übungen via `deleted_at` Timestamp ## Konventionen - **API Prefix:** Alle Endpoints unter `/api/v1`. Fehler als `{ "error": "..." }`. - **Gewichte:** Immer in kg. Feldnamen mit `_kg` Suffix (`weight_kg`, `weight_step_kg`). - **UI-Sprache:** Deutsch. - **Dark Mode:** Default. `bg-gray-950` Body, `bg-gray-900` Cards, `blue-500` Primary. - **Touch-Targets:** min 44×44px. ## Vollständige Spezifikation Siehe `PRD.md` im übergeordneten Verzeichnis (`03_Projekte/fitness-pad/PRD.md`) für: - Vollständiges SQLite-Schema (Abschnitt 4.1) - Alle Go-Structs und TypeScript-Typen (Abschnitt 4.2–4.3) - Komplette API-Spezifikation mit Request/Response-Beispielen (Abschnitt 5) - Validierungsregeln (Abschnitt 6) - Frontend-Spezifikation und Komponentenverhalten (Abschnitt 7)