Implement organization_id scoping on all contact queries
epic-contact-list-management-foundation-task-002 — Within ContactRLSQueryBuilder, implement the organization_id scoping logic that appends an .eq('organization_id', orgId) filter to every outbound Supabase query. Ensure the scope is applied before any additional predicates so it cannot be bypassed. Cover the multi-chapter NHF case where a user may belong to multiple organization units.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Structure the query builder as a fluent builder pattern: ContactRLSQueryBuilder.forOrganisation(orgId).withRole(role).withSearch(query).build(). This makes the mandatory organisation scoping the entry point — callers cannot reach withRole() without going through forOrganisation() first. For multi-chapter support, overload forOrganisation() to accept either a single String or a List
Testing Requirements
Unit tests: (1) single orgId produces .eq filter with correct column and value; (2) list of two orgIds produces .in_ filter; (3) empty list throws ArgumentError before Supabase is called; (4) organization_id filter appears first in the filter chain regardless of call order. Use a mock Supabase query builder that records filter call sequence. All tests in flutter_test. These tests will be consolidated with the broader unit test suite in task-004.
Existing Supabase RLS policies for the contacts and peer_mentors tables may not align with the application-level UserRole model, causing ContactRLSQueryBuilder to construct filter expressions that are redundant, conflicting, or that allow over-fetching. In a multi-chapter context (NHF), this could expose contacts belonging to other chapters.
Mitigation & Contingency
Mitigation: Audit and document the existing RLS policies against the UserRole enum before writing a single line of query builder code. Write integration tests asserting cross-organization data isolation using separate test user tokens for each role.
Contingency: If RLS policies are misaligned at runtime, add an explicit application-level organization_id equality check in ContactRepository as a secondary guard while the database policies are corrected in a coordinated migration.
The Supabase schema for contacts and peer_mentors tables may differ from the expected typed models — missing columns, renamed fields, or type mismatches — causing deserialization failures that surface only at runtime during integration testing.
Mitigation & Contingency
Mitigation: Document expected schema fields upfront and validate against the live Supabase schema at sprint start. Use freezed and json_serializable for compile-time-safe deserialization with explicit required/optional field declarations.
Contingency: Introduce nullable fields with safe defaults for any schema mismatches discovered in testing; log deserialization errors to the monitoring service so schema drift is caught before production deployment.