critical priority low complexity backend pending backend specialist Tier 7

Acceptance Criteria

ProxyRegistrationService.registerProxyActivity() calls coordinatorRoleGuard.requireCoordinator() as its absolute first statement before any other logic
When requireCoordinator() throws InsufficientPermissionsException, the service method immediately propagates it — no swallowing, no wrapping in a generic error
The returned ProxyRegistrationError (for non-authorization failures) uses ProxyRegistrationErrorCode.unauthorized specifically when an authorization failure is caught
No downstream service (repository, RPC, duplicate checker) is invoked when the guard throws
ProxyRegistrationService accepts CoordinatorRoleGuard via constructor injection (not as a static global) to support testing
The service is a plain Dart class registered as a Riverpod Provider, with CoordinatorRoleGuard injected via the Riverpod ref in the provider factory
Unit test verifying that a non-coordinator call never reaches the repository mock (mockito verify(repo, never()).insertProxyActivity(...))
Integration with the result contract: successful guard pass continues to return ProxyRegistrationResult variants as defined in task-001

Technical Requirements

frameworks
Flutter
Riverpod
Dart
data models
ProxyRegistrationRequest
ProxyRegistrationResult
ProxyRegistrationErrorCode
CoordinatorRoleGuard
InsufficientPermissionsException
performance requirements
Guard check must be synchronous (ref.read) — no awaiting auth state on the hot path of each service call
Service method must not hold any locks or resources if it short-circuits on authorization failure
security requirements
Guard check must never be placed inside a conditional or try/catch that could silence the exception — it must be unconditional and at the top of the method
Service must not cache the result of the guard check between calls — re-evaluate on every invocation to handle mid-session role changes
The guard check must run server-side (Supabase RLS) as a secondary enforcement layer — the client-side guard is defence-in-depth, not the sole control

Execution Context

Execution Tier
Tier 7

Tier 7 - 84 tasks

Can start after Tier 6 completes

Dependencies (10)
epic-proxy-activity-registration-core-services-task-001 component Cross-Epic Component proxy-registration-service depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-002 component Cross-Epic Component proxy-registration-service depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-003 component Cross-Epic Component proxy-registration-service depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-008 component Cross-Epic Component proxy-registration-service depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-004 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-005 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-006 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-007 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-009 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-010 component Cross-Epic Component proxy-registration-service depends on activity-attribution-service
Dependents (18)
epic-proxy-activity-registration-ui-task-001 component Cross-Epic Component bulk-participant-list depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-002 component Cross-Epic Component bulk-participant-list depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-003 component Cross-Epic Component bulk-participant-list depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-004 component Cross-Epic Component duplicate-warning-dialog depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-005 component Cross-Epic Component duplicate-warning-dialog depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-006 component Cross-Epic Component duplicate-warning-dialog depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-007 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-008 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-009 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-010 component Cross-Epic Component proxy-activity-form depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-011 component Cross-Epic Component proxy-activity-form depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-012 component Cross-Epic Component proxy-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-013 component Cross-Epic Component proxy-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-014 component Cross-Epic Component proxy-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-015 component Cross-Epic Component bulk-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-016 component Cross-Epic Component bulk-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-017 component Cross-Epic Component bulk-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-ui-task-018 component Cross-Epic Component proxy-registration-bloc depends on proxy-registration-service

Implementation Notes

Inject CoordinatorRoleGuard into ProxyRegistrationService via the constructor: class ProxyRegistrationService { ProxyRegistrationService(this._guard, this._repository); ... }. In the Riverpod provider factory, read both dependencies via ref.watch/ref.read. The first line of registerProxyActivity() should be: _guard.requireCoordinator(); — no if-statement wrapper.

This keeps the authorization intent explicit and grep-able. Use a try/catch block below the guard call to catch repository/network exceptions and map them to ProxyRegistrationError variants — but specifically do NOT catch InsufficientPermissionsException there, letting it propagate up to the BLoC where it will be mapped to an unauthorized UI state. Document this exception propagation contract in a code comment above the method signature to guide future maintainers.

Testing Requirements

Unit tests using flutter_test with mockito. Test matrix: (1) coordinator role — guard does not throw, service proceeds to call repository mock, result is ProxyRegistrationSuccess; (2) peer_mentor role — guard throws InsufficientPermissionsException, repository mock is never called (verified with Mockito verify(repo, never())), exception propagates to caller; (3) org_admin role — same as peer_mentor; (4) guard throws InsufficientPermissionsException mid-execution (simulated role expiry) — verify no partial state is left. Also test that the service correctly maps a network failure from the repository into ProxyRegistrationError with error_code = network_failure (to confirm error mapping logic is in place for other codes).

Component
Proxy Registration Service
service medium
Epic Risks (3)
high impact low prob integration

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.

medium impact medium prob scope

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.

high impact low prob security

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.