340 lines
9.0 KiB
Markdown
340 lines
9.0 KiB
Markdown
|
|
# Architektur-Regeln – Mitai Jinkendo
|
|||
|
|
|
|||
|
|
> **PFLICHTLEKTÜRE für Claude Code vor jeder Implementierung.**
|
|||
|
|
> Diese Regeln sind verbindlich und dürfen nicht ohne explizite
|
|||
|
|
> Genehmigung des Nutzers abgeändert werden.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. Router-Architektur
|
|||
|
|
|
|||
|
|
### 1.1 Ein Modul = Ein Router
|
|||
|
|
Jedes fachliche Modul hat genau eine Router-Datei in `backend/routers/`.
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
backend/routers/
|
|||
|
|
├── auth.py # Authentifizierung
|
|||
|
|
├── profiles.py # Nutzerprofile
|
|||
|
|
├── weight.py # Gewichts-Tracking
|
|||
|
|
├── sleep.py # Schlaf-Modul
|
|||
|
|
├── training_types.py # Trainingstypen + HF
|
|||
|
|
└── ... # je neues Modul = neue Datei
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Regeln:**
|
|||
|
|
- Kein Endpoint darf außerhalb seines thematischen Routers definiert werden
|
|||
|
|
- Neue Module immer als neue Router-Datei anlegen, nie in bestehende einfügen
|
|||
|
|
- Router in `main.py` registrieren: `app.include_router(modul.router, prefix="/api")`
|
|||
|
|
- Router-Datei-Name = Modul-Name in `version.py` MODULE_VERSIONS
|
|||
|
|
|
|||
|
|
### 1.2 API-First Prinzip
|
|||
|
|
Jede Funktion ist zuerst als API-Endpoint implementiert – die UI nutzt ausschließlich
|
|||
|
|
diese Endpoints über `api.js`. Keine Business-Logik im Frontend.
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# ✅ Richtig: Logik im Backend-Endpoint
|
|||
|
|
@router.get("/sleep/stats")
|
|||
|
|
def get_sleep_stats(session=Depends(require_auth)):
|
|||
|
|
# Berechnung hier
|
|||
|
|
return {"avg_duration": ..., "sleep_debt": ...}
|
|||
|
|
|
|||
|
|
# ❌ Falsch: Berechnung im Frontend
|
|||
|
|
const sleepDebt = entries.reduce((sum, e) => sum + (goal - e.duration), 0)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 1.3 Einheitliche Fehlerbehandlung
|
|||
|
|
```python
|
|||
|
|
# ✅ Immer dieses Format:
|
|||
|
|
raise HTTPException(status_code=404, detail="Eintrag nicht gefunden")
|
|||
|
|
# Response: {"detail": "Eintrag nicht gefunden"}
|
|||
|
|
|
|||
|
|
# ❌ Nie eigene Formate:
|
|||
|
|
return {"error": "not found"}
|
|||
|
|
return {"message": "Fehler", "success": False}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Versionskontrollsystem
|
|||
|
|
|
|||
|
|
### 2.1 Versionierungsschema
|
|||
|
|
**Semantic Versioning: `MAJOR.MINOR.PATCH`**
|
|||
|
|
|
|||
|
|
| Typ | Wann | Beispiel |
|
|||
|
|
|-----|------|---------|
|
|||
|
|
| MAJOR | Breaking Change, DB-Migration inkompatibel | 9.0.0 → 10.0.0 |
|
|||
|
|
| MINOR | Neues Feature, neues Modul | 9.2.0 → 9.3.0 |
|
|||
|
|
| PATCH | Bugfix, kleine Änderung, Refactor | 9.3.0 → 9.3.1 |
|
|||
|
|
|
|||
|
|
### 2.2 Versions-Dateien
|
|||
|
|
|
|||
|
|
**Backend: `backend/version.py`**
|
|||
|
|
```python
|
|||
|
|
APP_VERSION = "9.3.0"
|
|||
|
|
BUILD_DATE = "2026-03-22"
|
|||
|
|
|
|||
|
|
MODULE_VERSIONS = {
|
|||
|
|
"auth": "1.2.0",
|
|||
|
|
"profiles": "1.1.0",
|
|||
|
|
"weight": "1.0.3",
|
|||
|
|
"circumference": "1.0.1",
|
|||
|
|
"caliper": "1.0.1",
|
|||
|
|
"activity": "1.1.0",
|
|||
|
|
"nutrition": "1.0.2",
|
|||
|
|
"photos": "1.0.0",
|
|||
|
|
"insights": "1.3.0",
|
|||
|
|
"prompts": "1.1.0",
|
|||
|
|
"admin": "1.2.0",
|
|||
|
|
"stats": "1.0.1",
|
|||
|
|
"exportdata": "1.1.0",
|
|||
|
|
"importdata": "1.0.0",
|
|||
|
|
"membership": "2.1.0",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
CHANGELOG = [
|
|||
|
|
{
|
|||
|
|
"version": "9.3.0",
|
|||
|
|
"date": "2026-03-22",
|
|||
|
|
"changes": [
|
|||
|
|
"Feature: Sleep Module (sleep_log, JSONB-Segmente)",
|
|||
|
|
"Feature: Vitalwerte-Seite in Navigation",
|
|||
|
|
"Feature: Trainingstypen-Kategorisierung",
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"version": "9.2.1",
|
|||
|
|
"date": "2026-03-20",
|
|||
|
|
"changes": [
|
|||
|
|
"Fix: Feature-Enforcement Rollback",
|
|||
|
|
"Fix: Erholungsstatus-Gewichtung korrigiert",
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Frontend: `frontend/src/version.js`**
|
|||
|
|
```javascript
|
|||
|
|
export const APP_VERSION = "9.3.0"
|
|||
|
|
export const BUILD_DATE = "2026-03-22"
|
|||
|
|
|
|||
|
|
export const PAGE_VERSIONS = {
|
|||
|
|
Dashboard: "1.3.0",
|
|||
|
|
LoginScreen: "1.1.0",
|
|||
|
|
WeightPage: "1.0.3",
|
|||
|
|
ActivityPage: "1.2.0",
|
|||
|
|
NutritionPage: "1.1.0",
|
|||
|
|
AnalysisPage: "1.3.0",
|
|||
|
|
SettingsPage: "1.4.0",
|
|||
|
|
AdminPanel: "1.2.0",
|
|||
|
|
SubscriptionPage: "1.0.0",
|
|||
|
|
// Neue Seiten hier eintragen
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.3 Versions-Endpoint
|
|||
|
|
|
|||
|
|
**`GET /api/version`** – öffentlich (kein Auth erforderlich)
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"app_version": "9.3.0",
|
|||
|
|
"build_date": "2026-03-22",
|
|||
|
|
"backend_version": "9.3.0",
|
|||
|
|
"modules": {
|
|||
|
|
"auth": "1.2.0",
|
|||
|
|
"sleep": "1.0.0"
|
|||
|
|
},
|
|||
|
|
"db_schema_version": "20260322",
|
|||
|
|
"environment": "production"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Dieser Endpoint wird in `backend/routers/version.py` implementiert und liest
|
|||
|
|
direkt aus `version.py`.
|
|||
|
|
|
|||
|
|
### 2.4 Versions-Anzeige in der App
|
|||
|
|
|
|||
|
|
**Settings-Seite – Versions-Panel:**
|
|||
|
|
```
|
|||
|
|
System-Versionen
|
|||
|
|
─────────────────────────────────────
|
|||
|
|
App (gesamt) 9.3.0
|
|||
|
|
Backend 9.3.0 ✓ erreichbar
|
|||
|
|
Frontend 9.3.0 ✓ geladen
|
|||
|
|
DB-Schema 20260322
|
|||
|
|
Umgebung production
|
|||
|
|
─────────────────────────────────────
|
|||
|
|
Module
|
|||
|
|
auth 1.2.0
|
|||
|
|
sleep 1.0.0
|
|||
|
|
membership 2.1.0
|
|||
|
|
[alle Module...]
|
|||
|
|
─────────────────────────────────────
|
|||
|
|
[Changelog] [Cache leeren]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Frontend ruft beim Laden der Settings-Seite `/api/version` ab und vergleicht
|
|||
|
|
mit der eigenen `APP_VERSION` aus `version.js`. Bei Abweichung: Warnung anzeigen.
|
|||
|
|
|
|||
|
|
### 2.5 Pflicht-Regel: Versions-Bump bei jedem Commit
|
|||
|
|
|
|||
|
|
**Jede Code-Änderung erfordert:**
|
|||
|
|
1. Versions-Bump in `backend/version.py` (APP_VERSION + betroffenes MODULE_VERSION)
|
|||
|
|
2. Versions-Bump in `frontend/src/version.js` (APP_VERSION + betroffene PAGE_VERSION)
|
|||
|
|
3. Changelog-Eintrag in `backend/version.py` CHANGELOG
|
|||
|
|
|
|||
|
|
**Claude Code prüft das im `/deploy` Command automatisch.**
|
|||
|
|
|
|||
|
|
Kein Commit ohne Versions-Bump – keine Ausnahme.
|
|||
|
|
|
|||
|
|
### 2.6 DB-Schema-Version
|
|||
|
|
|
|||
|
|
Format: `YYYYMMDD` (Datum der letzten Migration)
|
|||
|
|
|
|||
|
|
Gespeichert in `backend/version.py`:
|
|||
|
|
```python
|
|||
|
|
DB_SCHEMA_VERSION = "20260322"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Bei jeder Schema-Änderung (ALTER TABLE, neue Tabelle) → DB_SCHEMA_VERSION aktualisieren.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Datenbankregeln
|
|||
|
|
|
|||
|
|
### 3.1 Pflichtfelder für neue Tabellen
|
|||
|
|
```sql
|
|||
|
|
-- Jede neue Tabelle braucht:
|
|||
|
|
id SERIAL PRIMARY KEY,
|
|||
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.2 Source-Tracking bei Import-Daten
|
|||
|
|
Tabellen die Daten aus externen Quellen empfangen brauchen:
|
|||
|
|
```sql
|
|||
|
|
source VARCHAR(50) DEFAULT 'manual'
|
|||
|
|
-- Werte: 'manual' | 'apple_health' | 'garmin' | 'withings'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Manuelle Einträge (`source = 'manual'`) haben IMMER Vorrang bei Reimport:
|
|||
|
|
```sql
|
|||
|
|
-- Reimport überschreibt nur nicht-manuelle Einträge:
|
|||
|
|
INSERT INTO sleep_log (...) ON CONFLICT (profile_id, date)
|
|||
|
|
DO UPDATE SET ... WHERE sleep_log.source != 'manual'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.3 Profile-ID Isolation
|
|||
|
|
Jede Tabelle mit Nutzerdaten hat `profile_id` als Foreign Key.
|
|||
|
|
Kein Endpoint gibt Daten eines anderen Profils zurück.
|
|||
|
|
Profile-ID kommt IMMER aus der Session, nie aus Request-Parametern.
|
|||
|
|
|
|||
|
|
### 3.4 Boolean-Werte
|
|||
|
|
```sql
|
|||
|
|
-- PostgreSQL Boolean (nicht SQLite 0/1):
|
|||
|
|
WHERE active = true ✓
|
|||
|
|
WHERE active = 1 ✗
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Frontend-Regeln
|
|||
|
|
|
|||
|
|
### 4.1 Alle API-Calls über api.js
|
|||
|
|
```javascript
|
|||
|
|
// ✅ Richtig:
|
|||
|
|
import { api } from '../utils/api'
|
|||
|
|
const data = await api.listSleep()
|
|||
|
|
|
|||
|
|
// ❌ Falsch:
|
|||
|
|
const r = await fetch('/api/sleep')
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 Neue Seite = Eintrag in PAGE_VERSIONS
|
|||
|
|
Jede neue Seite in `frontend/src/version.js` registrieren.
|
|||
|
|
|
|||
|
|
### 4.3 CSS-Variablen statt Hardcoded-Farben
|
|||
|
|
```javascript
|
|||
|
|
// ✅ Richtig:
|
|||
|
|
style={{color: 'var(--accent)'}}
|
|||
|
|
|
|||
|
|
// ❌ Falsch:
|
|||
|
|
style={{color: '#1D9E75'}}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.4 Fehlerbehandlung in allen async Funktionen
|
|||
|
|
```javascript
|
|||
|
|
try {
|
|||
|
|
const data = await api.meinEndpoint()
|
|||
|
|
setData(data)
|
|||
|
|
} catch(e) {
|
|||
|
|
setError(e.message)
|
|||
|
|
} finally {
|
|||
|
|
setLoading(false)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Git & Deployment-Regeln
|
|||
|
|
|
|||
|
|
### 5.1 Nie direkt auf main pushen
|
|||
|
|
Immer über Pull Request in Gitea: develop → main.
|
|||
|
|
develop Branch niemals löschen.
|
|||
|
|
|
|||
|
|
### 5.2 Commit-Message Format
|
|||
|
|
```
|
|||
|
|
feat: neues Feature oder Modul
|
|||
|
|
fix: Bugfix
|
|||
|
|
refactor: Umbau ohne Funktionsänderung
|
|||
|
|
docs: Dokumentation
|
|||
|
|
version: Versions-Bump
|
|||
|
|
ci: CI/CD Änderungen
|
|||
|
|
chore: Maintenance
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.3 Versions-Bump im Commit
|
|||
|
|
```
|
|||
|
|
feat: Sleep Module v1.0.0
|
|||
|
|
|
|||
|
|
- sleep_log Tabelle mit JSONB-Segmenten
|
|||
|
|
- Import aus Apple Health CSV
|
|||
|
|
- Korrelationen Schlaf <-> Ruhepuls
|
|||
|
|
|
|||
|
|
version: 9.3.0 (backend + frontend)
|
|||
|
|
module: sleep 1.0.0
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. Dokumentations-Regeln
|
|||
|
|
|
|||
|
|
### 6.1 Neue Module dokumentieren
|
|||
|
|
Bei jedem neuen Modul:
|
|||
|
|
1. Fachliche Spec: `.claude/docs/functional/MODUL_NAME.md`
|
|||
|
|
2. Technische Spec: `.claude/docs/technical/MODUL_NAME.md`
|
|||
|
|
3. Nach Fertigstellung: `.claude/library/` aktualisieren
|
|||
|
|
|
|||
|
|
### 6.2 CLAUDE.md aktuell halten
|
|||
|
|
Nach größeren Änderungen CLAUDE.md Versions-Tabelle aktualisieren.
|
|||
|
|
|
|||
|
|
### 6.3 Lessons Learned dokumentieren
|
|||
|
|
Jeder Rollback oder schwerer Bug → Eintrag in `.claude/rules/LESSONS_LEARNED.md`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Zusammenfassung: Checkliste vor jedem Commit
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
[ ] Versions-Bump in backend/version.py (APP_VERSION + MODULE)
|
|||
|
|
[ ] Versions-Bump in frontend/src/version.js (APP_VERSION + PAGE)
|
|||
|
|
[ ] Changelog-Eintrag in backend/version.py
|
|||
|
|
[ ] DB_SCHEMA_VERSION aktualisiert (wenn Schema geändert)
|
|||
|
|
[ ] Neues Modul in PAGE_VERSIONS / MODULE_VERSIONS eingetragen
|
|||
|
|
[ ] Auth auf alle neuen Endpoints (require_auth)
|
|||
|
|
[ ] Fehlerformat einheitlich (HTTPException mit detail)
|
|||
|
|
[ ] Neue Tabellen haben created_at + updated_at
|
|||
|
|
[ ] Import-Tabellen haben source-Feld
|
|||
|
|
[ ] api.js für alle Frontend API-Calls
|
|||
|
|
```
|