critical priority low complexity backend pending backend specialist Tier 0

Acceptance Criteria

A `BufdirFormSection` sealed class (or equivalent typed constant structure) is declared with one subtype per Bufdir form section in the correct submission order
Each section contains an ordered `List<BufdirFieldDefinition>` of its fields
BufdirFieldDefinition has: `fieldKey` (String, unique across all sections), `bufdirLabel` (String, official Norwegian label), `isMandatory` (bool)
A top-level constant `kBufdirSections` exposes the complete ordered list of all sections — this is the single source of truth referenced by all other mapper functions
All field keys are validated to be non-empty and unique at compile time or via an assertion test
Sections cover at minimum: demographic categories (age, gender), activity types, geographic distribution, and any other sections present in the current Bufdir reporting form
Norwegian labels are verbatim copies of the official Bufdir form text — no paraphrasing
No business logic or data transformation exists in this file — constants only

Technical Requirements

frameworks
Dart
Flutter
data models
BufdirFieldDefinition
BufdirFormSection
performance requirements
Constants are compile-time or initialised once at app start — no runtime overhead

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use Dart sealed classes for BufdirFormSection if Dart 3+ is available, otherwise use an abstract class with private subclasses. Keep BufdirFieldDefinition as a simple immutable data class (`@immutable`, const constructor). Place all constants in a single file `bufdir_form_constants.dart` — do not scatter across multiple files. Obtain the official Bufdir reporting form from the project's documentation or directly from Bufdir to ensure label accuracy.

Add a comment referencing the source document version so future maintainers know when to update.

Testing Requirements

Unit tests asserting: all field keys are unique across the full kBufdirSections list; no section has an empty fields list; every BufdirFieldDefinition.bufdirLabel is non-empty; kBufdirSections is non-empty and ordered (index 0 = first Bufdir section). These tests act as a regression guard so that accidental edits to constants are immediately caught.

Component
Bufdir Report Structure Mapper
service 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.