Files
krafttrainer/CLAUDE.md
Christoph K. dfd66e43c6 Initial commit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 15:03:55 +01:00

3.9 KiB
Executable File
Raw Blame History

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

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):

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)