high priority low complexity frontend pending frontend specialist Tier 3

Acceptance Criteria

ClaimStatusBadge accepts ClaimStatus enum and renders correct color: draft=grey, submitted=blue, pending_approval=amber, approved=green, rejected=red, exported=purple
All colors meet WCAG 2.2 AA contrast ratio (≥ 4.5:1) against both light and dark theme backgrounds — verified with contrast checker
Optional size parameter accepts BadgeSize.small / BadgeSize.medium / BadgeSize.large with corresponding padding and font size variants
Semantics widget wraps the badge with label: 'Claim status: {status display name}' — verified with Flutter accessibility inspector
Badge text displays human-readable status name in English (e.g., 'Pending Approval' not 'pending_approval')
Widget is stateless — no internal state management
Exported from lib/shared/widgets/widgets.dart barrel file with named export
Works correctly in both light and dark theme — color scheme adapts via design token system not hardcoded hex values
Renders correctly at all three sizes in a golden test snapshot
ExcludeSemantics is NOT used — badge must be readable by VoiceOver/TalkBack

Technical Requirements

frameworks
Flutter (StatelessWidget)
Flutter Semantics API
data models
claim_event (ClaimStatus enum source)
performance requirements
Widget build time < 1ms — purely decorative, no async operations
const constructor supported for compile-time optimization
security requirements
No user data rendered beyond status label — no PII leakage risk
ui components
Container with BoxDecoration (borderRadius, color)
Text widget with design token typography
Semantics wrapper with descriptive label
BadgeSize enum (small, medium, large)

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Use a static const Map inside the widget to map statuses to design token color references — never hardcode hex values directly. Reference the organization's design token system (colors, typography, spacing, radii) as established in the shared design token constants. For the badge shape, use Container with BorderRadius.circular(design_tokens.radiusFull). The BadgeSize enum should drive a corresponding Map for padding and Map for font.

Place the file at lib/shared/widgets/claim_status_badge.dart and add the export to the barrel. The accessibility requirement is critical given Blindeforbundet (screen reader) users — test with TalkBack simulator.

Testing Requirements

Widget tests using flutter_test: (1) render each of 6 ClaimStatus variants and verify correct background color via find.byType(Container).first decoration, (2) verify Semantics node label matches 'Claim status: {name}' for each status, (3) golden snapshot tests for all 3 badge sizes × 2 themes (light/dark) = 6 golden files, (4) verify const constructor compiles without error. Run flutter_test with accessibility audit (SemanticsController) to confirm no accessibility violations. No mocking required — pure widget rendering.

Component
Claim Status Badge
ui low
Epic Risks (3)
medium impact medium prob technical

Optimistic locking in ExpenseClaimStatusRepository may produce excessive concurrency exceptions in high-volume coordinator sessions where multiple coordinators process the same queue simultaneously, causing confusing UI errors and coordinator frustration.

Mitigation & Contingency

Mitigation: Design the locking strategy with a short retry window (1-2 automatic retries with 200ms back-off) before surfacing the error to the UI. Document the concurrency model clearly so the UI layer can display a contextual 'claim was already actioned' message rather than a generic error.

Contingency: If contention remains high under load testing, switch to a last-writer-wins update with a conflict notification rather than a hard block, and log all concurrent edits for audit purposes.

medium impact medium prob integration

FCM device tokens stored for peer mentors may be stale (app reinstalled, token rotated) causing push notifications for claim status changes to silently fail, leaving submitters unaware their claim was approved or rejected.

Mitigation & Contingency

Mitigation: Implement token refresh on every app launch and store updated tokens in Supabase. ApprovalNotificationService should fall back to in-app Realtime delivery when FCM returns an invalid-token error and should queue a token refresh request.

Contingency: If FCM delivery rates fall below acceptable thresholds in production monitoring, add a polling fallback in the peer mentor claim list screen that checks status on foreground resume.

high impact low prob dependency

Supabase Realtime has per-project channel and connection limits. If many coordinators and peer mentors are simultaneously subscribed across multiple screens, the project may hit quota limits causing subscription failures.

Mitigation & Contingency

Mitigation: Design RealtimeApprovalSubscription to use a single shared channel per user session rather than per-screen subscriptions. Implement subscription reference counting so channels are only opened once and reused across screens.

Contingency: Upgrade the Supabase plan tier if limits are reached, and implement graceful degradation to polling with a 30-second interval when Realtime is unavailable.