docs: complete project research
This commit is contained in:
206
.planning/research/STACK.md
Normal file
206
.planning/research/STACK.md
Normal file
@@ -0,0 +1,206 @@
|
||||
# Stack Research
|
||||
|
||||
**Domain:** Local-first Flutter household chore management app (Android-first)
|
||||
**Researched:** 2026-03-15
|
||||
**Confidence:** HIGH (versions verified directly from pub.dev; compatibility notes cross-checked against GitHub issues and official docs)
|
||||
|
||||
---
|
||||
|
||||
## Recommended Stack
|
||||
|
||||
### Core Technologies
|
||||
|
||||
| Technology | Version | Purpose | Why Recommended |
|
||||
|------------|---------|---------|-----------------|
|
||||
| Flutter SDK | ^3.41.x (stable) | UI framework and build toolchain | Current stable. Riverpod 3.3.x requires Dart 3.7+; Flutter 3.41 ships Dart 3.7. Earlier stable releases (pre-3.41) had a transitive `analyzer` conflict with Riverpod 3.2+ that was fixed in 3.41.1. |
|
||||
| Dart SDK | ^3.7.0 | Language runtime | Minimum required by `flutter_riverpod ^3.3.0`. Set as lower bound in `pubspec.yaml`. |
|
||||
| flutter_riverpod | ^3.3.1 | State management and dependency injection | The project already decided on Riverpod. v3.x is current stable (released Sep 2025); it unifies `AutoDispose`/`Family` variants, simplifies `Ref` (no more subclasses), and adds built-in offline persistence (opt-in). Start on v3 — migrating from v2 later is painful. |
|
||||
| riverpod_annotation | ^4.0.2 | Annotations for code-generation-based providers | Enables `@riverpod` annotation. Required companion to `riverpod_generator`. Code-gen is the recommended path in Riverpod 3 — less boilerplate, compile-safe, `autoDispose` by default. |
|
||||
| drift | ^2.32.0 | Type-safe reactive SQLite ORM | The project already decided on Drift. Reactive streams (`.watch()`) integrate naturally with `StreamProvider` in Riverpod. Type-safe query generation catches errors at compile time. Built-in migration support is essential for a long-lived local-first app. |
|
||||
| drift_flutter | ^0.3.0 | Flutter-specific Drift setup helper | Bundles `sqlite3_flutter_libs`, handles `getApplicationDocumentsDirectory()` automatically. Eliminates manual SQLite platform setup on Android. Use `driftDatabase(name: 'household_keeper')` to open the DB. |
|
||||
|
||||
### Supporting Libraries
|
||||
|
||||
| Library | Version | Purpose | When to Use |
|
||||
|---------|---------|---------|-------------|
|
||||
| freezed | ^3.2.5 | Immutable value objects with copyWith, equality, pattern matching | Use for all domain entities (Room, Task, TaskCompletion) and Riverpod state classes. `@freezed` + code-gen eliminates hand-written `==` / `copyWith`. |
|
||||
| freezed_annotation | ^3.1.0 | Annotations for freezed code generation | Required companion to `freezed`. Always add to `dependencies` (not `dev_dependencies`). |
|
||||
| go_router | ^17.1.0 | Declarative URL-based navigation | Official Flutter team package. The app has shallow navigation (RoomList → TaskList → DailyPlan), but GoRouter's `ShellRoute` cleanly handles a bottom nav bar with persistent state per tab. Simple enough for this app's needs; widely supported. |
|
||||
| flutter_local_notifications | ^21.0.0 | Scheduled local notifications | For the daily summary notification (required by PROJECT.md). No Firebase needed — purely on-device scheduling via Android's AlarmManager. Requires Android 7.0+ (API 24). |
|
||||
| timezone | ^0.11.0 | Timezone-aware scheduled notifications | Required by `flutter_local_notifications` for reliable scheduled notification timing across daylight-saving boundaries. |
|
||||
| flex_color_scheme | ^8.4.0 | Material 3 theme generation | Generates a fully consistent M3 `ThemeData` — including legacy color properties that `ColorScheme.fromSeed()` misses — from a single seed color. The calm muted-green palette specified in PROJECT.md is straightforward to express as a seed color. Reduces ~300 lines of manual theme code to ~20. |
|
||||
| intl | ^0.19.0 | Date and number formatting; localization infrastructure | Format due dates (German locale: `dd.MM.yyyy`), relative strings ("übermorgen", "heute"). Also the underlying engine for `flutter_localizations`. Even for a German-only MVP, you still need date formatting. |
|
||||
|
||||
### Development Tools and Code-Generation Packages
|
||||
|
||||
| Tool / Package | Version | Purpose | Notes |
|
||||
|----------------|---------|---------|-------|
|
||||
| riverpod_generator | ^4.0.3 (dev) | Generates provider boilerplate from `@riverpod` annotations | Run `dart run build_runner watch -d` during development. The `-d` flag deletes conflicting outputs before building. |
|
||||
| drift_dev | ^2.32.0 (dev) | Generates type-safe Drift query code from table definitions | Same `build_runner` run handles both Drift and Riverpod generation. |
|
||||
| build_runner | ^2.12.2 (dev) | Orchestrates all code generation | One `build_runner watch` invocation covers all generators in the project. |
|
||||
| freezed (dev) | ^3.2.5 (dev) | Generates immutable class implementations | Note: `freezed` appears in both `dependencies` (as annotation) and `dev_dependencies` (as generator). `freezed_annotation` goes in `dependencies`, `freezed` itself in `dev_dependencies`. |
|
||||
| flutter_lints | ^6.0.0 (dev) | Official Flutter lint ruleset | Default in new Flutter projects. Catches common errors and style issues. Extend with stricter rules in `analysis_options.yaml` as the codebase grows. |
|
||||
| riverpod_lint | ^4.0.x (dev) | Riverpod-specific lint rules | Catches incorrect provider usage: unused providers, missing `ref.watch` inside builds, incorrect `async` patterns. Add alongside `flutter_lints`. Check exact version on pub.dev at setup time — tracks `riverpod_generator` versions. |
|
||||
|
||||
---
|
||||
|
||||
## pubspec.yaml
|
||||
|
||||
```yaml
|
||||
name: household_keeper
|
||||
description: Local-first chore management app for Android.
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ^3.7.0
|
||||
flutter: ">=3.41.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
|
||||
# State management
|
||||
flutter_riverpod: ^3.3.1
|
||||
riverpod_annotation: ^4.0.2
|
||||
|
||||
# Database
|
||||
drift: ^2.32.0
|
||||
drift_flutter: ^0.3.0
|
||||
|
||||
# Immutable models
|
||||
freezed_annotation: ^3.1.0
|
||||
|
||||
# Navigation
|
||||
go_router: ^17.1.0
|
||||
|
||||
# Notifications
|
||||
flutter_local_notifications: ^21.0.0
|
||||
timezone: ^0.11.0
|
||||
|
||||
# Theming
|
||||
flex_color_scheme: ^8.4.0
|
||||
|
||||
# Localization / date formatting
|
||||
intl: ^0.19.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^6.0.0
|
||||
|
||||
# Code generation
|
||||
riverpod_generator: ^4.0.3
|
||||
riverpod_lint: ^4.0.0 # verify exact version on pub.dev at setup time
|
||||
build_runner: ^2.12.2
|
||||
drift_dev: ^2.32.0
|
||||
freezed: ^3.2.5
|
||||
|
||||
flutter:
|
||||
generate: true # required for flutter_localizations ARB code gen
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
| Category | Recommended | Alternative | Why Not Alternative |
|
||||
|----------|-------------|-------------|---------------------|
|
||||
| State management | Riverpod 3.x | flutter_bloc | Project already decided Riverpod. Bloc requires more boilerplate (events, states, blocs) for what this app needs. Riverpod integrates more naturally with Drift's reactive streams. |
|
||||
| State management | Riverpod 3.x | Riverpod 2.x | v2 is no longer maintained upstream. v3 was released Sep 2025; migrating later is a breaking-change effort. Start on v3 now. |
|
||||
| Database | Drift | Isar | Isar is a NoSQL document store — less natural for the relational structure (rooms → tasks → completions). Drift's reactive streams fit Riverpod's `StreamProvider` perfectly. Isar's future is uncertain after its maintainer handed it off. |
|
||||
| Database | Drift | ObjectBox | ObjectBox is a NoSQL object store. Same relational argument applies. Drift's SQL gives more flexibility for complex queries (e.g., "overdue tasks per room" with joins). ObjectBox has a commercial tier for some features. |
|
||||
| Database | Drift | sqflite + raw SQL | Raw sqflite requires manual query strings, manual mapping, no reactive streams, no compile-time safety. The project explicitly chose Drift over raw sqflite for type safety and migration support. |
|
||||
| Navigation | go_router | auto_route | auto_route has slightly better type safety but requires more setup. go_router is an official Flutter package — simpler, well-documented, maintained by the Flutter team. Good enough for this app's flat navigation graph. |
|
||||
| Navigation | go_router | Navigator 2.0 (raw) | Excessive boilerplate for a 4-screen app. go_router wraps Navigator 2.0 cleanly. |
|
||||
| Theming | flex_color_scheme | Manual ThemeData | Manual M3 theming misses legacy color sync (e.g., `ThemeData.cardColor`, `dialogBackgroundColor` still default to wrong values without explicit override). flex_color_scheme fills all gaps. For a calm, consistent design, the investment of one dependency is worth it. |
|
||||
| Theming | flex_color_scheme | dynamic_color (Material You) | Dynamic color adapts to wallpaper — inappropriate for a fixed calm-palette design. The app defines its own identity; it should not shift colors based on user wallpaper. |
|
||||
| Notifications | flutter_local_notifications | awesome_notifications | awesome_notifications is more powerful but significantly heavier. flutter_local_notifications is sufficient for a single daily scheduled notification. |
|
||||
| Localization | flutter_localizations + intl | easy_localization | For German-only MVP, flutter_localizations with ARB files is the official path. easy_localization adds another dependency with no benefit until multi-language is needed. When English is added in v1.1, the ARB infrastructure is already in place. |
|
||||
|
||||
---
|
||||
|
||||
## What NOT to Use
|
||||
|
||||
| Avoid | Why | Use Instead |
|
||||
|-------|-----|-------------|
|
||||
| Provider (package) | Predecessor to Riverpod, now in maintenance mode. Much weaker compile-time safety. Migration from Provider to Riverpod later is non-trivial. | `flutter_riverpod ^3.3.1` |
|
||||
| StateNotifierProvider / StateProvider (Riverpod legacy) | Moved to `package:flutter_riverpod/legacy.dart` in Riverpod 3.0. The official docs now use `@riverpod` + `AsyncNotifier` / `Notifier`. Using legacy providers means you will need to migrate soon after starting. | `@riverpod` annotated `AsyncNotifier` / `Notifier` classes |
|
||||
| Hive | No first-class SQLite support. Key-value store with no query language — cannot express "tasks due today across all rooms" without loading the entire dataset. Hive v2 has had stale maintenance; Isar (its successor) is now also uncertain. | Drift |
|
||||
| Firebase (any service) | PROJECT.md is explicit: zero backend, zero network dependencies, no analytics, no tracking. Firebase Firestore, Firebase Analytics, Firebase Crashlytics, Firebase Auth — all out of scope. | Nothing; handle everything locally. |
|
||||
| GetIt (service locator) | Riverpod already handles DI through providers. Using GetIt alongside Riverpod creates two competing DI systems and makes provider scoping/testing harder. | Riverpod providers as the single DI mechanism |
|
||||
| MobX | Not compatible with Riverpod. Requires its own code generation and observable pattern. Complexity without benefit when Riverpod 3.x already handles reactive state. | `flutter_riverpod + riverpod_generator` |
|
||||
| flutter_bloc alongside Riverpod | Two competing state systems in one codebase creates cognitive overhead and testing complexity. | Pick one: Riverpod for this project. |
|
||||
| `StateNotifier` (standalone package) | Deprecated upstream. Riverpod 3.x `Notifier` replaces it. | `Notifier<T>` with `@riverpod` |
|
||||
|
||||
---
|
||||
|
||||
## Stack Patterns by Variant
|
||||
|
||||
**For reactive Drift queries (read-only list screens):**
|
||||
- Use `@riverpod Stream<List<T>>` backed by a DAO `.watch()` method
|
||||
- The screen consumes via `ref.watch(roomsProvider)` returning `AsyncValue<List<Room>>`
|
||||
- Drift emits a new list automatically when the database changes — no manual invalidation
|
||||
|
||||
**For mutations (completing a task, adding a room):**
|
||||
- Use `@riverpod class TaskNotifier extends AsyncNotifier<void>` with explicit methods
|
||||
- Call `ref.invalidate(tasksProvider)` after mutation to trigger rebuild on affected watchers
|
||||
- In Riverpod 3.x, the new experimental `Mutation` API is available but still experimental — use manual invalidation for stability
|
||||
|
||||
**For the daily plan (complex cross-room query):**
|
||||
- Implement a Drift query that joins tasks + rooms filtered by due date
|
||||
- Expose via `@riverpod Stream<DailyPlanSummary>` so the plan view auto-updates as tasks are completed
|
||||
- Do NOT compute the daily plan in the UI layer — push join logic into a DAO method
|
||||
|
||||
**For notification scheduling:**
|
||||
- Schedule the daily notification at app startup (in a `ProviderScope` override or `app.dart` `initState`)
|
||||
- Re-schedule when the user completes all tasks for the day or explicitly changes notification time
|
||||
- Notification scheduling is one-time daily, not per-task — keeps it simple for MVP
|
||||
|
||||
**For German-only MVP localization:**
|
||||
- Use hardcoded German strings in widgets for MVP rather than ARB files
|
||||
- Set up the ARB infrastructure skeleton (`l10n.yaml`, `lib/l10n/app_de.arb`) before v1.1 so adding English is a string extraction exercise, not an architectural change
|
||||
- Do NOT use `String.fromCharCodes` or runtime locale detection — always target `de`
|
||||
|
||||
---
|
||||
|
||||
## Version Compatibility Notes
|
||||
|
||||
| Package | Compatible With | Notes |
|
||||
|---------|-----------------|-------|
|
||||
| flutter_riverpod ^3.3.1 | Flutter >=3.41.0, Dart >=3.7 | Pre-3.41 Flutter stable had a transitive `analyzer` conflict. Resolved in Flutter 3.41.1. Use current stable (3.41.2). |
|
||||
| drift ^2.32.0 + drift_dev ^2.32.0 | Build-runner ^2.12.2 | drift and drift_dev versions must match exactly. |
|
||||
| riverpod_generator ^4.0.3 | riverpod_annotation ^4.0.2 | Generator and annotation major versions must match (both 4.x). |
|
||||
| freezed ^3.2.5 | freezed_annotation ^3.1.0 | Major versions must match (both 3.x). |
|
||||
| flutter_local_notifications ^21.0.0 | Android API 24+ (Android 7.0+) | Minimum API level 24. Requires `RECEIVE_BOOT_COMPLETED` permission in `AndroidManifest.xml` and core library desugaring in `build.gradle.kts`. |
|
||||
| flex_color_scheme ^8.4.0 | Flutter >=3.x, Dart >=3.x | M3 enabled by default in v8+. No additional configuration needed. |
|
||||
|
||||
---
|
||||
|
||||
## Sources
|
||||
|
||||
- [pub.dev/packages/flutter_riverpod](https://pub.dev/packages/flutter_riverpod) — version 3.3.1 verified directly
|
||||
- [pub.dev/packages/riverpod_generator](https://pub.dev/packages/riverpod_generator) — version 4.0.3 verified directly
|
||||
- [pub.dev/packages/riverpod_annotation](https://pub.dev/packages/riverpod_annotation) — version 4.0.2 verified directly
|
||||
- [riverpod.dev/docs/whats_new](https://riverpod.dev/docs/whats_new) — Riverpod 3.0 feature list
|
||||
- [riverpod.dev/docs/3.0_migration](https://riverpod.dev/docs/3.0_migration) — breaking changes guide
|
||||
- [pub.dev/packages/drift](https://pub.dev/packages/drift) — version 2.32.0 verified directly
|
||||
- [pub.dev/packages/drift_flutter](https://pub.dev/packages/drift_flutter) — version 0.3.0 verified directly
|
||||
- [drift.simonbinder.eu/setup](https://drift.simonbinder.eu/setup/) — official Drift setup guide
|
||||
- [pub.dev/packages/go_router](https://pub.dev/packages/go_router) — version 17.1.0 verified directly
|
||||
- [pub.dev/packages/flutter_local_notifications](https://pub.dev/packages/flutter_local_notifications) — version 21.0.0 verified directly
|
||||
- [pub.dev/packages/freezed](https://pub.dev/packages/freezed) — version 3.2.5 verified directly
|
||||
- [pub.dev/packages/freezed_annotation](https://pub.dev/packages/freezed_annotation) — version 3.1.0 verified directly
|
||||
- [pub.dev/packages/flex_color_scheme](https://pub.dev/packages/flex_color_scheme) — version 8.4.0 verified directly
|
||||
- [pub.dev/packages/timezone](https://pub.dev/packages/timezone) — version 0.11.0 verified directly
|
||||
- [pub.dev/packages/build_runner](https://pub.dev/packages/build_runner) — version 2.12.2 verified directly
|
||||
- [pub.dev/packages/flutter_lints](https://pub.dev/packages/flutter_lints) — version 6.0.0 verified directly
|
||||
- [github.com/rrousselGit/riverpod/issues/4676](https://github.com/rrousselGit/riverpod/issues/4676) — Riverpod 3.2+/stable channel compatibility; resolved in Flutter 3.41.1 (MEDIUM confidence)
|
||||
- [docs.flutter.dev/release/archive](https://docs.flutter.dev/release/archive) — Flutter 3.41 current stable confirmed
|
||||
- [docs.flexcolorscheme.com](https://docs.flexcolorscheme.com/) — M3 legacy color sync coverage (MEDIUM confidence, official docs)
|
||||
|
||||
---
|
||||
|
||||
*Stack research for: Local-first Flutter household chore management app (HouseHoldKeaper)*
|
||||
*Researched: 2026-03-15*
|
||||
Reference in New Issue
Block a user