Implement CoordinatorRoleGuard
epic-proxy-activity-registration-foundation-task-009 — Implement `CoordinatorRoleGuard` as a Riverpod provider that reads the current user's role from the session/role state and exposes `requireCoordinator()` which throws `InsufficientPermissionsException` when the role is not coordinator. Also expose `isCoordinator` bool stream. Wire into route guards and repository call sites.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Use a Riverpod Provider
Define InsufficientPermissionsException in a shared exceptions file to keep it reusable across guards. When wiring route guards, use GoRouter's redirect callback with a ref.read(coordinatorRoleGuardProvider).isCoordinatorSync getter to keep routing logic simple. Avoid duplicating the guard logic in the UI layer — the BLoC/service should throw and the UI should catch.
Testing Requirements
Unit tests using flutter_test with a ProviderContainer and mock auth state notifier. Test matrix: (1) user with coordinator role — requireCoordinator() does not throw, isCoordinator emits true; (2) user with peer_mentor role — requireCoordinator() throws InsufficientPermissionsException, isCoordinator emits false; (3) user with org_admin role — same as peer_mentor; (4) unauthenticated / null session — requireCoordinator() throws, isCoordinator emits false; (5) role change mid-session — isCoordinator stream emits correct new value. Route guard wiring covered by widget tests that attempt navigation to a coordinator-only route as a non-coordinator and assert redirect to no-access screen.
The activities table migration adding registered_by and attributed_to columns may conflict with existing RLS policies or FK constraints if the user profile table structure differs from assumptions, blocking all subsequent epics.
Mitigation & Contingency
Mitigation: Review existing activities table schema and RLS policies before writing the migration. Run the migration against a staging database clone first. Write rollback scripts alongside the migration.
Contingency: If migration fails in staging, isolate the conflict with a targeted schema audit, adjust FK references or RLS policy scope, and re-run before touching production.
The RLS policy must filter proxy inserts to the coordinator's chapter scope. If the chapter-scope resolver pattern differs between organisations (multi-chapter coordinators in NHF vs single-chapter in HLF), the policy may be too broad or too restrictive.
Mitigation & Contingency
Mitigation: Design the RLS policy to accept a coordinator's full set of assigned chapter IDs (array) rather than a single chapter_id. Validate the policy against NHF multi-chapter test fixtures during the integration test phase.
Contingency: If the policy is found to be incorrect after deployment, introduce a server-side validation edge function as a safety net while the RLS policy is corrected.
The bulk_register_activities RPC function may time out or cause lock contention when inserting large participant batches (e.g. 40+ peer mentors in a single group session), degrading the user experience.
Mitigation & Contingency
Mitigation: Benchmark the RPC function with 50-participant batches during development. Use unnest-based bulk insert rather than row-by-row PL/pgSQL loops. Set a reasonable statement_timeout.
Contingency: If performance is insufficient, split the client-side submission into chunks of 20 participants with progress feedback, rather than a single RPC call.