mitai-jinkendo/.claude/docs/architecture/BACKEND.md
Lars 7940dc7560 docs: Struktur .claude/docs versionieren, working/, Gitea-Index, Regeln
- .gitignore: .claude/docs, rules, commands tracken; settings.local weiter ignorieren
- DOCUMENTATION.md: verbindliche Ablage functional/technical/working/issues
- .claude/README.md: Agent-Einstieg; GITEA_ISSUES_INDEX aus MCP (Stand 2026-04-08)
- Arbeitspapiere von docs/ nach .claude/docs/working/ verschoben
- docs/MEMBERSHIP_SYSTEM.md als Stub; kanonisch technical/MEMBERSHIP_SYSTEM.md
- CLAUDE.md Pflichtlektüre und Links angepasst; docs/README.md vereinfacht

Made-with: Cursor
2026-04-08 13:01:49 +02:00

95 lines
3.3 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.

# Backend-Architektur
## Struktur
```
backend/
├── main.py # App-Setup + Router-Registration (~75 Zeilen)
├── db.py # PostgreSQL Connection Pool + get_cursor() Helper
├── auth.py # hash_pin · verify_pin · require_auth · require_admin
├── models.py # Alle Pydantic Models (LoginRequest, ProfileUpdate, etc.)
├── schema.sql # Vollständiges PostgreSQL-Schema
└── routers/
├── auth.py # Login, Logout, Password Reset, PIN (7 Endpoints)
├── profiles.py # Profile CRUD + Current User (7 Endpoints)
├── weight.py # Weight Tracking (5 Endpoints)
├── circumference.py # Body Measurements (4 Endpoints)
├── caliper.py # Skinfold Tracking (4 Endpoints)
├── activity.py # Workout Logging + CSV Import (6 Endpoints)
├── nutrition.py # Nutrition + FDDB Import (4 Endpoints)
├── photos.py # Progress Photos (3 Endpoints)
├── insights.py # AI Analysis + Pipeline (8 Endpoints)
├── prompts.py # AI Prompt Management (2 Endpoints)
├── admin.py # User Management (7 Endpoints)
├── stats.py # Dashboard Stats (1 Endpoint)
├── exportdata.py # CSV/JSON/ZIP Export (3 Endpoints)
└── importdata.py # ZIP Import (1 Endpoint)
```
## Router registrieren (main.py Pattern)
```python
from routers import auth, profiles, weight
app.include_router(auth.router, prefix="/api")
app.include_router(profiles.router, prefix="/api")
```
## Neuen Router anlegen
1. `backend/routers/mein_modul.py` erstellen
2. `router = APIRouter()` definieren
3. Endpoints mit `@router.get/post/put/delete` definieren
4. In `main.py` importieren und registrieren
5. Schema-Änderungen in `schema.sql` + Migration
## Datenbank-Zugriff
```python
# ✅ Immer so:
from db import get_db, get_cursor
with get_db() as conn:
cur = get_cursor(conn) # RealDictCursor gibt Dicts zurück
cur.execute("SELECT * FROM weight_log WHERE profile_id = %s", (pid,))
rows = cur.fetchall() # Liste von Dicts
# ❌ Nie so (SQLite-Syntax):
conn.execute("SELECT * FROM weight_log WHERE profile_id=?", (pid,))
```
## Auth-Pattern
```python
# Standard-Endpoint mit Auth:
@router.get("/mein-endpoint")
def mein_endpoint(session: dict = Depends(require_auth)):
pid = session['profile_id']
role = session['role']
# Admin-only:
@router.get("/admin-endpoint")
def admin_endpoint(session: dict = Depends(require_admin)):
pass
# ❌ NIEMALS so (session innerhalb Header eingebettet):
def endpoint(x: str = Header(default=None, session=Depends(require_auth))):
```
## PostgreSQL vs. SQLite Unterschiede
```python
# Platzhalter:
%s # PostgreSQL ✅
? # SQLite ❌
# Boolean:
WHERE active = true # PostgreSQL ✅
WHERE active = 1 # SQLite ❌
# Returning:
INSERT INTO ... RETURNING id # PostgreSQL ✅ (für neue IDs)
# JSON:
JSONB # PostgreSQL (für flexible Felder)
```
## DB-Schema ändern
1. `backend/schema.sql` anpassen
2. Migration schreiben (ALTER TABLE oder neues Skript)
3. Container neu bauen: `docker compose build --no-cache backend`
4. NIEMALS Spalten direkt löschen/umbenennen ohne Datenmigration