high priority medium complexity backend pending backend specialist Tier 3

Acceptance Criteria

BufdirPreviewRepository exposes a `priorPeriodStream` Riverpod StreamProvider that emits BufdirPeriodComparisonData
The prior-period query uses the same underlying Supabase query as the current-period query, with the date range shifted back by exactly one reporting period
BufdirPeriodComparisonData model contains: currentSnapshot (BufdirReportData), priorSnapshot (BufdirReportData), and deltaValues (Map<String, num>) computed as current minus prior for each numeric field
Prior-period data is cached independently from current-period data — a cache hit for one does not affect the other
When the prior period has no data, priorSnapshot is an empty/zero-value BufdirReportData and deltas equal the current values
The stream emits AsyncLoading, then AsyncData or AsyncError states correctly
Cache expiry for prior-period results is configurable and defaults to 24 hours (prior data rarely changes)
No Supabase query is duplicated — the existing query layer is reused with a DateRange parameter

Technical Requirements

frameworks
Flutter
Riverpod
Dart
apis
Supabase REST/PostgREST — activity aggregation query with date range filter
data models
BufdirReportData
BufdirPeriodComparisonData
DateRange
performance requirements
Prior-period cache TTL >= 24h to avoid redundant queries on stable historical data
Delta computation must be O(n) over field count — no nested iteration
Stream should not re-fetch if cached data is still valid
security requirements
Supabase RLS policies must be respected — user may only fetch data for their own organisation
No raw activity records are exposed — only aggregated counts/values

Execution Context

Execution Tier
Tier 3

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.

Component
Bufdir Preview Repository
data medium
Epic Risks (2)
high impact medium prob integration

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.

high impact medium prob scope

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.