Jede Diagnose landet automatisch in households/{id}/plants/{id}/diagnoses;
das Pflanzen-Detail zeigt die Liste (Ampel-Icon, Kurzbefund, Datum),
Antippen öffnet das Ergebnis-Sheet mit Untersuchungsdatum, volle
Mitglieder können Einträge löschen. Rules: read/create für alle im
Haushalt (auch Sitter), delete nur member, update nie. Widget-Test
navigiert bis ins Sheet.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
13 KiB
Handoff: LeafItToMe (Pflanzenpflege-App)
Stand: 2026-07-23. 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.
Wo alles liegt
- Code:
~/Documents/Projekte/Planty(Ordner heißt noch Planty, Projekt heißt seit Umbenennungleafittome, App-Name „LeafItToMe", Bundle-ID-Platzhalterdev.leafittome.app) - Git-Remote: selbst gehostetes Forgejo
https://git.cshomelabs.work/cschlaefke/leafittome.git(HTTPS + Token im macOS-Schlüsselbund,git pushlä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 - 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, SecretsPLANTNET_API_KEY/ANTHROPIC_API_KEYim 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 inlib/features/auth/data/auth_repository.dart, Login-UI in.../presentation/login_screen.dart. Haushalts-Bootstrap (Profil + eigener Haushalt beim ersten Login) läuft reaktiv überhouseholdBootstrapProvider+BootstrapGate(Maßstab:householdIdim users-Doc).
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.mdSchritt 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 (
memberUidsist Quelle der Wahrheit,users.householdIdnur noch aktiver Zeiger),sendDailyReminderssammelt 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 nochnameändern), Haushalts-Wechsler im Drawer, Tages-Checkliste gruppiert Aufgaben aus allen Haushalten, FunctionsleaveHousehold/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/removeMemberwarfen 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:memberEntrySyncProviderträgt beim App-Start die eigene E-Mail in allen eigenen Haushalten nach, plus eine eng gefasste Rules-Ausnahme (jeder darf nur den eigenenmembers-Eintrag pflegen, Rollenwechsel bleibt gesperrt).
Offen / Nächstes
🟡 V3 Baustein 1 — Krankheits-Diagnose per Foto: implementiert, wartet auf Deploy + Gerätetest
2026-07-23 implementiert:
- Function
diagnosePlant(functions/src/index.ts): Foto (+ optionale Art alsspeciesHint) → Claude beurteilt Gesundheitszustand → JSON{healthy, summary, details, treatment, prevention}auf Deutsch. Nutzt den bestehendenaskClaude-Helper (Modellclaude-sonnet-5); dessenmax_tokensvon 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,
tsckompiliert.
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).
Feinschliff deployt und bestätigt („sieht sehr gut aus", 2026-07-23).
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.
Noch zu tun (Nutzer):
- Rules-Deploy (neue diagnoses-Regeln; ohne sie schlägt das Speichern der Historie still fehl):
firebase deploy --only firestore --project leaf-it-to-me-app - App neu bauen, Untersuchung durchführen → Eintrag erscheint in „Untersuchungen", antippen zeigt den vollen Text, Löschen fragt nach.
Danach V3 weiter: Stellplatz-Bewertung (Zwei-Ebenen-Konzept), Umtopf-Erinnerungen.
🟡 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:
- 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). - Die eigentliche Falle: Die Push-Registrierung (
_saveToken,set(..., merge: true)) hatte dasusers-Dokument beim ersten Apple-Login längst angelegt (fcmTokens/timezone, aber ohnehouseholdId). 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 keinhouseholdIdim users-Doc". Maßstab ist überallhouseholdId, 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, inapp.darteingehä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;signInWithAppleruft ihn nicht mehr selbst auf. Selbstheilend für bereits kaputte Accounts.- Speicher-Fehler in
plant_form_screenzeigen 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 (
signInWithApplevia eingebautemAppleAuthProvider, „oder"-Trenner + Button im Login, iOS-Entitlementcom.apple.developer.applesignin, l10n-Strings, Dokufirebase-einrichtung.mdSchritt 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)
- V3: Krankheits-Diagnose per Foto, Stellplatz-Bewertung (Standort-Analyse pro Stellplatz + Eignungs-Sterne pro Pflanze — Zwei-Ebenen-Konzept siehe Memory), Umtopf-Erinnerungen.
- Backlog: Button „KI-Zweitmeinung" bei unbefriedigendem PlantNet-Ergebnis; Push-Anzeige auch bei App im Vordergrund; App Check vor App-Store-Release (
firebase-einrichtung.mdSchritt 9); Englisch (app_en.arb).
Stolperfallen (teuer erkauft, nicht erneut zahlen)
firebase functions:loghinkt 15–20 Minuten hinterher — „keine Läufe" heißt meist nur Log-Verzögerung. Scheduler-Status im Cloud-Scheduler-Console prüfen lassen.- Android zeigt FCM-Pushes nur bei App im Hintergrund.
flutter_timezone≥5 liefertTimezoneInfo-Objekt →.identifierverwenden (Objekt crasht Firestore-Writes still).- 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.actAsscheitern → wenige Minuten warten, erneut deployen. - Analyzer:
build/undios/build/sind inanalysis_options.yamlausgeschlossen (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 beipub getmit iOS 13 erzeugt; erstflutter build ios/flutter runhebt es auf das Projekt-Target (15.0) an. Nachflutter cleanoder beim Bauen direkt aus Xcode daher einmalflutter build ios --config-onlyausführen. - 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 viafirebase_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), dannflutter gen-l10n - Deploy:
firebase deploy --only functions|firestore|storage --project leaf-it-to-me-app; nach jedem Arbeitsstand committen +git push
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