critical priority high complexity integration pending integration specialist Tier 6

Acceptance Criteria

On successful login, AccessScopeService.computeScope() is called and the resulting unit_ids list is injected into the active Supabase JWT via RlsPolicyManager.refreshSessionClaims()
When UnitAssignmentService emits AssignmentChanged, the integration layer triggers both AccessScopeService cache invalidation and RlsPolicyManager.refreshSessionClaims() within 500ms
A coordinator whose JWT contains unit_ids = ['unit-A', 'unit-B', 'unit-C'] cannot retrieve any row from any table where organization_unit_id is not in that list — verified by attempting a direct Supabase query bypassing service layer
A national admin with isNationalAdmin=true in JWT claims receives all rows across the organization without unit filtering
Session-level scope cache is populated on login and survives app backgrounding without requiring a new network call on foreground
Cache is fully cleared on sign-out; subsequent login as a different user starts with a fresh empty cache
Claim refresh failures are logged and surfaced as a non-blocking warning in the UI — they do not crash the session but trigger a retry after 5 seconds
End-to-end test: assign coordinator to chapter X → log in → attempt query for chapter Y data → receives zero rows

Technical Requirements

frameworks
Flutter
Dart
Riverpod
Supabase Edge Functions (Deno)
apis
Supabase Auth API
Supabase PostgreSQL 15 RLS
Supabase Edge Functions REST API
data models
assignment
contact_chapter
activity
contact
performance requirements
Post-login scope injection (computeScope + refreshSessionClaims) completes within 2 seconds before the home screen is shown
Post-assignment claim refresh completes within 2 seconds of AssignmentChanged event
Cache hit for scope read adds under 5ms overhead to any data query
security requirements
JWT unit_ids claim is set exclusively by the server-side Edge Function using the service role key — client cannot manipulate claims
RLS policies enforce unit filtering at the database level as the final backstop — even if Flutter service layer is bypassed, data is protected
Tokens stored in flutter_secure_storage — never plaintext SharedPreferences
Refresh tokens rotated on each use per Supabase Auth security model
Scope cache cleared on logout to prevent data leakage between users on shared devices
All Edge Function inputs validated for organization_id match against calling user's JWT before any claim update

Execution Context

Execution Tier
Tier 6

Tier 6 - 158 tasks

Can start after Tier 5 completes

Implementation Notes

Create an AuthSessionCoordinator class that is initialized at app startup (Riverpod app-level provider) and owns the wiring between auth, scope, and RLS. It listens to three streams: Supabase auth state changes (sign in/out), UnitAssignmentService.assignmentChangedStream, and a periodic token refresh timer (every 45 minutes as a safety net). On sign-in: await AccessScopeService.computeScope() then await RlsPolicyManager.refreshSessionClaims(). On AssignmentChanged: call both in sequence.

On sign-out: call AccessScopeService.clearCache() and RlsPolicyManager.clearCache(). The coordination between task-009 and task-006 is exactly this class — do not scatter the wiring across multiple widgets or BLoCs. For the retry-on-failure behavior, use an exponential backoff with a max of 3 retries before surfacing the warning. The Supabase Edge Function (update-jwt-claims) called by RlsPolicyManager should accept a trigger_type parameter ('login' | 'assignment_change') for server-side logging and audit purposes.

This is especially important for GDPR compliance given that scope changes affect what personal data (contacts, activities) is accessible.

Testing Requirements

Integration tests against a local Supabase instance with real RLS policies active: (1) login as coordinator assigned to unit-A → query activities filtered to unit-B → assert empty result; (2) login as national admin → query all activities → assert all returned; (3) trigger assignment change → assert JWT refreshed within 2s → query new unit data → assert visible. Unit tests for the wiring layer: mock AccessScopeService and RlsPolicyManager, assert refreshSessionClaims is called on login and on AssignmentChanged. Test retry logic for claim refresh failure. Use flutter_test and integration_test package.

Security regression test: hardcode a JWT with fabricated unit_ids claim and attempt a direct Supabase query — assert RLS blocks it (proves server-side enforcement).

Component
Access Scope Service
service high
Epic Risks (3)
high impact medium prob security

If the AccessScopeService and the Supabase RLS policies use different logic to determine accessible units, a coordinator could see data in the client that RLS blocks server-side, causing confusing empty states, or worse, RLS could block data the scope service declares accessible.

Mitigation & Contingency

Mitigation: Define the canonical scope computation in a single Supabase Postgres function shared by both the RLS policies and the RPC endpoint called by AccessScopeService. The client-side service calls this RPC rather than reimplementing the logic, ensuring a single source of truth.

Contingency: Add integration tests that execute the same access decision through both the RLS policy path and the AccessScopeService path and assert identical results. Use these as regression guards in the CI pipeline.

medium impact medium prob integration

When a user switches active chapter via the ChapterSwitcher, widgets that are already built may not receive the context-change event if they subscribe incorrectly to the ActiveChapterState BLoC, leading to stale data being displayed under the new chapter context.

Mitigation & Contingency

Mitigation: Use Riverpod's ref.watch on the active chapter provider at the root of each scoped data subtree rather than at individual leaf widgets. Trigger a global data refresh by invalidating all scoped providers when the chapter changes.

Contingency: Add an app-level chapter-change listener that forces a full navigation stack reset to the home screen on chapter switch, guaranteeing all widgets rebuild from scratch with the new context. Accept the UX cost of navigation reset for correctness.

medium impact medium prob scope

Non-technical organization administrators may find the hierarchy management interface too complex for the structural changes they need to make frequently (e.g., chapter renaming, coordinator reassignment), leading to low adoption and continued reliance on manual processes.

Mitigation & Contingency

Mitigation: Conduct usability testing with at least one NHF administrator before finalizing the admin portal screen layout. Prioritize the most common operations (rename, reparent, add child) as primary actions in the UI. Include inline help text and confirmation dialogs with plain-language descriptions of consequences.

Contingency: Provide a simplified 'quick edit' mode that exposes only the three most common operations (rename, deactivate, add child) and hides advanced structural operations behind an 'Advanced' toggle.