Erganzt den Profil-Tab um eine Community-Profil-Karte (UI-Teil zum
Backend-Fundament 634e67c):
- Benutzername-Feld mit Hinweis auf den vergebenen Handle (Username#XXXX).
- Bio-Textarea (max 280 Zeichen) mit Zeichenzaehler.
- Sichtbarkeits-Checkbox (Privacy-by-Default: aus) mit Datenschutzhinweis,
dass Gewicht, Kalorien und Ziele immer privat bleiben.
- Eigener Submit, der setMyHandle (nur bei eingegebenem Username) und
updateMyCommunityProfile aufruft und myProfile invalidiert.
Typecheck gruen (db/api/admin), Admin-Tests 10/10.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Battle.net-Style Handle Username#XXXX als Basis fuer kommende
Community-Features (Stufe 2 der Roadmap). Diese Stufe: Schema, Migration,
Generator und API. Die UI im Profil-Tab folgt in einem eigenen Commit.
Schema (packages/db/src/schema/auth.ts):
- Neue Spalten an der user-Tabelle: username, discriminator, bio (alle
nullable), profileVisible (notNull, default false = Privacy-by-Default).
- uniqueIndex auf (username, discriminator); NULLs distinct, greift also
nur bei vollstaendigen Handles. Index user_username_idx auf username
fuer die Handle-Erstvergabe-Query.
- Migration 0019_community_profile, per drizzle-kit generate erzeugt,
driftfrei (zweiter generate: keine Aenderung), drizzle-kit check ok.
Noch nicht gegen die DB angewendet.
Generator (packages/api/src/lib/handle.ts):
- Discriminator aus verwechslungsarmem Alphabet, Kollisions-Retry.
- formatHandle, validateUsername. 17 node:test-Unit-Tests.
API (packages/api/src/trpc/routers/users.ts):
- myProfile um die Felder + abgeleitetes handle erweitert (Feld-Whitelist).
- setMyHandle: Discriminator stabil bei Erst-Vergabe, Kollisionspruefung
inkl. DB-unique-violation-Fallback (PG 23505).
- updateMyCommunityProfile: bio + Sichtbarkeit, strikt userId-gescoped.
Verifiziert: Typecheck gruen (db/api/admin), 62 API-Tests gruen,
drizzle-kit check ok. Datenmodell-Architekt abgenommen (Index-Auflage
erfuellt).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drei projektspezifische Begutachtungs-Skills analog zum
ernaehrungswissenschaftler:
- datenschutz-pruefer: DSGVO/Privacy für sensible Gesundheitsdaten
(userId-Scope, keine Leaks, Privacy-by-Default, Lösch-/Export-Pfade).
- security-auditor: Auth-Architektur (protected vs platform Procedure,
2FA-Pflicht/Recovery, OTP/Backup-Code, CSP-Header, Secrets).
- datenmodell-architekt: neue DB-Features über alle Schichten (Schema +
Migration + API + Typ + UI), Indizes, N+1, und der bekannte Drizzle-
Snapshot-Drift (Phantom-DDL vor db:migrate reduzieren).
Hilfreich besonders vor dem geplanten Profil-/Register-/OAuth-Feature.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nachbesserungen aus der fachlichen Begutachtung (Skill
ernaehrungswissenschaftler):
- Kalorien-Untergrenze von 800 auf 1.200 kcal angehoben (goalsInput und
upsertWeeklyCaloriePlan, neue Konstante MIN_CALORIE_GOAL). Im Ziele-Tab
Sicherheitswarnung bei einem Ziel unter 1.500 kcal.
- Defizit-Banner wird nur noch bei moderatem Defizit (10-25 % unter dem
Basis-Tagesziel) gefeiert und gegen baseDailyGoal statt inkl. Sportbonus
gerechnet. Bei einem Defizit über 25 % erscheint stattdessen ein sanfter
"iss genug"-Hinweis statt Lob.
- Wochenbudget-Verteilung: der am 1.200-Floor gekappte Rest wird iterativ
auf die übrigen Tage weiterverteilt, sodass das Wochenbudget erhalten
bleibt, solange es geht. Neue Funktion weeklyExtrasOverflow meldet den
unvermeidbaren Überschuss; die Wochenbudget-Seite weist ihn ehrlich aus
statt pauschal "bleibt gleich" zu versprechen.
- Dashboard-Makros: Kohlenhydrate und Fett als geschätzt (~) gekennzeichnet
inkl. erklärendem Hinweis; Protein bleibt real getrackt.
- 2 neue API-Tests (iterative Floor-Verteilung, weeklyExtrasOverflow).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pro-Tag-Mehrbedarf statt fester Tageswerte:
- DB: Spalte extraCalories in weekly_calorie_plans (Migration 0018).
- API: neuer Endpoint setWeeklyExtras nimmt die ganze Woche entgegen
und verteilt eingeplante Mehrkalorien serverseitig. Reine, getestete
Verteilungslogik distributeWeeklyExtras haelt das Wochenziel konstant
(Tage mit Blocker = Tagesziel + Extra; uebrige Tage anteilig reduziert,
Floor 1200). statsSummary liefert extraCalories pro Tag mit.
- 3 neue API-Tests (Verteilung konstant, Floor, Endpoint).
- Wochenbudget-UI: je Tag ein "+kcal"- und ein "Anlass"-Feld plus ein
einziger "kcal neu verteilen"-Button. Blocker-Tage werden hervorgehoben.
Das fehleranfaellige Einzel-Datumsformular entfaellt.
- Dashboard nimmt den verteilten Plan-Wert des Tages als Basis-Tagesziel
(z. B. 1.740 nach Ausgleich, 2.800 an einem Blocker-Tag) und zeigt einen
Hinweis. Behebt zugleich den Sync: Wochenbudget-Aenderungen invalidieren
jetzt alle statsSummary-Varianten, sodass das Dashboard sofort mitzieht.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Health-/Ernährungslogik überarbeitet:
- Fix: upsertProfile speichert fehlende Größe/Gewicht als null statt 0
(Round-Trip-Bug: gespeicherte 0 scheiterte beim erneuten Speichern an
z.number().positive()). Frontend clampt zudem mealsPerDay/cooksPerDay
auf die Zod-Grenzen. 3 neue API-Tests.
- Ziele-Bearbeitung vom Standalone /ziele in den Einstellungen-Tab
?tab=ziele gezogen; /ziele-Seite + Sidebar-Eintrag entfernt. Liest/
schreibt jetzt aus der DB (vorher las der Tab veraltetes localStorage).
- Wochenziel wird automatisch als Tagesziel × 7 berechnet (Feld entfällt).
- Sportbonus klar dargestellt: Tagesansicht addiert den heutigen Sport
aufs Budget (nur wenn sportAddsCalories aktiv) mit Bolt-Badge; Wochen-
Box mit Icon und Info "ganze Woche". Dashboard invalidiert alle
statsSummary-Varianten.
- Belohnende Banner bei Sport heute und bei Kaloriendefizit.
- Doku: rules.md-Verweis auf docs/projektreferenz.md korrigiert.
- Neuer Skill: ernaehrungswissenschaftler (fachliche Abnahme der
Health-Logik).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sichtbare Texte in einstellungen/page.tsx und settings-tabs.tsx von
ASCII-Ersatz (ae/oe/ue/ss) auf echte Umlaute (ä/ö/ü/ß) umgestellt:
Ernährung, Präferenzen, persönlich, Straße, Eiweiß, Kochvorgänge,
Passwörter, für, über, groß u. a. Tab-id-Slug "ernaehrung" bleibt
ASCII (URL-Parameter).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI-Pipeline (Forgejo Actions):
- .forgejo/workflows/ci.yml: lint + typecheck + test + admin build
- typecheck-Scripts in packages/api, packages/db, apps/admin ergaenzt
- ESLint FlatConfig (eslint-config-next 16) in apps/admin angelegt
- React-19-Hook-Findings im bestehenden Code als Warnings markiert
(set-state-in-effect, preserve-manual-memoization, no-unused-vars)
DB-Schema-Split:
- packages/db/src/schema/health.ts (636 Zeilen, Monolith) entfernt und auf
7 Domain-Module aufgeteilt: profiles, foods, stores, recipes, tracking,
shopping, community. index.ts re-exportiert alles.
API-Refactoring:
- 2FA-Middleware: 2 DB-Queries pro Admin-Call sind jetzt lazy + per-Request
gecached. Bei tRPC-Batch-Requests mit mehreren protected Procedures wird
der 2FA-State nur einmal geladen (siehe context.ts getTwoFactorState).
- any-Typen in trpc/init.ts und trpc/routers/health.ts entfernt; Drizzle
inferiert Closure-Typen automatisch.
- packages/api/src/trpc/routers/health/_shared.ts: alle Helper-Funktionen
und Zod-Input-Schemas aus health.ts extrahiert. health.ts: 2419 -> 2061
Zeilen. Vorbereitung fuer Procedure-Split in Folge-Session.
Konfiguration:
- .env.example um alle in turbo.json deklarierten Env-Vars erweitert,
jeweils mit Kontext-Kommentar.
- turbo.json um real genutzte Env-Vars erweitert: NEXT_PUBLIC_HELP_URL,
ENABLE_DB_MIGRATIONS, ADMIN_INITIAL_PASSWORD, DEMO_RECIPE_OWNER_EMAIL.
- .gitignore: *.tsbuildinfo (TypeScript-Build-Cache).
- apps/admin/lib/hellth-data.test.ts: fehlendes Recipe.minutes Feld in Mocks.
Offene Folge-Sessions:
- Vollstaendiger Procedure-Split von routers/health.ts in Sub-Files
- Aufteilung von apps/admin/lib/hellth-data.ts (1149 Zeilen) in Domain-Module
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>