high priority medium complexity testing pending testing specialist Tier 5

Acceptance Criteria

Test suite connects to a real Supabase test instance (not mocked) with a clean schema per test run
Test: assigning a peer mentor to a primary chapter succeeds and sets is_primary=true on the contact_chapter row
Test: assigning a second primary chapter to the same peer mentor in the same organization fails with a constraint violation and the first primary remains unchanged
Test: NHF organization — assigning a 6th chapter to a peer mentor fails with a 'maximum 5 chapters' error; the 5th assignment succeeds
Test: unassigning the primary chapter triggers an update to the peer mentor's active_chapter_id field (set to null or next available chapter)
Test: changing primary assignment from chapter A to chapter B updates active_chapter_id atomically — no intermediate state where active_chapter_id points to a non-primary chapter
Test: coordinator role can assign/unassign peer mentors within their organization
Test: peer mentor role cannot assign themselves to a new chapter (RLS blocks the write)
Test: coordinator from organization A cannot assign peer mentors from organization B (RLS cross-org isolation)
Test: concurrent assign requests for the same peer mentor (simulated via parallel Supabase calls) do not violate the single-primary constraint due to a database-level unique partial index
Test: all tests run in under 60 seconds total on CI
Test teardown cleans all inserted rows using cascading deletes keyed to a test-run UUID to prevent data leakage between runs

Technical Requirements

frameworks
flutter_test
Flutter
Supabase PostgreSQL 15
apis
Supabase PostgREST: POST /contact_chapter (assign)
Supabase PostgREST: DELETE /contact_chapter?id=eq.{id} (unassign)
Supabase PostgREST: PATCH /contact_chapter (update primary flag)
Supabase Auth: JWT generation for coordinator and peer mentor test users
data models
contact_chapter
contact
assignment
performance requirements
Full integration test suite completes in under 60 seconds on CI
Each individual test case completes in under 5 seconds
Test setup (schema seed + test user creation) completes in under 10 seconds
security requirements
Test instance uses a dedicated non-production Supabase project — never run against production
Test JWTs generated with minimal scopes (coordinator, peer_mentor roles only)
All test data keyed with a unique run UUID prefix to prevent cross-test contamination
Service role key used only for test setup/teardown — never in the code paths under test

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Create a TestSupabaseHelper class with static methods: seedOrganization(), seedPeerMentor(), seedChapter(), cleanupByRunId(String runId). Generate a UUID run ID at test suite start and prefix all inserted entity names/IDs with it. For the unique partial index test (single primary constraint), the index should be: CREATE UNIQUE INDEX uq_primary_chapter_per_org ON contact_chapter (contact_id, organization_id) WHERE is_primary = true. Verify this index exists before running the constraint test; if absent, mark the test as skipped with a clear message pointing to the missing migration.

For coordinator vs peer_mentor RLS tests, use two separate Supabase client instances initialized with the respective JWTs. The 5-chapter NHF constraint should be enforced by a Postgres CHECK constraint or trigger — the test verifies this at the database level, not via application logic, ensuring the constraint cannot be bypassed by future code changes.

Testing Requirements

All tests are integration tests (not unit tests) running against a real Supabase test instance. Test file structure: integration_test/unit_assignment_service_test.dart. Use setUpAll to seed required organizations, peer mentors, and chapters; use tearDownAll to cascade-delete all seeded data. Use supabase.auth.signInWithPassword() with test credentials to obtain coordinator and peer_mentor JWTs before role-specific tests.

For concurrency test: use Future.wait([assign1, assign2]) with two simultaneous inserts and assert exactly one succeeds. Assert database constraint errors by catching PostgrestException and checking code field for '23505' (unique violation) or '23514' (check violation). Include a smoke test at the start that asserts the test Supabase instance is reachable and the schema version matches expectations.

Component
Unit Assignment Service
service medium
Epic Risks (3)
high impact medium prob technical

Recursive aggregation queries across four hierarchy levels (national → region → local) with 1,400 leaf nodes may be too slow for real-time dashboard requests, exceeding the 200ms target and causing spinner timeouts.

Mitigation & Contingency

Mitigation: Implement aggregation as a Supabase RPC using a single recursive CTE rather than multiple round-trip queries. Pre-compute aggregations nightly via a scheduled Edge Function and cache results. For real-time needs, aggregate only the immediate subtree on demand.

Contingency: Surface a 'Refreshing...' indicator and serve stale cached aggregations immediately. Queue an async recalculation and push updated data via Supabase Realtime when ready, avoiding blocking the admin dashboard.

medium impact medium prob scope

The 5-chapter limit and primary-assignment constraint are NHF-specific. Applying these rules globally may break HLF and Blindeforbundet configurations where different limits apply, requiring per-organization configuration that was not initially scoped.

Mitigation & Contingency

Mitigation: Make the maximum assignment count a configurable value stored in the organization's feature-flag or settings table rather than a hardcoded constant. Design the assignment service to read this limit at runtime per organization.

Contingency: Default the limit to a high value (e.g., 100) for organizations other than NHF, effectively making it non-restrictive, while keeping the enforcement logic intact for when per-org configuration is fully implemented.

medium impact low prob technical

The searchable parent dropdown in HierarchyNodeEditor must search across up to 1,400 units efficiently. Client-side filtering of the full hierarchy may be slow; server-side search adds complexity and latency.

Mitigation & Contingency

Mitigation: Use the in-memory hierarchy cache as the search corpus — since the cache already holds the flat unit list, client-side filtering with a debounced input is sufficient and avoids extra Supabase calls. Pre-build a search index on cache load.

Contingency: Cap the dropdown to showing the 50 most recently accessed units by default, with a 'search all' option that triggers a server-side full-text query. This keeps the common case fast while supporting edge cases.