Doku: Handoff konsolidiert — Session-Stand 2026-07-23

Erledigte 🟡-Blöcke in den verifizierten Stand überführt (Auth komplett,
V3 Bausteine 1+2), offene Fäden gebündelt (Gerätetests, Stellplatz-
Bewertung mit Konzeptfragen), Session-Erkenntnisse zu den Stolperfallen
(Berechtigungsfilter/Deploys via Nutzer, Riverpod-3-Pausierung,
users-Doc vs. householdId, Anführungszeichen, Bash-cwd).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cschlaefke 2026-07-23 23:49:19 +02:00
parent 81d990dd7e
commit a02509c384

View file

@ -1,106 +1,74 @@
# Handoff: LeafItToMe (Pflanzenpflege-App)
Stand: 2026-07-23. Sprache mit dem Nutzer (Chris): **Deutsch**.
Stand: 2026-07-23 (Session-Ende). Sprache mit dem Nutzer (Chris): **Deutsch**.
## Projekt in einem Satz
Private Flutter-App (iOS+Android) zur Pflanzenpflege für Haushalt + Pflanzen-Sitter: Foto-Erkennung (PlantNet + Claude), Gieß-/Düngeplan mit Tages-Checkliste, tägliche Sammel-Push, Haushalt-Teilen per Einladungscode mit Rollen.
Private Flutter-App (iOS+Android) zur Pflanzenpflege für Haushalt + Pflanzen-Sitter: Foto-Erkennung (PlantNet + Claude), Gieß-/Dünge-/Umtopfplan mit Tages-Checkliste, tägliche Sammel-Push, Krankheits-Diagnose per Foto mit Historie, Haushalt-Teilen per Einladungscode mit Rollen.
## Wo alles liegt
- **Code:** `~/Documents/Projekte/Planty` (Ordner heißt noch Planty, Projekt heißt seit Umbenennung `leafittome`, App-Name „LeafItToMe", Bundle-ID-Platzhalter `dev.leafittome.app`)
- **Git-Remote:** selbst gehostetes Forgejo `https://git.cshomelabs.work/cschlaefke/leafittome.git` (HTTPS + Token im macOS-Schlüsselbund, `git push` läuft ohne Abfrage)
- **Doku (im Repo, deutsch, aktuell halten!):** `README.md`, `docs/architektur.md`, `docs/firebase-einrichtung.md` (Schritt-für-Schritt-Historie aller Backend-Einrichtungen), `docs/git-forgejo.md`
- **Doku (im Repo, deutsch, aktuell halten!):** `README.md`, `docs/architektur.md` (inkl. Kernentscheidungen: berechnete Aufgaben, reaktiver Haushalts-Bootstrap, Umtopfen als Opt-in-Monatsintervall), `docs/firebase-einrichtung.md` (Schritt-für-Schritt-Historie aller Backend-Einrichtungen, zuletzt Schritt 8 Google-Login), `docs/git-forgejo.md`
- **Claude-Memory:** Projektplan, Nutzerprofil und Backlog liegen im persistenten Memory-Verzeichnis dieser Claude-Code-Installation (werden automatisch geladen)
- **Firebase-Projekt:** `leaf-it-to-me-app` (Blaze aktiv, Budget-Alarm eingerichtet; Firebase CLI ist eingeloggt)
- **Functions:** `functions/` (TypeScript, Node 22, Region europe-west3): `identifyPlant` (PlantNet + Claude, Secrets `PLANTNET_API_KEY`/`ANTHROPIC_API_KEY` im Secret Manager), `diagnosePlant` (V3: Krankheits-Diagnose per Foto, Claude Vision), `sendDailyReminders` (alle 15 Min, sammelt über alle Haushalte eines Nutzers), `joinHousehold` (Einladungs-Einlösung), `leaveHousehold` (Haushalt verlassen), `removeMember` (Mitglied entfernen, nur Besitzer)
- **Auth:** E-Mail/Passwort + **Anmelden mit Apple** (iOS nativ, Android Web-Flow über Firebase-Handler) + **Anmelden mit Google** (beide Plattformen Web-Flow, eingebauter `GoogleAuthProvider`) — Code in `lib/features/auth/data/auth_repository.dart`, Login-UI in `.../presentation/login_screen.dart`. Haushalts-Bootstrap (Profil + eigener Haushalt beim ersten Login) läuft **reaktiv** über `householdBootstrapProvider` + `BootstrapGate` (Maßstab: `householdId` im users-Doc).
- **Functions:** `functions/` (TypeScript, Node 22, Region europe-west3): `identifyPlant` (PlantNet + Claude, Secrets `PLANTNET_API_KEY`/`ANTHROPIC_API_KEY` im Secret Manager), `diagnosePlant` (V3: Krankheits-Diagnose per Foto, Claude Vision, Modell `claude-sonnet-5`), `sendDailyReminders` (alle 15 Min, sammelt Gießen/Düngen/Umtopfen über alle Haushalte eines Nutzers), `joinHousehold`, `leaveHousehold`, `removeMember`
- **Auth:** E-Mail/Passwort + **Apple** (iOS nativ, Android Web-Flow) + **Google** (beide Plattformen Web-Flow, eingebauter `GoogleAuthProvider`) — Code in `lib/features/auth/`. Haushalts-Bootstrap läuft **reaktiv** über `householdBootstrapProvider` + `BootstrapGate` (Maßstab: `householdId` im users-Doc, NICHT Doc-Existenz — die Push-Registrierung legt das users-Doc nebenbei an!). Details der Entscheidung in `docs/architektur.md`.
## Verifizierter Stand
- **V1 komplett** und auf Android + iOS Ende-zu-Ende getestet: Foto → Erkennung → vorbefülltes Profil; Tages-Checkliste; Sammel-Push kam im regulären Scheduler-Lauf auf dem Sperrbildschirm an. **iOS-Push seit 2026-07-20 eingerichtet und laufend** (Apple Developer Account freigeschaltet, APNs-Schlüssel in Firebase, Push-/Background-Capability in Xcode — Details + Stolperfalle „Personal Team" in `docs/firebase-einrichtung.md` Schritt 6).
- **V2 implementiert, deployt und vom Nutzer erfolgreich getestet** (Einladungscodes member/sitter, `joinHousehold`-Function, Rules-Enforcement für Sitter, „bestätigt von"-Anzeige).
- **V2.1 Multi-Haushalt implementiert und getestet**: Nutzer bleiben Mitglied aller Haushalte (`memberUids` ist Quelle der Wahrheit, `users.householdId` nur noch aktiver Zeiger), `sendDailyReminders` sammelt Aufgaben aus allen Haushalten.
- **V2.2 implementiert, deployt und vom Nutzer vollständig getestet und bestätigt**: Besitzer-Konzept (`ownerUid`, Alt-Haushalte: memberUids[0]), Besitzer-Anzeige, Haushalt umbenennen (Rules: Clients dürfen nur noch `name` ändern), Haushalts-Wechsler im Drawer, Tages-Checkliste gruppiert Aufgaben aus allen Haushalten, Functions `leaveHousehold`/`removeMember` (biegen den aktiven Zeiger des Betroffenen um, legen notfalls frischen Haushalt an). Zwei Nachbesserungen aus dem Live-Test, beide behoben und bestätigt:
- `leaveHousehold`/`removeMember` warfen zunächst HTTP 401 — fehlende Cloud-Run-Invoker-Berechtigung bei frisch angelegten Gen-2-Functions (kein Auth-Bug im Code); Fix war ein gezielter Neu-Deploy dieser beiden Functions.
- Besitzer-Anzeige blieb bei Alt-Haushalten aus der V1-Zeit leer (kein `members`-Eintrag für den Ersteller, die Map kam erst mit V2). Fix: `memberEntrySyncProvider` trägt beim App-Start die eigene E-Mail in allen eigenen Haushalten nach, plus eine eng gefasste Rules-Ausnahme (jeder darf nur den eigenen `members`-Eintrag pflegen, Rollenwechsel bleibt gesperrt).
- **V1 komplett** (Foto → Erkennung → Profil; Checkliste; Sammel-Push), auf Android + iOS Ende-zu-Ende getestet. iOS-Push seit 2026-07-20 eingerichtet und laufend (`firebase-einrichtung.md` Schritt 6).
- **V2/V2.1/V2.2 komplett getestet und bestätigt:** Einladungscodes member/sitter, Multi-Haushalt (`memberUids` = Quelle der Wahrheit, `users.householdId` = aktiver Zeiger), Besitzer-Konzept, Umbenennen, Haushalts-Wechsler, `leaveHousehold`/`removeMember`.
- **Apple-Login: implementiert, Bug behoben, vom Nutzer bestätigt** (2026-07-23). Der Bug (neuer Apple-Account konnte nichts speichern) hatte zwei Schichten: Bootstrap hing am Login-Aufruf und wurde vom Router-Redirect überholt; UND die Push-Registrierung hatte das users-Doc ohne `householdId` vorab angelegt, weshalb ein Existenz-Check nicht reichte. Fix: reaktiver Bootstrap + `householdId`-Maßstab + merge-Writes; selbstheilend für kaputte Accounts. Zusätzlich beseitigt: Riverpod-3-Warnung „markNeedsBuild during build" (BootstrapGate als Stack-Overlay statt Baum-Austausch + `checklistWarmupProvider` in `app.dart` gegen das Pausieren unbeobachteter Provider).
- **Google-Login: implementiert und deployt** (2026-07-23, `firebase-einrichtung.md` Schritt 8; Debug-SHA-1/SHA-256 per `firebase apps:android:sha:create` hinterlegt — der SHA-Konsolen-Hinweis betrifft nur den nativen Flow und ist für unseren Browser-Flow irrelevant). Konsolen-Schalter vom Nutzer aktiviert; expliziter Gerätetest nicht rückgemeldet.
- **V3 Baustein 1 — Krankheits-Diagnose per Foto: komplett, deployt, vom Nutzer bestätigt** („sieht richtig gut aus"). Function `diagnosePlant` + „Pflanze untersuchen" im Pflanzen-Detail (Kamera/Galerie → Ergebnis-Sheet mit Ampel-Icon, Behandlung, Vorbeugung, KI-Disclaimer; `diagnosis_sheet.dart` gemeinsam genutzt). Nachbesserungen aus Live-Tests, alle bestätigt: Art-Angabe ist unbestätigter Hinweis (`matchesSpecies=false` → Warnkasten „Foto zeigt andere Pflanze"), kein HTML/Markdown im Text, konsequentes Duzen. **Untersuchungshistorie** unter `households/{id}/plants/{id}/diagnoses` (Rules: read/create alle im Haushalt, delete nur member, update nie), auf eigener Seite `/plants/:id/diagnoses`; Button „Frühere Untersuchungen" im Detail ist bei leerer Historie deaktiviert.
- **V3 Baustein 2 — Umtopf-Erinnerungen: implementiert und deployt** (2026-07-23, Commit `81d990d`). Dritter Aufgabentyp `repotting`, als Einziger opt-in (`repottingIntervalMonths` optional) und in Kalender-Monaten (31. → Monatsletzter; Logik gespiegelt in `due_tasks_provider` und `reminders.ts`). Formular mit Intervall-Feld + „Zuletzt umgetopft"-Datum, Checkliste + Push („Umtopfen: …"), Sitter dürfen bestätigen. Rules + `sendDailyReminders` sind deployt. **Gerätetest steht aus.**
- Testabdeckung: 13 Widget-Tests grün (u. a. Bootstrap-Heilung, Untersuchungshistorie bis ins Sheet, Umtopf-Flow Ende-zu-Ende), Analyzer sauber, `tsc` kompiliert.
## Offen / Nächstes
### 🟡 V3 Baustein 1 — Krankheits-Diagnose per Foto: implementiert, wartet auf Deploy + Gerätetest
### 1. Ausstehende Gerätetests (Nutzer, bei Rückmeldung ggf. nachbessern)
**2026-07-23 implementiert:**
- **Function `diagnosePlant`** (`functions/src/index.ts`): Foto (+ optionale Art als `speciesHint`) → Claude beurteilt Gesundheitszustand → JSON `{healthy, summary, details, treatment, prevention}` auf Deutsch. Nutzt den bestehenden `askClaude`-Helper (Modell `claude-sonnet-5`); dessen `max_tokens` von 1024 auf 2048 erhöht (adaptives Denken zählt mit ins Limit).
- **App:** `PlantDiagnosisService` (`lib/features/plants/data/plant_diagnosis_service.dart`, lazy Functions-Getter wie beim Household-Repo) + „Pflanze untersuchen"-Sektion im Pflanzen-Detail (`_DiagnosisSection`): Kamera/Galerie-Sheet → Spinner im Button → Ergebnis als scrollbares Bottom-Sheet (Befund mit Ampel-Icon, „Was du tun kannst", „So beugst du vor", KI-Disclaimer). Auch Sitter dürfen den Check nutzen (rein lesend). Fehler der Function (z. B. „keine Pflanze erkannt") werden als Snackbar durchgereicht.
- Analyzer + alle 10 Tests grün, `tsc` kompiliert.
- **Umtopf-Flow:** Pflanze bearbeiten → Intervall 12 Monate + „Zuletzt umgetopft" vor >1 Jahr → Aufgabe „… umtopfen" in Checkliste → Erledigt; Push-Text „Umtopfen: …" beim nächsten regulären Slot.
- **Historie-Seite:** Button → Liste → Eintrag → Sheet; Löschen mit Rückfrage.
- **Google-Login** auf iPhone und Android (erster Login eines Google-Kontos muss kurz „Dein Haushalt wird eingerichtet …" zeigen — der reaktive Bootstrap deckt Google automatisch ab).
**Stand nach erstem Gerätetest (2026-07-23):** Deploy erfolgreich, Grundfunktion vom Nutzer bestätigt. Drei Nachbesserungen aus dem Test umgesetzt (Commit `b665bae`): (1) `speciesHint` ist jetzt eine unbestätigte Angabe — Claude prüft selbst, welche Pflanze zu sehen ist, beurteilt bei Abweichung die Pflanze im Bild und meldet `matchesSpecies=false`, worauf die App einen Warnhinweis im Ergebnis-Sheet zeigt; (2) Prompt verbietet HTML/Markdown (Nutzer hatte ein `</br>` im Text); (3) durchgängiges Duzen vorgeschrieben (war gemischt).
### 2. V3 Baustein 3 — Stellplatz-Bewertung (letzter Roadmap-Punkt)
**Feinschliff deployt und bestätigt** („sieht sehr gut aus", 2026-07-23).
Zwei-Ebenen-Konzept laut Roadmap: Standort-Analyse pro Stellplatz + Eignungs-Sterne pro Pflanze. **Konzeptlastig — VOR der Implementierung mit dem Nutzer abstimmen.** Bereits angeteaserte offene Fragen: Woher kommen die Standort-Daten (Stellplatz-Foto, Fragen zu Himmelsrichtung/Fensternähe, beides)? Sterne automatisch für alle Pflanzen des Stellplatzes oder auf Abruf (Kostenaspekt: Nutzer zahlt eigenen Anthropic-Key)?
**Erweiterung Untersuchungshistorie (2026-07-23):** Jede Diagnose wird automatisch unter `households/{id}/plants/{id}/diagnoses` gespeichert (healthy, matchesSpecies, Texte, `createdAt` Server-Timestamp). Im Pflanzen-Detail unter dem Untersuchen-Button: Liste „Untersuchungen" (neueste zuerst, Ampel-Icon + Kurzbefund + Datum), Tipp öffnet dasselbe Ergebnis-Sheet inkl. „Untersucht am …". Volle Mitglieder können Einträge löschen (Bestätigungsdialog); Sitter dürfen speichern/lesen, Einträge sind nachträglich unveränderbar (Rules). Neuer Widget-Test navigiert bis ins Sheet — alle 11 Tests grün.
### 3. Backlog
Rules deployt (2026-07-23). **Auf Nutzerwunsch ausgelagert:** Die Historie liegt jetzt auf einer eigenen Seite (`/plants/:id/diagnoses`, `PlantDiagnosesScreen`) statt inline im Detail; im Detail führt der Button „Frühere Untersuchungen" dorthin (deaktiviert/ausgegraut, solange keine Untersuchungen existieren). Das Ergebnis-Sheet ist in `diagnosis_sheet.dart` ausgelagert und wird von Detail (frische Untersuchung) und Historie-Seite gemeinsam genutzt. 12 Tests grün (neu: Button-deaktiviert-Test).
**Noch zu tun (Nutzer):** App neu bauen und die ausgelagerte Historie-Seite einmal durchklicken (Button → Liste → Eintrag → Sheet; Löschen).
### 🟡 V3 Baustein 2 — Umtopf-Erinnerungen: implementiert, wartet auf Deploys + Gerätetest
**2026-07-23 implementiert:** Dritter Aufgabentyp `repotting` im Intervall-Modell — als Einziger **opt-in** (`repottingIntervalMonths` optional am Pflanzenprofil, leer = keine Erinnerung) und in Kalender-**Monaten**. Formular: „Umtopf-Intervall (Monate)" + Datums-Auswahl „Zuletzt umgetopft" (erscheint nur bei gesetztem Intervall; Intervall leeren verwirft auch das Datum). Detail zeigt die Umtopf-Zeile nur bei gesetztem Intervall. Checkliste/Sammel-Push enthalten Umtopf-Aufgaben (`reminders.ts` gespiegelt, „Umtopfen: …" im Push-Text); Bestätigen schreibt `lastRepotted`/`lastRepottedBy`; Sitter dürfen bestätigen (Rules-Allowlist erweitert). Monats-Arithmetik kürzt den 31. auf den Monatsletzten. Analyzer, 13 Tests (neu: Ende-zu-Ende-Test Checkliste→Bestätigen), tsc, Debug-APK grün.
**Noch zu tun (Nutzer, Deploys sind in der Session blockiert):**
1. `firebase deploy --only firestore,functions:sendDailyReminders --project leaf-it-to-me-app`
2. Gerätetest: Pflanze bearbeiten → Intervall z. B. 12 Monate + „Zuletzt umgetopft" vor >12 Monaten setzen → Aufgabe „… umtopfen" in der Checkliste; Erledigt-Bestätigung; Sammel-Push müsste „Umtopfen: …" enthalten (nächster regulärer Push-Slot).
**Danach V3 weiter:** Stellplatz-Bewertung (Zwei-Ebenen-Konzept — Konzept vor Implementierung mit Nutzer abstimmen).
### 🟡 Google-Login: implementiert, wartet auf Konsolen-Schalter + Gerätetest
**2026-07-23 implementiert** (`AuthRepository.signInWithGoogle` via eingebautem `GoogleAuthProvider`, Google-Button im Login mit gemeinsamem Provider-Handler `_signInWithProvider`, l10n-Strings, iOS-URL-Scheme/Encoded App ID in `Info.plist`, Doku `firebase-einrichtung.md` Schritt 8). Analyzer + alle 10 Tests grün. **Nutzer muss noch:** In der Firebase-Konsole *Authentication → Sign-in method → Google* aktivieren (Support-E-Mail wählen — der einzige Konfigurationsschritt), dann auf iPhone und Android testen; der erste Google-Login muss kurz den Einrichtungs-Bildschirm zeigen (reaktiver Bootstrap deckt Google automatisch ab).
### ✅ Apple-Login-Bug behoben und vom Nutzer bestätigt (2026-07-23)
**Der Bug in Kurzform:** Mit einem neuen Apple-Account schlug jedes Speichern fehl. Zwei Ursachen-Schichten:
1. Der Haushalts-Bootstrap hing an `signInWithApple` — der Router leitet aber schon bei „angemeldet" weiter; scheiterte der Bootstrap danach, blieb der Account dauerhaft ohne Haushalt (Rules lehnen dann korrekt jeden Write ab).
2. **Die eigentliche Falle:** Die Push-Registrierung (`_saveToken`, `set(..., merge: true)`) hatte das `users`-Dokument beim ersten Apple-Login längst angelegt (fcmTokens/timezone, aber ohne `householdId`). Eine Reparatur, die nur auf „users-Doc existiert" prüft, hielt den Account deshalb fälschlich für fertig.
**Der Fix (alles committet und gepusht):**
- `householdBootstrapProvider` (`lib/features/auth/data/household_bootstrap_provider.dart`): reaktiver Bootstrap — legt Profil + Haushalt an, sobald „angemeldet, aber **kein `householdId`** im users-Doc". Maßstab ist überall `householdId`, nie die Dokument-Existenz. Schreibt per **merge** (Push-Felder bleiben erhalten). Deckt alle Login-Wege ab (auch künftig Google).
- `BootstrapGate` (`lib/features/auth/presentation/bootstrap_gate.dart`, in `app.dart` eingehängt): legt bis dahin einen deckenden Warte-Bildschirm **über** die App (Stack, kein Austausch des App-Baums — ein Remount mitten im Provider-Update löste „markNeedsBuild during build" aus); Fehler werden mit „Erneut versuchen" sichtbar.
- `AuthRepository`: `ensureHouseholdBootstrap` öffentlich, idempotent, In-Flight-Schutz; `signInWithApple` ruft ihn nicht mehr selbst auf. Selbstheilend für bereits kaputte Accounts.
- Speicher-Fehler in `plant_form_screen` zeigen jetzt den Firebase-Fehlercode (plugin/code) statt einer Generik.
- **Vom Nutzer auf dem iPhone bestätigt:** Anmeldung + Pflanze anlegen funktionieren mit dem Apple-Account.
### Zuletzt erledigt
- **2026-07-23 (2):** Apple-Login-Bug diagnostiziert und in zwei Schritten behoben (reaktiver Bootstrap + householdId-Maßstab, siehe oben); Riverpod-„markNeedsBuild during build"-Warnung per Overlay-Gate beseitigt; Architektur-Doku um die Bootstrap-Entscheidung ergänzt.
- **2026-07-23 (1):** Apple-Login **implementiert und committet** (`signInWithApple` via eingebautem `AppleAuthProvider`, „oder"-Trenner + Button im Login, iOS-Entitlement `com.apple.developer.applesignin`, l10n-Strings, Doku `firebase-einrichtung.md` Schritt 7). Konfiguration vom Nutzer erledigt, Login funktioniert.
- **2026-07-20:** iOS-Push eingerichtet (Apple Developer Account freigeschaltet, APNs/Firebase/Xcode). V1 damit auch auf iOS vollständig.
### Weitere Kandidaten (nach dem Bug)
1. **V3:** Krankheits-Diagnose per Foto, Stellplatz-Bewertung (Standort-Analyse pro Stellplatz + Eignungs-Sterne pro Pflanze — Zwei-Ebenen-Konzept siehe Memory), Umtopf-Erinnerungen.
2. **Backlog:** Button „KI-Zweitmeinung" bei unbefriedigendem PlantNet-Ergebnis; Push-Anzeige auch bei App im Vordergrund; App Check vor App-Store-Release (`firebase-einrichtung.md` Schritt 9); Englisch (`app_en.arb`).
Button „KI-Zweitmeinung" bei unbefriedigendem PlantNet-Ergebnis; Push-Anzeige auch bei App im Vordergrund; App Check vor App-Store-Release (`firebase-einrichtung.md` Schritt 9); Englisch (`app_en.arb`); `firebase-functions`-Paket-Upgrade (Deploy-Warnung, mit Breaking Changes — bei Gelegenheit).
## Stolperfallen (teuer erkauft, nicht erneut zahlen)
- `firebase functions:log` hinkt **1520 Minuten** hinterher — „keine Läufe" heißt meist nur Log-Verzögerung. Scheduler-Status im Cloud-Scheduler-Console prüfen lassen.
- **Deploys und Produktions-Datenzugriffe blockiert der Auto-Mode-Berechtigungsfilter der Session.** Nicht dagegen anarbeiten: Kommando fertig vorbereiten und den Nutzer bitten, es per `! <kommando>` in der Eingabezeile auszuführen — macht er zuverlässig und prompt.
- Frisch **angelegte** Gen-2-Functions können beim ersten Aufruf HTTP 401 liefern (fehlende Cloud-Run-Invoker-Berechtigung) → dieselbe Function einfach erneut deployen. Updates bestehender Functions sind nicht betroffen.
- `firebase functions:log` hinkt **1520 Minuten** hinterher — „keine Läufe" heißt meist nur Log-Verzögerung. Scheduler-Status in der Cloud-Scheduler-Console prüfen lassen.
- Android zeigt FCM-Pushes **nur bei App im Hintergrund**.
- `flutter_timezone` ≥5 liefert `TimezoneInfo`-Objekt → `.identifier` verwenden (Objekt crasht Firestore-Writes still).
- Die **Push-Registrierung legt `users/{uid}` per merge selbst an** (fcmTokens/timezone). Jede Logik, die „Profil existiert" prüfen will, muss auf das Feld `householdId` schauen, nie auf die Dokument-Existenz.
- Riverpod 3 **pausiert Provider ohne aktive Zuhörer**; beim Einhängen von Screens mitten im Provider-Update gibt das „setState() or markNeedsBuild() called during build". Gegenmittel im Repo: Overlay statt Baum-Austausch (BootstrapGate) und dauerhaftes Warmhalten kritischer Ketten (`checklistWarmupProvider`).
- Storage-Rules mit `firestore.get()` brauchen die IAM-Rolle „Firebase Rules Firestore Service Agent" fürs Storage-Dienstkonto (wurde manuell erteilt).
- Erster Functions-Deploy in frischem Projekt kann mit 403 `iam.serviceaccounts.actAs` scheitern → wenige Minuten warten, erneut deployen.
- Analyzer: `build/` und `ios/build/` sind in `analysis_options.yaml` ausgeschlossen (SwiftPM legt dort Fremdcode ab).
- iOS-Fehler „requires minimum platform version 15.0 … but this target supports 13.0": Das von Flutter generierte SwiftPM-Paket (`ios/Flutter/ephemeral/…/Package.swift`) wird bei `pub get` mit iOS 13 erzeugt; erst `flutter build ios`/`flutter run` hebt es auf das Projekt-Target (15.0) an. Nach `flutter clean` oder beim Bauen direkt aus Xcode daher einmal `flutter build ios --config-only` ausführen.
- iOS-Fehler „requires minimum platform version 15.0 … but this target supports 13.0": nach `flutter clean` oder beim Bauen direkt aus Xcode einmal `flutter build ios --config-only` ausführen (SwiftPM-Paket wird bei `pub get` mit iOS 13 erzeugt).
- In `.arb`-Dateien UND in deutschen Texten innerhalb von TS-Strings (Function-Prompts!) **typografische Anführungszeichen „…“** verwenden — gerade `"` brechen das JSON bzw. den TS-String.
- Die Bash-Session wechselt das Arbeitsverzeichnis **nicht zurück**: nach `cd functions && npm run build` vor Flutter-Kommandos wieder explizit ins Projekt-Root.
- Nutzer wünscht zu jedem Backend-Baustein **begleitende deutsche Doku** in `docs/` (keine Firebase-Vorerfahrung).
## Arbeitsabläufe
- Prüfen: `flutter analyze && flutter test` (Tests mocken Firebase via `firebase_auth_mocks`/`fake_cloud_firestore`); Android-Verifikation: `flutter build apk --debug`
- Texte: nur in `lib/l10n/app_de.arb` (typografische Anführungszeichen „…“ verwenden, gerade `"` brechen das JSON), dann `flutter gen-l10n`
- Deploy: `firebase deploy --only functions|firestore|storage --project leaf-it-to-me-app`; nach jedem Arbeitsstand committen + `git push`
- Prüfen vor jedem Commit: `flutter analyze && flutter test` (Tests mocken Firebase via `firebase_auth_mocks`/`fake_cloud_firestore`); bei TS-Änderungen zusätzlich `npm run build` in `functions/`; Android-Verifikation: `flutter build apk --debug`
- Texte: nur in `lib/l10n/app_de.arb`, danach `flutter gen-l10n`
- Deploy (führt der Nutzer aus, s. Stolperfallen): `firebase deploy --only functions|firestore|storage --project leaf-it-to-me-app`
- Nach jedem Arbeitsstand: committen + `git push` + dieses Handoff aktualisieren (deutsche Commit-Messages, Muster siehe Git-Log)
- Der Nutzer testet auf echten Geräten gegen das Produktions-Firebase und meldet präzise Beobachtungen; gezielte Diagnosefragen (AskUserQuestion) haben sich bewährt
## Suggested skills
- `/verify` — nach nichttrivialen Änderungen den echten Flow treiben (Gerät/Simulator), nicht nur Tests
- `/code-review` — vor größeren Merges über den Diff laufen lassen
- `/run` — App starten/screenshotten, wenn Änderungen sichtbar geprüft werden sollen
- `claude-api` — vor Änderungen an den Claude-Aufrufen in `functions/src/` laden (Modell-IDs, Vision, Prompt-Konventionen)