leafittome/docs/firebase-einrichtung.md
cschlaefke 52e72c25b1 Push-Erinnerungen: FCM-Registrierung in der App, geplante Function sendDailyReminders
- Function läuft alle 15 Min (europe-west3): prüft Erinnerungszeit pro Nutzer (Zeitzonen-korrekt), berechnet fällige Aufgaben, schickt eine Sammel-Push pro Tag, räumt ungültige Tokens auf
- App registriert Gerät nach Login (Berechtigung, Token, Zeitzone), Erinnerungszeit wird ins Nutzer-Dokument synchronisiert
- Doku Schritt 6 inkl. APNs-Anleitung für iOS (sobald Developer Account da ist)

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

136 lines
10 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.

# 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 Abrechnung****Tarif ä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):
```bash
# 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 method***E-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):
```bash
firebase deploy --only firestore --project leaf-it-to-me-app
```
## Das Datenmodell und die Sicherheitsregeln (zum Verständnis)
```
users/{uid} → E-Mail, householdId (nur der Nutzer selbst)
households/{id} → Name, memberUids [Liste der Mitglieder]
households/{id}/plants/{id} → Pflanze: Art, Intervalle, lastWatered, ...
households/{id}/locations/{id} → Stellplatz: Name
```
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):
```bash
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.com>*Certificates, Identifiers & Profiles***Keys** → „+" → 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 *Runner**Signing & 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).
## 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.