Implement conflict review gate and approved participant filtering in BulkRegistrationService
epic-proxy-activity-registration-orchestration-task-008 — After the duplicate detection loop, if any conflicts exist, return a BulkRegistrationConflictsDetected result containing the full BulkConflictSummary for coordinator review. When the coordinator approves the submission (passing the reviewed and approved set back), filter participants to only the approved entries before proceeding to the batch insert. This gate ensures no conflicting records are silently submitted.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 9 - 22 tasks
Can start after Tier 8 completes
Implementation Notes
Model the two-phase flow as two separate public methods on BulkRegistrationService: (1) checkAndPrepare(BulkRegistrationRequest) → BulkRegistrationResult (returns either ConflictsDetected or proceeds to insert if clean); (2) submitApproved(BulkRegistrationRequest, Set
Validate that approvedMentorIds is a subset of the original request's peer mentor IDs — reject any IDs not in the original request with an assertion or error result. For the batch insert, use a single Supabase RPC that accepts a JSON array of participant records and inserts them in one transaction — this is critical for Bufdir statistics accuracy (no partial batch counts).
Testing Requirements
Write unit tests using flutter_test with mocked BulkRegistrationRepository and ProxyDuplicateDetectionService. Required scenarios: (1) no conflicts → gate not triggered, proceeds directly to batch insert; (2) conflicts exist → BulkRegistrationConflictsDetected returned, insert not called; (3) coordinator approves subset → only approved participants passed to batch insert; (4) coordinator approves empty set → BulkRegistrationSuccess(committed_count: 0) returned, insert not called; (5) approved set contains ID not in original request → filtered out (security boundary test); (6) batch insert succeeds → BulkRegistrationSuccess with correct committed_count and activity IDs. Integration test: verify Supabase RPC is called exactly once with only the approved participant IDs.
If the Supabase batch RPC partial-inserts some records before encountering an error and does not roll back cleanly, the bulk service may report failure while orphaned records exist in the database, corrupting reporting data.
Mitigation & Contingency
Mitigation: Wrap the bulk insert in an explicit Supabase transaction via the RPC function. Write an integration test that simulates a mid-batch constraint violation and asserts zero records were written.
Contingency: If a partial-write incident occurs, the registered_by audit field allows identification and deletion of the orphaned records. Implement a coordinator-facing bulk submission status screen to surface any such anomalies.
When a bulk submission of 15 participants has 4 duplicates, the aggregated conflict summary may be too complex for coordinators to process quickly, leading to blanket override decisions that defeat the purpose of duplicate detection.
Mitigation & Contingency
Mitigation: Design the conflict result type to support per-participant override flags, so the UI can present a clear list of conflicting participants with individual cancel/override toggles rather than a single global decision.
Contingency: If coordinator usability testing reveals the conflict review screen is too complex, simplify to a 'skip all conflicts and submit the rest' mode as an immediate fallback while a more granular UI is designed.
If the coordinator role check inside proxy-registration-service is inconsistent with the route-level guard, a regression in the guard could allow peer mentors to call the service directly via deep links, submitting records with incorrect attribution.
Mitigation & Contingency
Mitigation: Enforce role authorization at both the route guard level (coordinator-role-guard) and inside each service method independently. Write a security test that calls the service directly with a peer mentor session token and asserts rejection.
Contingency: If a bypass is discovered, immediately enable the server-side RLS policy as the final enforcement layer and audit any records written during the exposure window using the registered_by field.