# 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` with `@riverpod` | --- ## Stack Patterns by Variant **For reactive Drift queries (read-only list screens):** - Use `@riverpod Stream>` backed by a DAO `.watch()` method - The screen consumes via `ref.watch(roomsProvider)` returning `AsyncValue>` - 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` 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` 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*