mitai-jinkendo/CLAUDE.md
Lars c4cead9e27
Some checks failed
Deploy Development / deploy (push) Failing after 11m50s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 30s
docs: add comprehensive design system to CLAUDE.md
Added detailed documentation for:
- Color system (CSS variables)
- CSS class conventions
- Spacing & sizing standards
- Component patterns (loading, error, empty states)
- Jinkendo logo system
- Available custom commands

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 06:13:58 +01:00

296 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Mitai Jinkendo Entwickler-Kontext für Claude Code
## Projekt-Übersicht
**Mitai Jinkendo** (身体 Jinkendo) ist eine selbst-gehostete PWA für Körper-Tracking (Gewicht, Körperfett, Umfänge, Ernährung, Aktivität) mit KI-Auswertung. Teil der **Jinkendo**-App-Familie (人拳道 Der menschliche Weg der Kampfkunst).
**Produktfamilie:** mitai · miken · ikigai · shinkan · kenkou (alle unter jinkendo.de)
## Tech-Stack
| Komponente | Technologie | Version |
|-----------|-------------|---------|
| Frontend | React 18 + Vite + PWA | Node 20 |
| Backend | FastAPI (Python) | Python 3.12 |
| Datenbank | SQLite (v9a) → PostgreSQL (v9b geplant) | - |
| Container | Docker + Docker Compose | - |
| Webserver | nginx (Reverse Proxy) | Alpine |
| Auth | Token-basiert + bcrypt | - |
| KI | OpenRouter API (claude-sonnet-4) | - |
## Ports
| Service | Prod | Dev |
|---------|------|-----|
| Frontend | 3002 | 3099 |
| Backend | 8002 | 8099 |
## Verzeichnisstruktur
```
mitai-jinkendo/
├── backend/
│ ├── main.py # FastAPI App, alle Endpoints (~2000 Zeilen)
│ ├── requirements.txt
│ └── Dockerfile
├── frontend/
│ ├── src/
│ │ ├── App.jsx # Root, Auth-Gates, Navigation
│ │ ├── app.css # Globale Styles, CSS-Variablen
│ │ ├── context/
│ │ │ ├── AuthContext.jsx # Session, Login, Logout
│ │ │ └── ProfileContext.jsx # Aktives Profil
│ │ ├── pages/ # Alle Screens
│ │ └── utils/
│ │ ├── api.js # Alle API-Calls (injiziert Token automatisch)
│ │ ├── calc.js # Körperfett-Formeln
│ │ ├── interpret.js # Regelbasierte Auswertung
│ │ ├── Markdown.jsx # Eigener MD-Renderer
│ │ └── guideData.js # Messanleitungen
│ └── public/ # Icons (Jinkendo Ensō-Logo)
├── .gitea/workflows/
│ ├── deploy-prod.yml # Auto-Deploy bei Push auf main
│ ├── deploy-dev.yml # Auto-Deploy bei Push auf develop
│ └── test.yml # Build-Test bei jedem Push
├── docker-compose.yml # Produktion (Ports 3002/8002)
├── docker-compose.dev-env.yml # Development (Ports 3099/8099)
└── CLAUDE.md # Diese Datei
```
## Aktuelle Version: v9a
### Was implementiert ist:
- ✅ Multi-User mit E-Mail + Passwort Login (bcrypt)
- ✅ Auth-Middleware auf ALLE Endpoints (44 Endpoints geschützt)
- ✅ Rate Limiting (Login: 5/min, Reset: 3/min)
- ✅ CORS konfigurierbar via ALLOWED_ORIGINS in .env
- ✅ Admin/User Rollen, KI-Limits, Export-Berechtigungen
- ✅ Gewicht, Umfänge, Caliper (4 Formeln), Ernährung, Aktivität
- ✅ FDDB CSV-Import (Ernährung), Apple Health CSV-Import (Aktivität)
- ✅ KI-Analyse: 6 Einzel-Prompts + 3-stufige Pipeline (parallel)
- ✅ Konfigurierbare Prompts mit Template-Variablen
- ✅ Verlauf mit 5 Tabs + Zeitraumfilter + KI pro Sektion
- ✅ Dashboard mit Kennzahlen, Zielfortschritt, Combo-Chart
- ✅ Assistent-Modus (Schritt-für-Schritt Messung)
- ✅ PWA (iPhone Home Screen), Jinkendo Ensō-Logo
- ✅ E-Mail (SMTP) für Password-Recovery
- ✅ Admin-Panel: User verwalten, KI-Limits, E-Mail-Test
- ✅ Multi-Environment: Prod (mitai.jinkendo.de) + Dev (dev.mitai.jinkendo.de)
- ✅ Gitea CI/CD mit Auto-Deploy auf Raspberry Pi 5
### Was in v9b kommt:
- 🔲 PostgreSQL Migration (aktuell noch SQLite)
- 🔲 Selbst-Registrierung mit E-Mail-Bestätigung
- 🔲 Freemium Tier-System (free/basic/premium/selfhosted)
- 🔲 14-Tage Trial automatisch
- 🔲 Einladungslinks für Beta-Nutzer
- 🔲 Admin kann Tiers manuell setzen
### Was in v9c kommt:
- 🔲 OAuth2-Grundgerüst für Fitness-Connectoren
- 🔲 Strava Connector
- 🔲 Withings Connector (Waage)
- 🔲 Garmin Connector
## Deployment
### Infrastruktur
```
Internet → privat.stommer.com (Fritz!Box DynDNS)
→ Synology NAS (Reverse Proxy + Let's Encrypt)
→ Raspberry Pi 5 (192.168.2.49, Docker)
```
### Git Workflow
```
develop branch → Auto-Deploy → dev.mitai.jinkendo.de (Port 3099/8099)
main branch → Auto-Deploy → mitai.jinkendo.de (Port 3002/8002)
```
### Deployment-Befehle (manuell falls nötig)
```bash
# Prod
cd /home/lars/docker/bodytrack
docker compose -f docker-compose.yml build --no-cache
docker compose -f docker-compose.yml up -d
# Dev
cd /home/lars/docker/bodytrack-dev
docker compose -f docker-compose.dev-env.yml build --no-cache
docker compose -f docker-compose.dev-env.yml up -d
```
## Datenbank-Schema (SQLite, v9a)
### Wichtige Tabellen:
- `profiles` Nutzer (role, pin_hash/bcrypt, email, auth_type, ai_enabled)
- `sessions` Auth-Tokens mit Ablaufdatum
- `weight_log` Gewichtseinträge (profile_id, date, weight)
- `circumference_log` 8 Umfangspunkte
- `caliper_log` Hautfaltenmessung, 4 Methoden
- `nutrition_log` Kalorien + Makros (aus FDDB-CSV)
- `activity_log` Training (aus Apple Health oder manuell)
- `ai_insights` KI-Auswertungen (scope = prompt-slug)
- `ai_prompts` Konfigurierbare Prompts mit Templates (11 Prompts)
- `ai_usage` KI-Calls pro Tag pro Profil
## Auth-Flow (v9a)
```
Login-Screen → E-Mail + Passwort → Token im localStorage
Token → X-Auth-Token Header → Backend require_auth()
Profile-Id → aus Session (nicht aus Header!)
SHA256 Passwörter → automatisch zu bcrypt migriert beim Login
```
## API-Konventionen
- Alle Endpoints: `/api/...`
- Auth-Header: `X-Auth-Token: <token>`
- Responses: immer JSON
- Fehler: `{"detail": "Fehlermeldung"}`
- Rate Limit überschritten: HTTP 429
## Umgebungsvariablen (.env)
```
OPENROUTER_API_KEY= # KI-Calls
OPENROUTER_MODEL=anthropic/claude-sonnet-4
SMTP_HOST= # E-Mail
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
SMTP_FROM=
APP_URL=https://mitai.jinkendo.de
ALLOWED_ORIGINS=https://mitai.jinkendo.de
DATA_DIR=/app/data
PHOTOS_DIR=/app/photos
```
## Wichtige Hinweise für Claude Code
1. **Ports immer 3002/8002 (Prod) oder 3099/8099 (Dev)** nie ändern
2. **npm install** (nicht npm ci) kein package-lock.json vorhanden
3. **SQLite safe_alters** neue Spalten immer via safe_alters Liste
4. **Pipeline-Prompts** haben slug-Prefix `pipeline_` nie als Einzelanalyse zeigen
5. **dayjs.week()** braucht Plugin stattdessen native JS ISO-Wochenberechnung
6. **useNavigate()** nur in React-Komponenten, nicht in Helper-Functions
7. **api.js nutzen** für alle API-Calls injiziert Token automatisch
8. **bcrypt** für alle neuen Passwort-Operationen verwenden
9. **session=Depends(require_auth)** als separater Parameter nie in Header() einbetten
## Code-Style
- React: Functional Components, Hooks
- CSS: Inline-Styles + globale CSS-Variablen (var(--accent), var(--text1), etc.)
- API-Calls: immer über `api.js` (injiziert Token automatisch)
- Kein TypeScript (bewusst, für Einfachheit)
- Python: keine Type-Hints Pflicht, aber bei neuen Funktionen erwünscht
## Design-System
### Farben (CSS-Variablen)
```css
--accent: #1D9E75 /* Jinkendo Grün Buttons, Links, Akzente */
--accent-dark: #085041 /* Dunkelgrün Icon-Hintergrund, Header */
--accent-light: #E1F5EE /* Hellgrün Hintergründe, Badges */
--bg: /* Seitenhintergrund (hell/dunkel auto) */
--surface: /* Card-Hintergrund */
--surface2: /* Sekundäre Fläche */
--border: /* Rahmen */
--text1: /* Primärer Text */
--text2: /* Sekundärer Text */
--text3: /* Muted Text, Labels */
--danger: #D85A30 /* Fehler, Warnungen */
```
### CSS-Klassen
```css
.card /* Weißer Container, border-radius 12px, box-shadow */
.btn /* Basis-Button */
.btn-primary /* Grüner Button (#1D9E75) */
.btn-secondary /* Grauer Button */
.btn-full /* 100% Breite */
.form-input /* Eingabefeld, volle Breite */
.form-label /* Feldbezeichnung, klein, uppercase */
.form-row /* Label + Input + Unit nebeneinander */
.form-unit /* Einheit rechts (kg, cm, etc.) */
.section-gap /* margin-bottom zwischen Sektionen */
.spinner /* Ladekreis, animiert */
```
### Abstände & Größen
```
Seiten-Padding: 16px seitlich
Card-Padding: 16-20px
Border-Radius: 12px (Cards), 8px (Buttons/Inputs), 50% (Avatare)
Icon-Größe: 16-20px inline, 24px standalone
Font-Größe: 12px (Labels), 14px (Body), 16-18px (Subtitel), 20-24px (Titel)
Font-Weight: 400 (normal), 600 (semi-bold), 700 (bold)
Bottom-Padding: 80px (für Mobile-Navigation)
```
### Komponenten-Muster
**Titelzeile einer Seite:**
```jsx
<div style={{display:'flex',alignItems:'center',
justifyContent:'space-between',marginBottom:20}}>
<div style={{fontSize:20,fontWeight:700,color:'var(--text1)'}}>
Seitentitel
</div>
<button className="btn btn-primary">Aktion</button>
</div>
```
**Ladezustand:**
```jsx
if (loading) return (
<div style={{display:'flex',justifyContent:'center',padding:40}}>
<div className="spinner"/>
</div>
)
```
**Fehlerzustand:**
```jsx
if (error) return (
<div style={{color:'var(--danger)',padding:16,textAlign:'center'}}>
{error}
</div>
)
```
**Leerer Zustand:**
```jsx
{items.length === 0 && (
<div style={{textAlign:'center',padding:40,color:'var(--text3)'}}>
<div style={{fontSize:32,marginBottom:8}}>📭</div>
<div>Noch keine Einträge</div>
</div>
)}
```
**Metric Card:**
```jsx
<div className="card" style={{padding:16,textAlign:'center'}}>
<div style={{fontSize:12,color:'var(--text3)',marginBottom:4}}>LABEL</div>
<div style={{fontSize:24,fontWeight:700,color:'var(--accent)'}}>
{value}
</div>
<div style={{fontSize:12,color:'var(--text3)'}}>Einheit</div>
</div>
```
### Jinkendo Logo-System
```
Grundelement: Ensō-Kreis (offen, Lücke 4-5 Uhr)
Farbe Ensō: #1D9E75
Hintergrund: #085041 (dunkelgrün)
Kern-Symbol: #5DCAA5 (mintgrün)
Wortmarke: Jin(light) + ken(bold #1D9E75) + do(light)
```
### Verfügbare Custom Commands
```
/deploy → Commit + Push vorbereiten
/merge-to-prod → develop → main mergen
/test → Manuelle Tests durchführen
/new-feature → Neues Feature-Template
/ui-component → Neue Komponente erstellen
/ui-page → Neue Seite erstellen
/fix-bug → Bug analysieren und beheben
/add-endpoint → Neuen API-Endpoint hinzufügen
/db-add-column → Neue DB-Spalte hinzufügen
```