high priority low complexity backend pending backend specialist Tier 2

Acceptance Criteria

BufdirCategory enum values use stable snake_case machine-readable keys (e.g., individual_guidance, group_activity, phone_support) that exactly match the CHECK constraint values defined in the database migration (task-001)
A bufdirCategoryLabels constant map (Map<BufdirCategory, String>) provides Norwegian display labels for every enum value
Labels are human-readable Norwegian strings suitable for display in coordinator-facing UI (e.g., 'Individuell veiledning', 'Gruppeaktivitet')
A bufdirCategorySortedList constant (List<BufdirCategory>) provides all values in a deterministic alphabetical-by-label order for consistent dropdown rendering
BufdirCategory.toDbString() (or equivalent) returns the stable snake_case key for serialisation — this method must NOT use the enum's .name to avoid breakage if enums are renamed
BufdirCategory.fromDbString(String value) factory returns the correct enum value or throws a descriptive ArgumentError for unknown strings
The set of enum values is in sync with the database CHECK constraint from task-001 — a unit test asserts that every enum value has a valid toDbString() that would pass the database constraint
No localisation keys are used for labels — Norwegian strings are hardcoded since Bufdir reporting is Norway-specific and labels must be stable for regulatory submission
The file is importable by both the model (task-002) and the form screen (task-004) without circular dependencies

Technical Requirements

frameworks
Dart
Flutter
apis
Bufdir reporting requirements (category taxonomy)
data models
BufdirCategory (referenced by ActivityType model from task-002)
performance requirements
bufdirCategorySortedList is a compile-time constant or computed once at startup — not recomputed on each dropdown build
security requirements
Category values sent to Supabase must be the stable toDbString() output — never the Dart enum .name which is refactor-sensitive
ui components
DropdownButton<BufdirCategory>
DropdownMenuItem<BufdirCategory>

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Obtain the official Bufdir category taxonomy from project documentation or client — do not invent categories. If the taxonomy is not yet available, define a placeholder enum with a clear TODO comment and a unit test that will fail until all values are confirmed. Use an extension method on BufdirCategory for toDbString() and a static helper for fromDbString() — this is cleaner than switch statements in the model class. Sort bufdirCategorySortedList by label using Norwegian locale-aware comparison if Dart's Intl package is available; otherwise standard alphabetical is acceptable for initial implementation.

Place this file at lib/constants/bufdir_categories.dart or alongside the model in lib/models/bufdir_category.dart — follow project conventions.

Testing Requirements

Write unit tests in test/models/bufdir_category_test.dart: (1) every BufdirCategory enum value has a non-null, non-empty entry in bufdirCategoryLabels; (2) bufdirCategorySortedList contains every enum value exactly once; (3) bufdirCategorySortedList is sorted by label alphabetically (Norwegian collation); (4) fromDbString correctly round-trips every toDbString() value; (5) fromDbString throws ArgumentError for an unknown string; (6) toDbString() returns a snake_case string matching the exact CHECK constraint values from the database migration. Run these tests in CI to catch any drift between the Dart enum and the database constraint.

Component
Activity Type Form Screen
ui medium
Epic Risks (3)
high impact medium prob dependency

The Bufdir reporting category list is defined externally by Bufdir and may change between reporting years. If the dropdown in ActivityTypeFormScreen is hardcoded, existing activity type mappings could become invalid after a Bufdir schema update, breaking export validation for all organisations.

Mitigation & Contingency

Mitigation: Store the valid Bufdir category list in a Supabase configuration table (bufdir_categories) rather than as a Dart constant, so it can be updated by an admin without a mobile app release. Load the list in the form screen via a lightweight repository call cached locally.

Contingency: If the Bufdir category list cannot be externalised before the admin screen ships, expose a manual override field that allows coordinators to enter a raw Bufdir category code as a fallback, and schedule the configuration table migration as a follow-up task.

medium impact medium prob technical

Reusing ActivityTypeFormScreen for both creation and editing requires careful Riverpod provider scoping. If the form provider is not properly reset between navigation events, stale values from a previously edited type may pre-populate a new creation form, leading to incorrect data being saved.

Mitigation & Contingency

Mitigation: Scope the form state provider to the route using Riverpod's autoDispose modifier, ensuring the state is torn down when the screen is popped. Write a widget test that navigates to edit type A, pops, navigates to create new, and asserts all fields are empty.

Contingency: If provider scoping proves complex with the current router setup, fall back to separate widget implementations for create and edit that share a common form widget but maintain independent provider instances.

high impact low prob integration

Archiving an activity type must not break historical Bufdir export queries that filter activities by type. If the export pipeline performs an INNER JOIN against only active activity types, archived types will cause historical activities to be silently excluded from exports, producing incorrect reporting data.

Mitigation & Contingency

Mitigation: Audit all downstream query builders (Bufdir export, stats aggregation) before shipping the archive feature to confirm they join against all activity types regardless of is_active status. Add an integration test that archives a type, then asserts historical activity records for that type still appear in export queries.

Contingency: If a downstream query is discovered to filter on is_active post-launch, apply a targeted Supabase view fix that unions active and archived types for export contexts without requiring a mobile app update.