Implement prior-period comparison data fetching
epic-bufdir-report-preview-foundation-task-004 — Add a second Riverpod stream to BufdirPreviewRepository that fetches the equivalent aggregated data for the prior reporting period, enabling diff/comparison views. Re-use the existing query layer with a shifted date range parameter. Cache prior-period results independently. Return a BufdirPeriodComparisonData model containing both current and prior snapshots alongside delta values.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Define a `DateRange` value object with `start` and `end` fields and a `shiftBack(ReportingPeriod period)` factory to keep date arithmetic centralised. Use `family` provider modifier so both current and prior period providers share the same query function with different DateRange arguments. Store cache timestamps in-memory (or Hive if persistence is needed). Delta computation should be a pure static method on BufdirPeriodComparisonData to keep it testable.
Guard against division-by-zero if prior values are zero when computing percentage deltas.
Testing Requirements
Unit tests using a mocked Supabase client: verify the prior-period query receives a date range shifted back by one period; verify BufdirPeriodComparisonData.deltaValues are computed correctly for standard data, for zero prior data, and for partial prior data. Integration test: emit sequence (loading → data) for both streams in parallel. Cache tests: assert a second subscription within TTL does not trigger a new Supabase call. Minimum 85% line coverage on repository and model classes.
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.