Implement Role Resolution Service Post-Login Flow
epic-role-based-access-control-state-and-services-task-004 — Build the RoleResolutionService that orchestrates the post-authentication role determination flow: invoke RoleRepository to fetch all roles for the authenticated user, determine the primary role using precedence rules (coordinator > peerMentor), call RoleStateManager.setActiveRole() with the primary role, and store all available roles for multi-role users to enable role switching. Handle the case where globalAdmin users on mobile are blocked immediately.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Define a sealed class RoleResolutionResult with subtypes: RoleResolved(primaryRole, availableRoles), GlobalAdminBlocked, NoRoleAssigned, RoleResolutionError(message). Precedence map should be a const Map
Testing Requirements
Unit tests using flutter_test and mocktail: mock RoleRepository to return various role combinations (single peerMentor, single coordinator, both, globalAdmin only, empty). Assert correct primary role selection and that setActiveRole is called with expected argument. Assert globalAdmin path returns blocked result without calling setActiveRole. Integration test: spin up local Supabase emulator, seed a user with known roles, run resolveRoles and assert RoleStateManager state.
Target 90%+ line coverage of RoleResolutionService.
A coordinator's permissions could be revoked by an admin while they are actively using the app. If the permission checker relies solely on the cached role state from login, the coordinator could continue performing actions they are no longer authorized for until the next login.
Mitigation & Contingency
Mitigation: The Permission Checker Service must re-validate against the Role Repository (not just in-memory state) before high-impact actions. Implement a configurable staleness window (e.g., 15 minutes) after which role data is refreshed from Supabase in the background.
Contingency: If a revoked permission is detected during a pre-action check, immediately clear the cached role state, force a re-resolution from Supabase, and display an inline error explaining the permission change rather than crashing or silently failing.
Using both BLoC and Riverpod in the same state management layer for roles risks state synchronization bugs where one system updates before the other, causing widgets to render with stale role data during the switch transition.
Mitigation & Contingency
Mitigation: Choose a single primary state management approach (Riverpod StateNotifier is recommended) for role state and wrap the BLoC pattern within it if legacy code requires BLoC interfaces. Establish a single source-of-truth provider that all consumers read from.
Contingency: If synchronization bugs appear during integration testing, introduce a RoleStateReady gate widget that delays rendering of role-dependent UI until the state notifier emits a confirmed resolved state, preventing partial renders.
Hardcoded permission constants per role can become a maintenance burden as new features are added across 61 total features, leading to permission definitions that are scattered, stale, or inconsistent.
Mitigation & Contingency
Mitigation: Centralize all role-permission mappings in a single RolePermissions constants file with named action keys. Enforce that no widget or service directly checks role type strings; all checks must go through the Permission Checker Service.
Contingency: If permission definitions drift out of sync, introduce a validation test suite that cross-references all registered permission constants against their usage sites and fails the CI build if an undefined permission key is referenced.