- Renamed references from "Dashboard-Lab-Widgets" to "Dashboard-Widgets" across documentation and codebase for consistency. - Removed the deprecated Dashboard-Lab page and integrated its functionality into the new Dashboard-Widgets layout. - Updated widget registration and configuration handling to reflect the new naming convention. - Adjusted documentation in `.claude/docs/technical/DASHBOARD_WIDGETS_AGENT_GUIDE.md` and other related files to ensure clarity on the updated structure. - Bumped application version to reflect these changes.
15 KiB
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.
Dokumentationsablage: siehe
DOCUMENTATION.md(gleicher Ordner) – fachlich/technisch/working/issues.
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.pyregistrieren:app.include_router(modul.router, prefix="/api") - Router-Datei-Name = Modul-Name in
version.pyMODULE_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.
# ✅ 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
# ✅ 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
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
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)
{
"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:
- Versions-Bump in
backend/version.py(APP_VERSION + betroffenes MODULE_VERSION) - Versions-Bump in
frontend/src/version.js(APP_VERSION + betroffene PAGE_VERSION) - Changelog-Eintrag in
backend/version.pyCHANGELOG
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:
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
-- 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:
source VARCHAR(50) DEFAULT 'manual'
-- Werte u. a.: 'manual' | 'apple_health' | 'garmin' | 'withings' | 'csv'
Importe über den Universal CSV-Pfad setzen source = 'csv', sofern die Tabelle ein source-Feld hat; CHECK-Constraints und Migrationen müssen diesen Wert erlauben.
Agent-Pflicht bei neuen Import-Zielen oder Executor-Änderungen: .claude/docs/technical/UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md
Manuelle Einträge (source = 'manual') haben IMMER Vorrang bei Reimport:
-- 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
-- PostgreSQL Boolean (nicht SQLite 0/1):
WHERE active = true ✓
WHERE active = 1 ✗
4. Frontend-Regeln
4.1 Alle API-Calls über api.js
// ✅ 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
// ✅ Richtig:
style={{color: 'var(--accent)'}}
// ❌ Falsch:
style={{color: '#1D9E75'}}
4.4 Fehlerbehandlung in allen async Funktionen
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:
- Fachliche Spec:
.claude/docs/functional/MODUL_NAME.md - Technische Spec:
.claude/docs/technical/MODUL_NAME.md - 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
7. Prod-Schutz & Dev-Zugriff
7.1 Absoluter Prod-Schutz
Claude Code darf auf dem Prod-System (mitai.jinkendo.de) NIEMALS:
- Container neustarten (
docker restart mitai-*) - Schreibend in Container ausführen (
docker exec mitai-api ...) - Dateien direkt ändern (
/home/lars/docker/bodytrack/) - Prod-Datenbank schreiben (nur SELECT erlaubt)
Prod-Änderungen ausschließlich über:
git push origin develop → Gitea PR → Merge → deploy-prod.yml
7.2 Dev-System – voller Zugriff erlaubt
Claude Code darf auf dem Dev-System (dev.mitai.jinkendo.de):
- Container neustarten (
docker restart dev-mitai-*) - Logs lesen und filtern
- DB lesen und schreiben (für Tests)
- Container neu bauen
7.3 Test-Umgebung
- API-Tests: gegen http://dev.mitai.jinkendo.de
- Playwright-Tests: gegen https://dev.mitai.jinkendo.de
- Screenshots: in
screenshots/Ordner (in .gitignore) - Test-Credentials: in Umgebungsvariablen (TEST_EMAIL, TEST_PASSWORD)
- NIEMALS Test-Credentials in Code committen
7.4 Erkennungsmerkmale Prod vs. Dev
Prod-Container: mitai-api, mitai-ui, mitai-db-prod
Dev-Container: dev-mitai-api, dev-mitai-ui, dev-mitai-postgres
Prod-Ports: 8002 (Backend), 3002 (Frontend)
Dev-Ports: 8099 (Backend), 3099 (Frontend)
Prod-URL: mitai.jinkendo.de
Dev-URL: dev.mitai.jinkendo.de
8. CSV-Import vs. Data Layer (Issue #53)
8.1 Leitlinie: Wo Interpretation stattfindet
| Schicht | Erlaubt | Nicht Sinn der Schicht |
|---|---|---|
| Import (Ingest) | Zuordnung CSV→Speicherfeld, Typ-/Einheits-Konvertierung (type_conversions), Duplikat-/Constraint-Logik |
Fachliche Interpretation, Aggregation von „Bedeutung“, Metriken für Auswertung |
| Data Layer (Issue #53, Layer 1+) | Daten lesen, aufbereiten, ableiten, für Charts/KI/Prompts bereitstellen | — |
Verbindlich: Semantik und Auswertung nicht dauerhaft im Import verstecken; neue Features werden an dieser Grenze geprüft.
Detail & Zielbild (Multi-Layer, Single Source of Truth): docs/issues/issue-53-phase-0c-multi-layer-architecture.md
Umsetzung Schlaf-Import (Refactoring, Offen): Gitea #69
8.2 Ist-Einordnung Import-Pfade (Übergang)
Bis sukzessive auf das Zielbild umgestellt ist, gilt:
| Pfad | Einordnung |
|---|---|
Universal-CSV (csv_parser, routers/csv_import.py, Executor für u. a. Gewicht/Ernährung/Blutdruck/Aktivität/Vitals) |
Zielrichtung: Mapping + Typkonvertierung |
Apple-Schlaf-Aggregat (csv_parser/sleep_apple_import.py, import_mode: apple_sleep_aggregate) |
Legacy-Adapter (quellenspezifische Aufbereitung) – Austausch gegen mapping-nah + Layer 1 geplant |
Dedizierte Import-Endpoints (z. B. /api/activity/import-csv, Vitals Apple) |
Legacy/Parallel – neue Quellen bevorzugt über Universal-Pfad + Vorlagen |
Änderungen an Import-Pfaden: Legacy nur erweitern mit expliziter Issue-/Review-Begründung; kein neues „wir rechnen Auswertung beim Insert“ ohne Data-Layer-Bezug.
9. Test-Regeln
9.1 Tests schreiben ist Pflicht
Jedes neue Feature bekommt mindestens einen Playwright-Test in
tests/dev-smoke-test.spec.js.
9.2 Reihenfolge: Test vor Commit
Implementieren → Tests schreiben → Tests grün → Committen
NIEMALS: Implementieren → Committen → Tests später
9.3 Claude Code schreibt Tests selbst
Nach jeder Implementierung:
- Passende Tests in dev-smoke-test.spec.js ergänzen
npx playwright testausführen- Fehler korrigieren bis alle Tests grün
- Erst dann committen
9.4 Test-Kategorien
// UI-Test (Playwright)
test('FEATURE: Beschreibung', async ({ page }) => { ... })
// API-Test (Playwright request)
test('API: Endpoint', async ({ request }) => { ... })
9.5 Screenshots bei Fehlern
Fehlgeschlagene Tests erzeugen automatisch Screenshots in:
test-results/TESTNAME/test-failed-1.png
→ Immer ansehen bevor Code geändert wird
9.6 Prod nie testen
Tests laufen IMMER gegen dev.mitai.jinkendo.de NIEMALS gegen mitai.jinkendo.de
10. Dashboard-Widgets und Feature-System
Kontext: Dashboard-Widgets (backend/widget_catalog.py, API unter /api/app/...) und das Subscription-/Feature-Modell (features, tier_limits, check_feature_access in backend/auth.py) sind getrennte Schichten, müssen aber bei tariffrelevanten Widgets verknüpft werden.
Bindend:
- Keine fest codierten Tier-Namen für Widget-Rechte – Tiers und Limits kommen aus der DB.
- Komplexität (Module aus, Unter-Stufen, KI vs. Standard) liegt in der Feature-/Subscription-Logik, nicht verteilt in Widget-Komponenten.
- Nutzer-Konfigurator (Übersicht anpassen /
DashboardConfigurePage): Widgets ohne passende Berechtigung nicht anzeigen; alle erlaubten Widgets bleiben verfügbar. - Backend liefert die effektive Erlaubnis (z. B. über erweiterten Katalog oder Entitlements), und validiert beim Speichern des Layouts, dass keine unerlaubten Widget-IDs persistiert werden (Policy: ablehnen oder strippen – einheitlich halten).
- Daten/API: Zusätzlich zur UI-Filterung müssen die inhaltsliefernden Endpoints weiterhin über
check_feature_accessgeschützt sein (kein Leck über direkte API-Aufrufe).
Detail-Doku (Checklisten, Dateipfade): .claude/docs/technical/DASHBOARD_WIDGETS_AGENT_GUIDE.md § 0.