critical priority low complexity infrastructure pending backend specialist Tier 0

Acceptance Criteria

LabelKeyRegistry is declared as an abstract class with a private constructor to prevent instantiation
All constants are `static const String` — no instance fields, no methods, no logic
Constants are grouped into nested abstract classes by domain: Auth, Activity, Contacts, Navigation, Errors, UserRoles, Organizations (minimum domains)
Each constant value uses dot-notation matching the JSONB key path in organization_configs (e.g., `'activity.type.peer_support'`)
All four organizations' label keys are represented: NHF, Blindeforbundet, HLF, Barnekreftforeningen
No two constants share the same string value — all keys are unique
File compiles with zero warnings under `dart analyze`
A companion `all_keys_test.dart` verifies uniqueness: loads all constants reflectively (or via generated set) and asserts no duplicates
Naming convention is consistent: `domain.subdomain.specific_term` in snake_case dot-notation
File is located at `lib/core/labels/label_key_registry.dart`

Technical Requirements

frameworks
Flutter
Dart
data models
organization_configs (Supabase JSONB structure — keys must match this schema)
performance requirements
Zero runtime cost — all constants resolved at compile time
No dynamic map lookups in this class
security requirements
No sensitive data as constant values — keys only, never label content
Class must not expose any organization-specific configuration logic

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use nested abstract classes (not enums) to group constants because enums add `.name`/`.index` overhead and cannot hold arbitrary String values cleanly in all Dart versions. Example structure: `abstract class LabelKeyRegistry { abstract class Activity { static const String typeLabel = 'activity.type_label'; static const String durationLabel = 'activity.duration_label'; } }`. The dot-notation values must exactly mirror the JSONB key paths stored in Supabase `organization_configs.labels` — coordinate with the backend schema before finalizing keys. Add a top-level file comment listing the four organizations and the expected JSONB structure shape, so future developers understand the contract.

Keep this file as a pure data file — if business logic creeps in, it belongs in LabelKeyResolver instead.

Testing Requirements

Write a single Dart unit test file `label_key_registry_test.dart`. Test 1: assert that every constant value is non-empty and non-null. Test 2: collect all constant values into a List and assert `list.length == list.toSet().length` (no duplicates). Test 3: assert every constant value matches the regex `^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$` (valid dot-notation).

Since Dart does not support runtime reflection in Flutter, use a code-generated or manually maintained `Set allKeys` in a test helper to collect all constants for validation.

Component
Label Key Registry
infrastructure low
Epic Risks (2)
high impact medium prob integration

The labels JSONB column in organization_configs may lack a consistent schema across organizations, causing deserialization failures or silent missing keys when a new organization is onboarded with a differently structured map.

Mitigation & Contingency

Mitigation: Define and enforce a canonical JSONB schema via a Supabase check constraint and a migration script. Validate the schema in TerminologyRepository at parse time and emit structured errors for any key-type mismatches.

Contingency: If schema drift is discovered post-deployment, LabelKeyResolver's fallback logic ensures the app continues to function with English defaults while a data migration is prepared to normalize the offending organization's config.

medium impact low prob technical

Device local storage corruption or platform-specific SharedPreferences serialization bugs could render a cached terminology map unreadable, causing the app to fall back to English defaults unexpectedly for an organization with custom terminology.

Mitigation & Contingency

Mitigation: Wrap all cache reads in try/catch, validate the deserialized map against a minimum-required-keys check, and evict corrupted entries automatically before re-fetching from Supabase.

Contingency: Surface a non-blocking in-app warning to the coordinator that terminology may be in default English until the next sync completes; trigger an immediate background sync.