Author RLS policies for mentor status fields
epic-peer-mentor-pause-foundation-task-003 — Write and review Supabase Row Level Security policies for the new status, pause_at, and pause_reason columns on peer_mentors and for the peer_mentor_status_history table. Coordinators may read and update status for mentors within their chapter; peer mentors may read their own status but not write it directly. Validate policies cover all CRUD paths.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Use Supabase's built-in auth.uid() and auth.jwt() functions in policy expressions rather than custom functions to ensure compatibility with Supabase Auth token format. The coordinator chapter membership check should be written as: EXISTS (SELECT 1 FROM contact_chapter cc WHERE cc.contact_id = auth.uid() AND cc.organization_unit_id = peer_mentors.chapter_id). If the peer_mentors table does not have a direct chapter_id, resolve it through the assignments table. For the pause_reason visibility restriction, use a column-level security approach: create a separate restrictive policy on the column if PostgreSQL column-level security is available, or use a security-definer view that excludes pause_reason for the mentor role.
Document the chosen approach clearly since column-level RLS in PostgreSQL requires GRANT/REVOKE on individual columns which interacts with PostgREST's schema reflection.
Testing Requirements
Write a SQL-based policy test script (compatible with pgTAP or manual psql execution) that: (1) simulates a peer mentor JWT and asserts they can SELECT their own status but cannot UPDATE it, (2) simulates a coordinator JWT and asserts they can UPDATE status for an in-chapter mentor but receive 0 rows updated for an out-of-chapter mentor, (3) simulates an anon JWT and asserts zero rows returned from both tables, (4) simulates a service-role client and asserts all operations succeed. Also write a Dart integration test using the Supabase Flutter SDK that attempts an unauthorised status UPDATE from a mentor-role client and asserts it throws a PostgrestException with the expected error code.
Supabase RLS policies for status reads and writes must correctly distinguish between a mentor editing their own status and a coordinator editing another mentor's status within the same chapter. Incorrect policies could allow cross-chapter data leakage or silently block legitimate status updates, causing hard-to-diagnose runtime failures.
Mitigation & Contingency
Mitigation: Write RLS policies with explicit role checks (auth.uid() = mentor_id OR chapter_coordinator_check()) and verify with integration tests that cover same-chapter coordinator access, cross-chapter denial, and self-access. Review policies with a second developer before merging.
Contingency: If policy errors surface after merge, temporarily widen policy to coordinator role globally while a targeted fix is authored; use Supabase audit logs to trace any unauthorised access during the interim.
CoordinatorNotificationService must correctly resolve which coordinator(s) are responsible for a given mentor's chapter. If the chapter-coordinator mapping is incomplete or a mentor belongs to multiple chapters (as with NHF multi-chapter memberships), the service could fail to notify or duplicate notifications to the wrong coordinators.
Mitigation & Contingency
Mitigation: Use the existing chapter membership data model and query all active coordinator roles for each of the mentor's chapters. Add a de-duplication step before dispatch. Write integration tests with fixtures covering single-chapter, multi-chapter, and no-coordinator edge cases.
Contingency: If resolution logic proves too complex at this stage, fall back to notifying all coordinators in the organisation until a proper chapter-scoped resolver can be delivered in a follow-up task.
Adding new columns to peer_mentors in production could conflict with existing application code that does SELECT * queries if new non-nullable columns without defaults are introduced, causing unexpected failures in unrelated screens.
Mitigation & Contingency
Mitigation: Make all new columns nullable or provide safe defaults. Use additive migration strategy with no column renames or drops. Run migration against a staging copy of production data before applying to live.
Contingency: Prepare a rollback migration script that drops only the new columns; coordinate with the team to deploy the rollback and hotfix immediately if production issues are detected.