# 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*
