Implement BufdirPreviewRepository with Riverpod streams
epic-bufdir-report-preview-foundation-task-002 — Build the full BufdirPreviewRepository class exposing reactive Riverpod StreamProvider streams for current-period report data. Wire the Supabase query layer from task-001, add error handling, and ensure the repository emits loading/data/error states that UI layers can consume. Register the provider in the dependency injection tree.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Define an abstract class BufdirPreviewRepositoryInterface with the two fetch method signatures — the concrete BufdirPreviewRepository implements it and the mock in tests also implements it. This avoids relying on mocktail's generated mocks for a class with Supabase internals. The Riverpod StreamProvider should be a family provider parameterised by (periodId, orgId) — bufdirPreviewDataProvider(({String periodId, String orgId} params)) — so different period/org combinations can be independently watched without provider conflicts. Use ref.onDispose to cancel any in-flight futures.
Avoid ref.read inside the StreamProvider body — pass dependencies via provider overrides in tests.
Testing Requirements
Unit tests using flutter_test and mocktail: (1) fetchAggregatedData returns BufdirReportData on successful Supabase response, (2) fetchAggregatedData throws BufdirRepositoryException on PostgrestException, (3) fetchPriorPeriodData returns null when no prior-period row exists, (4) StreamProvider emits AsyncLoading then AsyncData in sequence, (5) StreamProvider emits AsyncError on repository failure. Mock SupabaseClient using mocktail. Use ProviderContainer from riverpod/test for provider testing without a full widget tree. Assert AsyncValue state transitions.
The preview repository depends on aggregated data produced by the Bufdir Data Aggregation feature. If the aggregation RPC schema or Supabase view columns change during parallel development, the repository's typed Dart models will break, causing compile errors or runtime null-dereference failures.
Mitigation & Contingency
Mitigation: Define a shared Dart interface (abstract class) for the aggregated data contract early and have both features code against it. Use Supabase typed generated clients so schema mismatches surface at code generation time rather than runtime.
Contingency: If the aggregation schema changes after the repository is complete, run `supabase gen types dart` immediately, update the repository model, and run repository unit tests before unblocking UI development. Keep a mock data fixture so UI work can continue during the fix.
The BufdirReportStructureMapper must map internal activity category IDs to the exact label strings used on the official Bufdir reporting form. If the mapping is incomplete or uses outdated labels, coordinators will see mismatches when cross-referencing the preview with the paper form, potentially leading to incorrect submissions.
Mitigation & Contingency
Mitigation: Obtain the current Bufdir reporting form PDF directly from Bufdir (Norse Digital Products has an existing Bufdir dialogue). Extract all field labels and section names into a static constants file reviewed by at least one coordinator from NHF or HLF before implementation begins.
Contingency: If incorrect labels are discovered during UAT on TestFlight, update the static constants file and redeploy. Because the mapper is a pure Dart class with no database storage, corrections require no migration — only a new build.