Перейти к содержанию

ADR-001: State Management — Riverpod

Status: Accepted Date: 2026-02-07 Deciders: Dmitry Aleshkovskiy, Claude (AI assistant) Jira: AF-94

Context

App Factory is a new Flutter application that needs a state management solution. The app follows an offline-first architecture with background sync, requiring robust async state handling, caching, and testability.

Key requirements from the architecture: - Offline-first with local persistence (Drift/SQLite) - Background sync via Celery + polling - Multiple app variants from a single codebase - High testability (TDD mandatory) - Code generation acceptable (build_runner already planned)

Options Considered

1. BLoC (flutter_bloc)

  • Pros: Battle-tested, strict Event/State pattern, good for large teams with strict conventions
  • Cons: Significant boilerplate (Event + State + Bloc classes per feature), verbose for simple cases, steeper learning curve for async flows

2. Riverpod 2.x (flutter_riverpod + riverpod_annotation)

  • Pros: Minimal boilerplate via @riverpod code generation, native AsyncNotifier + AsyncValue for async/offline flows, ProviderContainer for full test isolation, compile-time safety, no BuildContext dependency
  • Cons: Younger ecosystem, annotation-based API requires build_runner

3. Provider

  • Pros: Simple, well-documented
  • Cons: Being superseded by Riverpod (same author), limited async support, BuildContext dependency

4. GetX

  • Pros: Low boilerplate
  • Cons: Poor separation of concerns, implicit magic, hard to test, not recommended for production apps

Decision

Riverpod 2.x with code generation (riverpod_annotation + riverpod_generator).

Rationale

  1. Less boilerplate: No Event/State class hierarchies — a @riverpod annotation on a function or class is sufficient
  2. Native async support: AsyncNotifier and AsyncValue handle loading/error/data states out of the box — critical for offline-first
  3. Testability: ProviderContainer allows full provider override in tests without mocking frameworks
  4. Code generation: Already using build_runner for Drift and JSON serialization — Riverpod fits the existing toolchain
  5. Compile-time safety: Provider dependencies checked at compile time, no runtime errors
  6. No BuildContext: Providers accessible anywhere (services, repositories) without widget tree dependency

Packages

dependencies:
  flutter_riverpod: ^2.6.1
  riverpod_annotation: ^2.6.1

dev_dependencies:
  riverpod_generator: ^2.6.3
  build_runner: ^2.4.14

Consequences

  • All state management uses Riverpod providers (no mixing with other solutions)
  • Feature modules follow pattern: provider.dart (state) + notifier.dart (logic) + widget.dart (UI)
  • Tests use ProviderContainer with overrides for dependency injection
  • build_runner must be run after changing @riverpod annotated code
  • Team members need to learn Riverpod patterns (AsyncNotifier, ref.watch, ref.read)

References