Implement Duplicate Check Repository
epic-duplicate-activity-detection-state-management-task-001 — Create the DuplicateCheckRepository data layer that queries the Supabase database for existing activities matching the same peer mentor, date, and activity type. Implement methods for fetching candidate duplicate records with relevant metadata needed for comparison UI.
Acceptance Criteria
Technical Requirements
Implementation Notes
Define a CandidateDuplicate value object (immutable, with `==` and `hashCode`) rather than reusing the general Activity model — duplicate detection needs a trimmed projection, and coupling to the full Activity model creates fragile dependencies. The Riverpod provider should be a `Provider
Use `const` constructors on CandidateDuplicate for efficient widget rebuilds downstream.
Testing Requirements
Write unit tests using flutter_test with a mocked Supabase client (implement a MockSupabaseClient satisfying the interface). Test cases: (1) single duplicate returned with correct fields mapped to CandidateDuplicate; (2) multiple duplicates returned sorted by activity_date desc; (3) empty list when no match; (4) cross-chapter duplicate included in results; (5) excludeActivityId filters out the matching ID; (6) PostgrestException from Supabase is wrapped in DuplicateCheckException; (7) null/empty peerMentorId throws ArgumentError before network call. Achieve 100% branch coverage on the repository class. Integration tests against a local Supabase instance (via supabase CLI `supabase start`) should cover the happy path and cross-chapter case with seeded data.
For bulk registration with many participants, running duplicate checks sequentially before surfacing the consolidated summary could introduce a multi-second delay as each peer mentor is checked individually against the RPC. This degrades the bulk submission UX significantly.
Mitigation & Contingency
Mitigation: Issue all duplicate check RPC calls concurrently using Dart's `Future.wait` or a bounded parallel executor (max 5 concurrent calls to avoid Supabase rate limits). The BLoC collects all results and emits a single BulkDuplicateSummary state with the consolidated list.
Contingency: If concurrent RPC calls hit Supabase connection limits or rate limits, implement a batched sequential approach with a progress indicator showing 'Checking participant N of M' so the coordinator understands the delay is expected and bounded.
In proxy registration, the peer mentor's ID must be used as the duplicate check parameter, not the coordinator's ID. If the proxy context is not correctly threaded through the BLoC and service layer, duplicate checks will silently run against the wrong person, missing actual duplicates.
Mitigation & Contingency
Mitigation: Define a `SubmissionContext` model that carries the effective `peer_mentor_id` (distinct from `submitter_id`) and pass it explicitly through the BLoC event payload. The DuplicateDetectionService always reads peer_mentor_id from SubmissionContext, never from the authenticated user session.
Contingency: If SubmissionContext threading proves difficult to retrofit into the existing proxy registration BLoC, add an assertion in DuplicateDetectionService that throws a descriptive error when peer_mentor_id is null or matches the coordinator's own ID in a proxy context, making the bug immediately visible in testing.