leafittome/docs/architektur.md
cschlaefke 6e22d9c3aa Projekt-Gerüst: Flutter-App mit Heute-Checkliste, Pflanzenverwaltung, Stellplätzen und Einstellungen
- Flutter/Dart (iOS + Android), Riverpod, go_router, i18n via ARB (deutsch)
- Feature-Struktur: today, plants, locations, household (V2-Platzhalter), settings
- Intervall-Modell: Aufgaben werden aus lastWatered/lastFertilized + Intervall berechnet
- In-Memory-Demo-Daten, Firebase-Anbindung folgt im nächsten Block
- Doku: Architektur, Firebase-Einrichtung, Forgejo-Git-Hosting

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

60 lines
4.5 KiB
Markdown

# Architektur & Projektstruktur
Dieses Dokument erklärt den Aufbau des Planty-Codes — auch als Blaupause für weitere Flutter-Apps.
## Ordnerstruktur
```
lib/
├── main.dart # Einstiegspunkt: lädt SharedPreferences, startet die App
├── app.dart # MaterialApp: Theme, Routing, Lokalisierung, Schriftgröße
├── core/ # Alles, was NICHT zu einem einzelnen Feature gehört
│ ├── router/app_router.dart # Zentrale Routen-Definition (go_router)
│ ├── settings/ # App-Einstellungen (Theme, Schriftgröße, Erinnerungszeit)
│ ├── theme/app_theme.dart # Farbschema und Bedienbarkeits-Anpassungen
│ └── widgets/app_drawer.dart# Das Hamburger-Menü
├── features/ # Ein Ordner pro Fachlichkeit
│ ├── today/ # Tages-Checkliste (Start-Screen)
│ ├── plants/ # Pflanzen: Liste, Profil, Anlegen/Bearbeiten
│ ├── locations/ # Stellplätze
│ ├── household/ # Haushalt (V2-Platzhalter)
│ └── settings/ # Einstellungs-Screen
└── l10n/
├── app_de.arb # ALLE deutschen Texte (Quelle)
└── generated/ # Automatisch generierter Code (nicht anfassen)
```
## Schichten innerhalb eines Features
Jedes Feature folgt demselben Muster (nicht jedes braucht alle Schichten):
- **`domain/`** — Die fachlichen Modelle (`Plant`, `DueTask`, `PlantLocation`). Reines Dart, keine Flutter- oder Firebase-Abhängigkeiten. Hier steckt die Fachlogik (z. B. „Fälligkeit = letzte Erledigung + Intervall").
- **`data/`** — Datenhaltung. Aktuell In-Memory-Notifier mit Demo-Daten; im Firebase-Block werden sie durch Firestore-Anbindungen ersetzt. **Wichtig:** Die Provider-Schnittstelle nach außen bleibt gleich — die Screens merken vom Austausch nichts.
- **`application/`** — Abgeleitete Zustände / Anwendungslogik, z. B. `dueTasksProvider`, der aus den Pflanzen die heute fälligen Aufgaben berechnet.
- **`presentation/`** — Die Screens und Widgets.
**Faustregel für Abhängigkeiten:** `presentation → application → data → domain`. Niemals andersherum, und Features greifen nur über Provider aufeinander zu.
## State Management: Riverpod in 3 Sätzen
1. Ein **`Notifier`** hält veränderlichen Zustand (z. B. die Pflanzenliste) und bietet Methoden zum Ändern (`addPlant`, `confirmTask`); ein **`Provider`** berechnet abgeleiteten Zustand (z. B. fällige Aufgaben) und aktualisiert sich automatisch, wenn sich seine Quellen ändern.
2. Screens sind `ConsumerWidget`s: `ref.watch(provider)` liest den Zustand und baut die UI bei Änderungen neu; `ref.read(provider.notifier).methode()` löst Änderungen aus (in Callbacks).
3. `ProviderScope` in `main.dart` ist die Wurzel; dort werden auch echte Abhängigkeiten (SharedPreferences, später Firebase) hineingereicht — Tests können sie durch Mocks ersetzen.
## Kernentscheidungen im fachlichen Modell
- **Aufgaben werden nicht gespeichert, sondern berechnet.** Es gibt keine „Task-Tabelle": Aus `lastWatered + wateringIntervalDays` ergibt sich die Fälligkeit. Eine Bestätigung setzt nur `lastWatered` neu — dadurch kann nichts inkonsistent werden, und Überfälliges „wandert" automatisch mit.
- **Haushaltszentriert gedacht:** Pflanzen, Stellplätze und Aufgaben gehören dem *Haushalt*, nicht einem Nutzer. In Firestore wird das `households/{id}/plants/{id}` usw. — so ist V2 (Sharing) nur „weiteres Mitglied hinzufügen", keine Datenmigration.
- **`null` bei `lastWatered` heißt „noch nie"** → Aufgabe ist sofort fällig. So braucht eine neu angelegte Pflanze keine Sonderbehandlung.
## Übersetzungen (i18n)
Alle Texte stehen in `lib/l10n/app_de.arb` als Schlüssel-Wert-Paare. Im Code heißt es nie `Text('Gießen')`, sondern `Text(l10n.taskWaterTitle(name))`. Englisch später hinzufügen = eine Datei `app_en.arb` mit denselben Schlüsseln anlegen und `flutter gen-l10n` ausführen — kein Code-Umbau.
Nach jeder Änderung an der `.arb`-Datei: `flutter gen-l10n` ausführen (passiert bei `flutter run` auch automatisch).
## Bedienbarkeit (Zielgruppe: auch ältere Menschen)
- Schriftgröße in den Einstellungen wirkt **zusätzlich** zur System-Schriftgröße (`app.dart`, `builder`).
- „Hoher Kontrast" nutzt Material 3 `contrastLevel` — dasselbe Farbschema, kräftigere Kontraste.
- Große Touch-Ziele (`app_theme.dart`), keine Swipe-Gesten, alle Funktionen über sichtbare Buttons und das Hamburger-Menü.