Initial commit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Christoph K.
2026-03-21 15:03:55 +01:00
commit dfd66e43c6
78 changed files with 6219 additions and 0 deletions

93
CLAUDE.md Executable file
View File

@@ -0,0 +1,93 @@
# 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.24.3)
- Komplette API-Spezifikation mit Request/Response-Beispielen (Abschnitt 5)
- Validierungsregeln (Abschnitt 6)
- Frontend-Spezifikation und Komponentenverhalten (Abschnitt 7)