Define LabelKeyRegistry Dart abstract class
epic-dynamic-terminology-and-labels-foundation-task-001 — Create the LabelKeyRegistry as a Dart abstract class containing only static const String fields grouped by domain (auth, activity, contacts, navigation, errors, etc.). Each constant holds a dot-notation key string matching the JSONB column structure in organization_configs. No logic, no constructors — purely a compile-time registry that prevents key-typo bugs across all four partner organizations.
Acceptance Criteria
Technical Requirements
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
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.
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.