Implement Badge Definition Repository
epic-achievement-badges-ui-task-002 — Create the badge-definition-repository that loads static badge definitions (criteria, icon keys, tier thresholds, display names) from Supabase or a bundled configuration source. Implement caching to avoid repeated network calls and expose typed Dart models for all badge definition fields.
Acceptance Criteria
Technical Requirements
Implementation Notes
Use a simple Map
Expected columns: id (text PK), display_name (text), description (text), icon_key (text), tier_thresholds (jsonb), criteria (text), organization_scope (uuid, nullable). Register as a Riverpod Provider
Testing Requirements
Unit tests using flutter_test with mocked Supabase client and mocked AssetBundle. Test: (1) first call fetches from Supabase and populates cache, (2) second call returns cached data without contacting Supabase, (3) invalidateCache() followed by a call re-fetches from Supabase, (4) Supabase error triggers asset fallback and returns non-empty list, (5) fetchDefinitionById returns null for unknown ID without throwing, (6) organizationScope filtering excludes out-of-scope definitions. Verify all fields of BadgeDefinition are correctly parsed from both Supabase JSON and asset JSON.
The badge-earned-celebration overlay must appear within 2 seconds of the triggering activity being saved, but badge evaluation runs server-side in an edge function triggered by a database webhook. Network latency, edge function cold start, and Supabase Realtime delivery delays could cause the overlay to appear late or not at all, breaking the motivational loop.
Mitigation & Contingency
Mitigation: Implement an optimistic UI path: after activity save, badge-bloc immediately checks whether any badge thresholds are crossed client-side using cached stats and badge definitions, showing the overlay speculatively before server confirmation. The server result then reconciles. Subscribe to Supabase Realtime on the earned_badges table for authoritative confirmation.
Contingency: If Realtime delivery is unreliable in production, add a polling fallback: badge-bloc polls for new earned badges 3 seconds after an activity save and shows the overlay if a new record is detected, accepting up to 5-second latency as a fallback SLA.
The celebration overlay uses animation for positive reinforcement, but motion sensitivity (prefers-reduced-motion) and screen reader users require a non-animated or text-only alternative. Failing to handle this risks excluding Blindeforbundet users or triggering vestibular discomfort for motion-sensitive volunteers.
Mitigation & Contingency
Mitigation: Check MediaQuery.disableAnimations in badge-earned-celebration-overlay and skip animation entirely when true, showing a static card instead. Add an ExcludeSemantics wrapper around the decorative animation widget and a separate Semantics node with a live region announcement of the badge name and congratulatory message.
Contingency: If accessibility issues are identified in TestFlight testing with Blindeforbundet's test group, fast-track a patch that defaults to the static card path and gates the animation behind a user preference setting in notification preferences.