Docker & Deployment: - docker-compose.yml (Prod: Port 3003/8003) - docker-compose.dev-env.yml (Dev: Port 3098/8098) - Backend Dockerfile (Python 3.12-slim) - Frontend Dockerfile (Node 20 + Nginx) - Gitea Actions (deploy-dev.yml, deploy-prod.yml) Frontend: - React 18 + Vite setup - package.json, vite.config.js, index.html - App.jsx (minimal with version display) - api.js (complete API client) - app.css + AuthContext from Mitai - main.jsx entry point Backend Migrations: - 001_auth_membership.sql (Auth + Features + Tier Limits) - 002_organization.sql (Clubs, Divisions, Training Groups) - 003_catalogs.sql (Skills + Methods with sample data) Documentation: - .claude/rules/ (ARCHITECTURE, CODING_RULES, etc.) - SHINKAN_PROJECT_SETUP.md (technical setup guide) Server: - Directories created on Pi: /home/lars/docker/shinkan[-dev] - Gitea Runner configured and running Ready for first deployment to dev.shinkan.jinkendo.de version: 0.1.0 date: 2026-04-21
5.7 KiB
Lessons Learned
Fehler die gemacht wurden – damit sie nicht wiederholt werden.
1. Feature-Enforcement Rollback (20.03.2026)
Was: Membership-System Feature-Enforcement implementiert Problem: Brach Analyse-Verlauf, Export-Sichtbarkeit und Zähler Rollback: Commit 4fcde4a Lösung: Einfaches ai_enabled + ai_limit_day System aktiv
Regel: Feature-Enforcement nie ohne vollständige Test-Suite aktivieren. Zuerst Shadow-Mode (loggen aber nicht blockieren), dann schrittweise aktivieren.
2. session=Depends(require_auth) innerhalb Header()
Was: Automatisches Einfügen von Auth in bestehende Endpoints
Problem: session wurde innerhalb Header(default=None, session=...) eingebettet
Folge: FastAPI ignorierte Auth stillschweigend – Endpoint ungeschützt
Lösung: session immer als separater Parameter
# ❌ Was passiert ist:
def endpoint(x: str = Header(default=None, session=Depends(require_auth))):
# ✅ Korrekt:
def endpoint(x: str = Header(default=None), session: dict = Depends(require_auth)):
3. PostgreSQL Migration – apt-get Probleme
Was: Docker Build mit apt-get postgresql-client Problem: Build hing 30+ Minuten Lösung: Reine Python-Lösung mit psycopg2-binary, kein apt-get
4. SQLite → PostgreSQL Datenmigration
Probleme:
- Leere date-Strings (
'') → PostgreSQL wirft Fehler → zu NULL konvertieren - Boolean: SQLite
0/1→ PostgreSQLtrue/false ?Platzhalter →%s
5. dayjs.week() Plugin fehlt
Was: dayjs().week() ohne isoWeek-Plugin aufgerufen Problem: Weißer Screen auf Verlauf/Ernährung Lösung: Native ISO-Wochenberechnung (siehe FRONTEND.md)
6. Bun Crash bei langen Claude Code Sessions
Was: Claude Code CLI lief >30 Minuten Problem: Bun (JS Runtime) crashed mit "Illegal instruction" Lösung: Bei komplexen Tasks früher committen und neue Session starten
7. Docker Cache nach Dateiänderung
Was: main.py auf Pi kopiert, Container neu gestartet
Problem: Docker nutzte gecachten Layer – alte Datei im Container
Lösung: Immer --no-cache bei Änderungen am Code:
docker compose build --no-cache backend
8. Placeholder Registry Framework – Kritische Learnings (02.04.2026)
Was: Implementation von 14 Nutrition Placeholders mit neuem Registry Framework
8.1 OutputType.TEXT existiert nicht
Problem: OutputType.TEXT verursachte AttributeError
Richtig: OutputType.STRING für Text-Outputs
Verfügbar: NUMERIC, STRING, BOOLEAN, JSON, LIST, TEXT_SUMMARY
# ❌ Falsch:
output_type=OutputType.TEXT
# ✅ Richtig:
output_type=OutputType.STRING
8.2 Time Window "mixed" ist problematisch
Problem: time_window="mixed" unklar für Export und Consumers
Lösung: Dominante Zeitkomponente wählen, Rest als Kommentar
# ❌ Unklar:
time_window="mixed"
# ✅ Klar:
time_window="7d" # protein 7d avg; weight ist snapshot (secondary)
8.3 Units müssen präzise sein
Problem: Unpräzise Units führen zu Interpretationsproblemen
# ❌ Unpräzise:
unit="score"
unit="kcal"
# ✅ Präzise:
unit="score (0-100)"
unit="kcal/day"
8.4 Date Aggregation bei CSV-Imports
Problem: Mehrere Einträge pro Tag → falsche "Tage"-Zählung
Lösung: Immer GROUP BY date, SUM() für Tages-Aggregation
# ❌ Falsch (zählt Einträge):
SELECT protein_g FROM nutrition_log WHERE date >= ...
# ✅ Richtig (zählt Tage):
SELECT date, SUM(protein_g) as daily_protein
FROM nutrition_log
WHERE date >= ...
GROUP BY date
Betroffen: Alle Funktionen die "Tage" zählen oder daily averages berechnen
8.5 Evidence-Based = Nie Raten
Problem: CODE_DERIVED falsch gesetzt ohne Code-Inspektion
Lösung: Bei Unsicherheit UNRESOLVED oder TO_VERIFY nutzen
# Wenn unklar:
metadata.set_evidence("field", EvidenceType.UNRESOLVED) # ehrlich
# Nicht:
metadata.set_evidence("field", EvidenceType.CODE_DERIVED) # halluziniert
8.6 Known Limitations = Dokumentations-Gold
Problem: Inkonsistenzen/Bugs verschwiegen
Erfolg: Transparent dokumentiert in known_limitations
Beispiel:
known_limitations=(
"KRITISCHE INKONSISTENZ: Protein ist geglättet (7d average), "
"Gewicht ist single-point (latest). Anfällig für Gewichts-Outlier."
)
Regel: Probleme dokumentieren statt verstecken. User entscheidet über Fixes.
8.7 Formeln explizit dokumentieren
Problem: "Berechnet Score" zu vage, nicht reproduzierbar
Erfolg: Alle Formeln, Thresholds, TDEE-Modelle explizit dokumentiert
Beispiel:
known_limitations=(
"TDEE-MODELL: weight_kg × 32.5 (vereinfacht). "
"NICHT berücksichtigt: Aktivitätslevel, Alter, Geschlecht."
)
8.8 No-Change Requirement ist absolut
Problem: Versuchung, offensichtliche Bugs zu fixen
Regel: NUR dokumentieren, User entscheidet
Beispiel: protein_g_per_kg hat Zeitfenster-Inkonsistenz (7d protein / latest weight)
→ Dokumentiert in known_limitations, NICHT gefixed
8.9 Testing nach jedem Deploy
Problem: Fehler erst nach komplettem Cluster entdeckt
Erfolg: Testing nach jedem Part (A, B, C) → frühe Fehlerkennung
Workflow:
- Deploy Part A
- Test Export
- Werte verifizieren
- Erst dann Part B
8.10 .claude in .gitignore
Problem: Versuch, .claude/task/ Files zu committen
Lösung: Nur backend/ Code committen, .claude/ ist local docs
Zusammenfassung Nutrition Cluster:
- 14 Placeholders erfolgreich implementiert
- 2 Bugs gefunden und behoben (OutputType, Date Aggregation)
- 2 Metadaten-Inkonsistenzen korrigiert (time_window, unit)
- Alle kritischen Formeln dokumentiert
- Framework bewährt und skalierbar