leafittome/docs/firebase-einrichtung.md
cschlaefke 1b2c880c89 V2: Haushalt teilen – Einladungscodes, Mitglieder- und Sitter-Rolle, sichtbare Bestätigungen
- Einladen per einmaligem 6-stelligem Code (7 Tage gültig), wahlweise als Mitglied oder Pflanzen-Sitter
- Beitritt über Cloud Function joinHousehold (Transaktion, Admin-Rechte)
- Security Rules: Sitter dürfen an Pflanzen nur Bestätigungs-Felder ändern; invites nur erstellen, nie lesen
- Haushalts-Screen: Mitgliederliste mit Rollen, Einladen, Beitreten mit Wechsel-Warnung
- UI-Gating: Sitter sehen keine Anlegen-/Bearbeiten-/Löschen-Aktionen
- Bestätigungen speichern den Namen (lastWateredBy/lastFertilizedBy), Anzeige im Profil
- Tests: Members-Map im Seed, neuer Sitter-Test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 19:14:34 +02:00

11 KiB
Raw Blame History

Firebase-Einrichtung — Schritt für Schritt

Firebase ist Googles „Backend als Dienst": Es liefert uns Login (Auth), Datenbank mit Echtzeit-Sync (Firestore), Foto-Speicher (Storage), serverseitigen Code (Cloud Functions) und Push-Nachrichten (FCM) — ohne dass wir einen eigenen Server betreiben.

Stand: Schritt 13 erledigt, Blaze aktiv (18.07.2026). Der Code für Firestore (Pflanzen, Stellplätze, Haushalte) und Login (E-Mail+Passwort) ist eingebaut — offen ist Schritt 4 (Firestore-Datenbank anlegen + E-Mail-Login aktivieren, machst du in der Console) und danach das Rules-Deployment. Dieses Dokument wird mit jedem Baustein erweitert.

Was wofür? (Überblick)

Baustein Aufgabe in LeafItToMe
Authentication Login mit E-Mail+Passwort, Google und Apple
Cloud Firestore Datenbank: Haushalte, Pflanzen, Stellplätze, Bestätigungen — synchronisiert in Echtzeit auf alle Geräte des Haushalts
Storage Speichert die Pflanzen- und Stellplatz-Fotos
Cloud Functions Unser Server-Code: ruft PlantNet/Claude auf (damit API-Keys nie in der App stecken) und verschickt die täglichen Erinnerungen
Cloud Messaging (FCM) Stellt die Push-Nachrichten auf dem Sperrbildschirm zu

Schritt 1: Firebase-Projekt anlegen (machst du, ~10 Minuten)

  1. Öffne https://console.firebase.google.com und melde dich mit deinem Google-Konto an.
  2. „Projekt hinzufügen" → Name: leafittome → Google Analytics kannst du deaktivieren (brauchen wir nicht).
  3. Nach dem Anlegen bist du in der Projekt-Übersicht. Fertig für heute — Apps registrieren wir gemeinsam per CLI (Schritt 3).

Schritt 2: Auf den Blaze-Tarif umstellen (machst du, ~5 Minuten)

Cloud Functions (unser Server-Code) setzen den Blaze-Tarif („Pay as you go") voraus. Keine Sorge vor Kosten:

  • Die großzügigen Gratis-Kontingente bleiben auch im Blaze-Tarif bestehen (z. B. 2 Mio. Function-Aufrufe/Monat, 50.000 Firestore-Lesezugriffe/Tag). Bei ~5 Nutzern bleiben wir weit darunter → real ~0 €/Monat.
  • In der Console: Zahnrad → Nutzung und AbrechnungTarif ändern → Blaze → Kreditkarte hinterlegen.

Kostenschutz einrichten (wichtig, machen wir direkt mit):

  1. In der Google Cloud Console (https://console.cloud.google.com, gleiches Projekt) → Abrechnung → Budgets und Benachrichtigungen.
  2. Budget anlegen: z. B. 5 €/Monat, E-Mail-Alarm bei 50 %, 90 % und 100 %.
  3. So bekommst du eine Mail, lange bevor irgendetwas teuer wird.

Schritt 3: App mit Firebase verbinden (machen wir gemeinsam per CLI)

Wenn Schritt 12 erledigt sind, läuft das so (führe ich mit dir aus, hier zur Doku):

# Firebase-CLI installieren und einloggen (öffnet den Browser)
npm install -g firebase-tools
firebase login

# FlutterFire-CLI installieren
dart pub global activate flutterfire_cli

# Verbindet das Flutter-Projekt mit dem Firebase-Projekt:
# registriert die iOS- und Android-App und erzeugt lib/firebase_options.dart
flutterfire configure

flutterfire configure erzeugt lib/firebase_options.dart — darin stehen die Projekt-Kennungen (keine Geheimnisse, darf ins Git). Die eigentlichen API-Keys (Anthropic, PlantNet) leben nur in der Cloud-Functions-Umgebung, niemals in der App.

Was dabei konkret passiert ist (zum Nachvollziehen):

  • In der Firebase Console tauchen unter Projekteinstellungen → Meine Apps jetzt zwei Apps auf (iOS und Android, jeweils dev.leafittome.app).
  • android/app/google-services.json und ios/Runner/GoogleService-Info.plist sind die plattformspezifischen Verbindungsdateien; firebase.json merkt sich die Zuordnung fürs CLI.
  • In den Android-Gradle-Dateien wurde das google-services-Plugin eingetragen (verarbeitet die JSON-Datei beim Build).
  • lib/main.dart ruft beim Start Firebase.initializeApp(...) auf — ab jetzt können wir nach und nach Auth, Firestore, Storage und FCM andocken.

Schritt 4: Firestore und Login aktivieren (machst du, ~5 Minuten)

Der App-Code für Datenbank und Login ist fertig — zwei Schalter musst du in der Console einmalig umlegen:

  1. Firestore-Datenbank anlegen: Firebase Console → Build → Firestore Database„Datenbank erstellen" → Standort eur3 (Europa) wählen → Produktionsmodus (die strengen Startregeln werden gleich durch unsere eigenen ersetzt). Das aktiviert auch die Firestore-API des Projekts.
  2. E-Mail/Passwort-Login aktivieren: Firebase Console → Build → Authentication„Jetzt starten" → Tab Sign-in methodE-Mail/Passwort aktivieren. (Google- und Apple-Login rüsten wir in einem späteren Block nach — Apple braucht den Developer Account.)

Danach werden die Sicherheitsregeln aus dem Repo deployt (macht Claude per CLI):

firebase deploy --only firestore --project leaf-it-to-me-app

Das Datenmodell und die Sicherheitsregeln (zum Verständnis)

users/{uid}                      → E-Mail, householdId, fcmTokens, reminderTime (nur der Nutzer selbst)
households/{id}                  → Name, memberUids, members {uid → Rolle+E-Mail}
households/{id}/plants/{id}      → Pflanze: Art, Intervalle, lastWatered(+By), ...
households/{id}/locations/{id}   → Stellplatz: Name
invites/{code}                   → Einladung: householdId, Rolle; nur Erstellen erlaubt,
                                   Einlösen ausschließlich über die Function joinHousehold

Rollen (V2): member = volle Rechte, sitter = Pflanzen-Sitter (sieht alles, darf aber nur Aufgaben bestätigen — die Rules erlauben Sittern an Pflanzen ausschließlich Änderungen der Bestätigungs-Felder). Der Beitritt per Einladungscode läuft über die Cloud Function joinHousehold, weil der Beitretende laut Rules noch kein Mitglied ist.

Die Regeln in firestore.rules setzen das Haushalts-Prinzip durch:

  • Dein Nutzerprofil (users/{uid}) kannst nur du selbst lesen/schreiben.
  • Einen Haushalt sieht und ändert nur, wer in dessen memberUids steht. Anlegen darf man einen Haushalt nur, wenn man sich dabei selbst als Mitglied einträgt (passiert automatisch bei der Registrierung).
  • Alle Unterdaten (Pflanzen, Stellplätze) erben diese Regel: voller Zugriff für Mitglieder, für niemanden sonst. V2 (Sitter einladen) wird damit nur „weitere UID in memberUids aufnehmen".

Wichtig zu verstehen: Die App spricht direkt mit Firestore — die Regeln laufen auf Googles Servern und sind die eigentliche Zugriffskontrolle. Selbst eine manipulierte App könnte fremde Haushalte nicht lesen.

Schritt 5: Foto-Erkennung — Storage, Functions und API-Keys

Der Code ist fertig: Beim Anlegen einer Pflanze kannst du fotografieren, die Cloud Function identifyPlant bestimmt die Art (PlantNet, bei Unsicherheit Claude als Zweitmeinung) und Claude erstellt das deutsche Pflegeprofil samt Intervall-Vorschlägen. Das Foto landet in Firebase Storage im Haushalts-Ordner.

Was du einmalig tun musst:

  1. Storage aktivieren: Firebase Console → Build → Storage → „Jetzt starten" → Standort eur3 (falls gefragt) → Produktionsmodus. (Die Zugriffsregeln kommen danach per Deploy aus storage.rules — gleiches Haushalts-Prinzip wie bei Firestore.)
  2. PlantNet-API-Key holen (kostenlos): Auf https://my.plantnet.org registrieren → unter Settings/API den Key kopieren. Free-Tier: 500 Erkennungen/Tag — mehr als genug.
  3. Beide API-Keys als Secrets hinterlegen (im Terminal, jeweils Key einfügen, Enter):
firebase functions:secrets:set PLANTNET_API_KEY --project leaf-it-to-me-app
firebase functions:secrets:set ANTHROPIC_API_KEY --project leaf-it-to-me-app

Die Keys liegen damit im Google Secret Manager — verschlüsselt, nur die Cloud Function kann sie lesen, sie tauchen nie im Code, im Git oder in der App auf.

Danach (macht Claude): firebase deploy --only functions,storage — deployt die Function nach europe-west3 (Frankfurt) und die Storage-Regeln.

Kosten: PlantNet kostenlos; Claude ca. 13 Cent pro Foto (Erkennungs-Fallback + Pflegeprofil); Functions/Storage bei eurer Nutzung im Gratis-Kontingent. Der Budget-Alarm aus Schritt 2 überwacht alles.

Schritt 6: Push-Erinnerungen (FCM + geplante Function)

So funktioniert es: Die App registriert nach dem Login das Gerät bei Firebase Cloud Messaging und speichert den Geräte-Token, die Zeitzone und die Erinnerungszeit im Nutzer-Dokument. Die geplante Function sendDailyReminders läuft alle 15 Minuten, prüft für jeden Nutzer „ist gerade seine Erinnerungszeit erreicht und gibt es offene Aufgaben?" und schickt dann eine Sammel-Push pro Tag („3 Pflanzen brauchen dich heute 🌱 — Gießen: Monstera, Orchidee · Düngen: Bogenhanf"). Ungültig gewordene Tokens (Gerät gewechselt, App gelöscht) werden automatisch aufgeräumt. Kosten: ~2.900 Läufe/Monat, tief im Gratis-Kontingent.

Android: funktioniert sofort — beim ersten App-Start nach diesem Update fragt die App die Benachrichtigungs-Berechtigung ab, fertig.

iOS braucht den Apple Developer Account (Push ist auf iOS ohne bezahlten Account nicht möglich). Sobald er freigeschaltet ist:

  1. APNs-Schlüssel erzeugen: https://developer.apple.comCertificates, Identifiers & ProfilesKeys → „+" → Namen vergeben, Apple Push Notifications service (APNs) ankreuzen → Continue → Register → .p8-Datei herunterladen (nur einmal möglich!) und die Key ID notieren; die Team ID steht oben rechts im Account.
  2. In Firebase hinterlegen: Firebase Console → Projekteinstellungen (Zahnrad) → Cloud Messaging → Abschnitt „Apple-App-Konfiguration" → APNs-Authentifizierungsschlüssel hochladen (.p8 + Key ID + Team ID).
  3. Push-Capability in Xcode: ios/Runner.xcworkspace öffnen → Ziel RunnerSigning & Capabilities → „+ Capability" → Push Notifications hinzufügen (und einmal Background Modes → Remote notifications anhaken). Dafür muss als Team der Developer Account gewählt sein.

Danach einmal neu bauen (flutter run) — die Erinnerungen landen dann auch auf dem iPhone-Sperrbildschirm.

Schritt 7 und folgende (kommen mit den nächsten Blöcken)

  • Google-/Apple-Login — zusätzlich zu E-Mail/Passwort (Apple-Login braucht ebenfalls den Developer Account).
  • App Check — optionale Härtung vor dem App-Store-Release: bestätigt per Play Integrity (Android) / App Attest (iOS), dass Anfragen aus der echten App kommen. Bis dahin ist die Log-Warnung „No AppCheckProvider installed" harmlos und kann ignoriert werden — die Zugriffskontrolle leisten Login + Security Rules.

Begriffe kurz erklärt

  • Projekt: Der Container für alles — eine App = ein Firebase-Projekt.
  • Firestore-Dokument/Collection: Firestore ist keine Tabellen-Datenbank, sondern speichert JSON-artige Dokumente in Collections (Ordnern), z. B. households/abc123/plants/xyz789.
  • Security Rules: Regeln auf dem Server, die festlegen, wer welche Dokumente lesen/schreiben darf — unser Schutz, obwohl die App direkt mit der Datenbank spricht.
  • Cloud Function: Eine Funktion (bei uns TypeScript), die bei Ereignissen oder nach Zeitplan auf Google-Servern läuft.