high priority medium complexity integration pending backend specialist Tier 4

Acceptance Criteria

A `contactChapterRepositoryProvider` is defined using Riverpod `Provider` and accepts `SupabaseContactChapterAdapter` via the adapter provider from the foundation epic (217)
A `crossChapterActivityQueryProvider` is defined and correctly receives its required data source dependencies via Riverpod injection
A `duplicateWarningEventLoggerProvider` is defined and wired to its data source without exposing raw Supabase client to the service layer
All three providers are declared in a dedicated providers file (e.g., `contact_chapter_providers.dart`) following the project's provider file naming convention
Providers are scoped such that each authenticated session resolves an organisation-specific instance — no cross-tenant data leakage is possible via provider sharing
Service layer classes can consume all three providers via `ref.read` / `ref.watch` without direct instantiation of any adapter or repository class
If the underlying adapter provider throws (e.g., Supabase client unavailable), consuming providers propagate the error state correctly rather than silently returning null
Provider overrides are available for test environments, allowing mock adapter injection in unit and widget tests
No provider creates a circular dependency; the dependency graph is a strict DAG resolvable at runtime

Technical Requirements

frameworks
Flutter
Riverpod
apis
Supabase PostgREST (via adapter abstraction)
data models
contact_chapter
contact
activity
performance requirements
Provider instantiation must be lazy — objects are not created until first consumer reads them
Repository and query objects must be singletons within a given Riverpod container scope to avoid redundant adapter instances
security requirements
Organisation ID must be read from the authenticated JWT claims (Supabase Auth) at provider creation time — never passed as a raw parameter from the UI layer
Providers must not cache cross-organisation state; invalidate on auth session change
Raw Supabase service-role key must never be accessible to providers running in the Flutter client

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Use `riverpod_annotation` if the project already uses code generation; otherwise declare providers manually to stay consistent with the existing codebase style. The adapter provider from the foundation epic (217) should be a `Provider` that itself reads `supabaseClientProvider` — keep this pattern consistent. For multi-tenant scoping, read `currentOrganisationIdProvider` (or equivalent) inside the provider body and pass it to the repository constructor rather than relying on the repository to fetch it independently. This keeps providers pure and testable.

Avoid `StateNotifierProvider` here — these are stateless data-access objects, so plain `Provider` is appropriate. Add a `// coverage:ignore` annotation only for provider declarations that are purely wiring with no conditional logic.

Testing Requirements

Unit tests: use `ProviderContainer` with override for `supabaseContactChapterAdapterProvider` injecting a mock. Assert that each of the three providers resolves to the correct concrete type and that dependencies are wired in the expected order. Test that provider reads on an unauthenticated container surface an error rather than a null instance. Integration test: spin up a real Riverpod container against a local Supabase test instance and verify round-trip read through each provider.

Aim for 100% provider registration coverage and at least one positive and one error-path assertion per provider.

Component
Contact Chapter Repository
data medium
Epic Risks (3)
high impact medium prob technical

The Cross-Chapter Activity Query must avoid N+1 fetches across chapters. If naively implemented as a per-chapter loop, it will cause severe performance degradation for contacts affiliated with 5 chapters on poor mobile connections.

Mitigation & Contingency

Mitigation: Design the query as a single PostgREST join of contact_chapters and activities on contact_id from the start. Add a query performance test with 5 affiliations and 100+ activities to the integration test suite and enforce a maximum execution time threshold.

Contingency: If a performance regression is detected post-merge, introduce a Supabase RPC function (stored procedure) to move the join server-side, bypassing any client-side N+1 pattern.

high impact low prob security

If the Duplicate Warning Event Logger write fails silently (network error, RLS denial), audit entries will be missing from the Bufdir compliance record without the user being aware.

Mitigation & Contingency

Mitigation: Implement the logger with a local fallback queue: if the Supabase write fails, persist the event locally and retry on next launch. Log all failures to a verbose output channel.

Contingency: Add a reconciliation job that compares locally queued events to Supabase entries and re-submits any gaps. Provide a data export of the local queue for manual audit if reconciliation fails.

medium impact low prob technical

Two coordinators simultaneously adding the 5th chapter affiliation for the same contact could bypass the maximum enforcement check if both reads occur before either write completes.

Mitigation & Contingency

Mitigation: Enforce the 5-affiliation maximum as a database-level constraint (CHECK + trigger or RPC with a FOR UPDATE lock) rather than relying solely on application-layer validation.

Contingency: If a constraint violation is detected in production, run a corrective query to end the most recently created excess affiliation and notify the relevant coordinator.