Implement atomic batch insert via repository in BulkRegistrationService
epic-proxy-activity-registration-orchestration-task-009 — For the approved participants, apply ActivityAttributionService to each record, then submit the full set as a single atomic batch transaction via ProxyActivityRepository's batch-insert method. The entire batch must succeed or fail atomically — no partial commits. On success return BulkRegistrationSuccess with the committed record count. On failure, return BulkRegistrationError with the repository exception mapped to a user-readable error type.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 10 - 11 tasks
Can start after Tier 9 completes
Implementation Notes
Implement BulkRegistrationService as a plain Dart class injected via Riverpod provider. The core method signature should be: `Future
Pass the resulting list directly to `repository.batchInsert()`. Define a BulkErrorType enum (networkError, permissionDenied, duplicateConflict, unknown) and map PostgrestException status codes to it inside a private `_mapException()` helper. Do not catch errors in the loop — let them propagate to the single top-level try/catch. The Supabase RPC function (defined separately) should use a BEGIN/EXCEPTION/END block to guarantee atomicity at the database level.
Testing Requirements
Unit tests (covered in task-011) must mock ProxyActivityRepository and ActivityAttributionService via mocktail. Integration test (optional, lower priority): spin up a local Supabase instance and verify that a batch of 5 records either all appear or none appear after a simulated mid-insert failure. Test coverage target: 100% of public method branches in BulkRegistrationService. Specific scenarios: full happy path, empty list, repository exception, attribution service throwing mid-loop.
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.