high priority low complexity testing pending testing specialist Tier 2

Acceptance Criteria

Test: insertEvent() with valid ClaimEvent data returns ClaimEvent with server-assigned id and created_at
Test: update() throws UnsupportedError with message containing 'immutable' — verifies the repository enforces append-only semantics
Test: delete() throws UnsupportedError with message containing 'immutable' — audit log must never be deleted
Test: getEventsForClaim(claimId) returns events ordered by created_at ascending
Test: insertEvent() with duplicate event id propagates SupabaseException mapped to ClaimEventConflictError domain error
Test: insertEvent() with foreign key violation (non-existent claim_id) maps to ClaimNotFoundError
Test: getEventsForClaim() with no events returns empty list (not null, not error)
All 7 test cases pass with flutter_test runner
Code coverage report shows 100% branch coverage for ClaimEventsRepository class
Mock Supabase client used — no real network calls in any test

Technical Requirements

frameworks
flutter_test
mockito or mocktail (Dart mock generation)
apis
Supabase PostgREST — mocked insert, select operations on claim_events table
data models
claim_event (id, expense_claim_id, actor_id, actor_role, from_status, to_status, created_at)
performance requirements
All unit tests complete in < 5 seconds total — no real I/O allowed
security requirements
Test fixtures must not contain real personnummer, real user UUIDs from production, or real organization data

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

The core challenge is mocking Supabase's fluent builder API (e.g., supabase.from('claim_events').insert(data).select()). Use mocktail's when().thenReturn() on each chained method. Create a MockSupabaseClient that overrides the from() method to return a MockPostgrestBuilder. For the ordering test, the mock should return a pre-sorted list and verify that the repository does NOT re-sort (trusting the DB) OR return an unsorted list and verify the repository sorts — choose based on actual implementation.

The UnsupportedError tests are the most important: these guard the audit log's integrity. Document WHY these errors are intentional in the test description strings.

Testing Requirements

Pure unit tests in flutter_test. Use mocktail to mock the Supabase client's PostgrestBuilder chain (from(), insert(), select(), order()). Structure tests in a group('ClaimEventsRepository', ...) block with setUp() creating a fresh mock instance per test. Use throwsA(isA()) matcher for immutability tests.

Use equals() with ordered list matchers for event ordering tests. Run with --coverage flag and verify 100% branch coverage via lcov report. Place test file at test/infrastructure/repositories/claim_events_repository_test.dart.

Component
Claim Events Repository
data 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.