Implement single-record duplicate detection query
epic-proxy-activity-registration-core-services-task-002 — Implement the core query method on proxy-duplicate-detection-service that accepts a composite key (peer_mentor_id, date, activity_type_id) and returns all non-voided activity records matching that key regardless of submitter. The result must include structured conflict metadata: original submitter user ID, submission timestamp, and the conflicting record reference. This method is the primary guard against double-counting in Bufdir compliance reports.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Implement as a concrete class SupabaseDuplicateDetectionService implementing IDuplicateDetectionService. Inject the Supabase client via constructor for testability. The Supabase query should look like: supabase.from('activities').select('id, registered_by, created_at').eq('attributed_to', request.peerMentorId).eq('activity_date', request.date.toIso8601String().substring(0,10)).eq('activity_type_id', request.activityTypeId).neq('status', 'voided'). Confirm the exact table and column names against the Supabase schema before writing queries.
Date handling is critical — normalize to UTC date string before comparison to avoid timezone drift. Register the service via Riverpod Provider so BLoC layers can inject it. Keep this class thin: no business logic beyond mapping Supabase rows to DuplicateConflictResult DTOs.
Testing Requirements
Unit tests with mocked Supabase client covering: no conflicts found (empty list), single conflict found, multiple conflicts found, voided record correctly excluded, network timeout throws DuplicateDetectionException, date boundary cases (activity on same date but different time still matches). Integration test against a Supabase test project verifying the actual query filters work correctly end-to-end. Use flutter_test with mockito or mocktail for unit layer. Minimum 85% branch coverage.
Overly strict duplicate matching (exact date + type) may flag legitimate back-to-back sessions of the same activity type on the same day as duplicates, frustrating coordinators and undermining trust in the feature.
Mitigation & Contingency
Mitigation: Confirm with product owners whether the matching key should be (mentor_id, date, activity_type_id) only or should also consider duration and time-of-day. Document the chosen threshold in the service and surface it in the duplicate warning dialog for transparency.
Contingency: If false-positive rates are high in user testing, add a duration-window tolerance parameter to the detection query that can be tuned without code changes.
If the current session token is invalidated between the coordinator starting the proxy form and submitting it, the activity-attribution-service may fail to resolve the coordinator's user ID, causing a silent attribution error.
Mitigation & Contingency
Mitigation: Read the coordinator's user ID from the session at service call time rather than at form-open time. Validate the session is still active before committing the insert, and surface a clear re-authentication prompt if it has expired.
Contingency: If a mis-attributed record is detected post-submission, the audit log retains the original session metadata, allowing a corrective record to be created with accurate attribution.