Define Supabase query layer for aggregated report data
epic-bufdir-report-preview-foundation-task-001 — Design and implement the Supabase query methods inside BufdirPreviewRepository that fetch aggregated activity data for a selected reporting period. Define the query builder, RPC calls or view references, and the Dart data models (BufdirReportData, BufdirAggregatedField) that map Supabase rows to domain objects. Ensure row-level security is respected so only authorised coordinators can access their organisation's data.
Acceptance Criteria
Technical Requirements
Implementation Notes
Prefer a Supabase database view or RPC function over complex client-side query builders — this keeps aggregation logic in SQL where it is testable independently and benefits from database query optimisation. Name the RPC function bufdir_get_aggregated_report(p_period_id text, p_org_id uuid) following Supabase naming conventions. BufdirReportData should be an immutable class (use @immutable annotation and final fields). BufdirAggregatedField should carry: fieldId (String), fieldLabel (String), value (num), unit (String?), and isRequired (bool).
The distinction between required and optional Bufdir fields is important for downstream validation. Define BufdirRepositoryException with a code (String) and message (String) to allow UI layers to show specific error messages without depending on Supabase internals.
Testing Requirements
Write unit tests for BufdirReportData.fromJson() and BufdirAggregatedField.fromJson() covering: valid full response, missing optional fields defaulting correctly, null values for nullable fields, and unknown keys being ignored. Use flutter_test with hardcoded JSON fixture maps — no live Supabase connection needed. Also write a contract test documenting the expected Supabase RPC/view response shape so schema changes are caught early. Aim for 100% coverage on fromJson() factories.
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.