critical priority low complexity backend pending backend specialist Tier 1

Acceptance Criteria

RecurringTemplateRepository is a concrete Dart class (not abstract) with a corresponding abstract interface IRecurringTemplateRepository for dependency injection
fetchTemplatesForCoordinator(String coordinatorId, String orgId) returns Future<List<RecurringTemplate>> and filters by both coordinator_id and org_id
createTemplate(RecurringTemplate template) returns Future<RecurringTemplate> with the server-assigned id and created_at populated
updateTemplate(RecurringTemplate template) returns Future<RecurringTemplate> and throws a TemplateNotFoundException if the id does not exist or does not belong to the caller
deleteTemplate(String templateId) returns Future<void> and throws a TemplateNotFoundException if the id does not belong to the caller's org
All methods wrap Supabase errors in domain-specific exception types (e.g., TemplateRepositoryException) — raw PostgrestException never leaks to calling layers
Repository is registered with Riverpod as a Provider and can be overridden in tests
All method parameters are validated (non-null, non-empty) with ArgumentError before making network calls
Integration test demonstrates all four CRUD operations against a local Supabase instance

Technical Requirements

frameworks
Flutter
Riverpod
Supabase
apis
Supabase Dart client — supabase_flutter
recurring_activity_templates table
data models
RecurringTemplate
recurring_activity_templates
performance requirements
fetchTemplatesForCoordinator must complete in under 500ms on a standard mobile connection for up to 50 templates
Use .select() with specific columns rather than wildcard to minimize payload size
security requirements
Never pass raw SQL or user-controlled strings into .filter() or .eq() without using the typed Supabase query builder
Rely on Supabase RLS for org scoping — do NOT implement org filtering purely client-side as a security boundary
Supabase session must be validated before any call; throw AuthenticationException if session is null

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Follow the existing repository pattern in the codebase — check how other repositories (e.g., activity repository) structure their Supabase calls and replicate the pattern exactly for consistency. The RecurringTemplate Dart model should use freezed for immutability and JSON serialization. Org-scoped filtering via .eq('org_id', orgId) is a defense-in-depth measure — RLS is the true security boundary, but the explicit filter makes intent clear and avoids surprises in tests where RLS may be bypassed. Use Riverpod's ref.watch pattern for the Supabase client dependency rather than a singleton to support test overrides.

Do not add logging or analytics calls in this task — keep the repository pure data access.

Testing Requirements

Unit tests (flutter_test): mock the Supabase client using a mock generated with mockito or mocktail. Test: (1) fetchTemplatesForCoordinator returns correctly mapped RecurringTemplate list, (2) createTemplate maps response back to domain object, (3) updateTemplate throws TemplateNotFoundException on 404-equivalent Supabase error, (4) deleteTemplate throws on missing record, (5) all methods throw ArgumentError on null/empty inputs. Integration tests: run against local Supabase with real migration applied. Minimum 80% line coverage on the repository class.

Epic Risks (3)
high impact medium prob security

Supabase RLS policies for org-scoped proxy access may be difficult to express correctly, especially for coordinators with multi-chapter access. An overly permissive policy could allow cross-org proxy registrations, corrupting Bufdir reporting; an overly restrictive policy could block legitimate coordinators from registering.

Mitigation & Contingency

Mitigation: Write integration tests covering all access boundary cases (same org, cross-org, multi-chapter coordinator) before merging any RLS migration. Use parameterised RLS test helpers already established by the auth feature.

Contingency: If RLS proves insufficient, add a server-side Edge Function validation layer that re-checks org membership before persisting any proxy record, providing defence in depth.

medium impact low prob technical

Adding new tables and foreign key constraints to an existing production Supabase database risks migration failures or locking issues if the database already contains active sessions during deployment.

Mitigation & Contingency

Mitigation: Use additive-only migrations (no DROP or ALTER on existing tables). Test full migration sequence in a staging Supabase project before production deployment. Schedule during low-traffic window.

Contingency: Maintain a rollback migration script. If the migration fails, the feature remains unreachable behind a feature flag while the schema issue is resolved.

high impact medium prob security

Audit log entries must be immutable for compliance, but Supabase RLS by default allows row owners to update their own rows. If audit records are accidentally mutable, dispute resolution and accountability guarantees are invalidated.

Mitigation & Contingency

Mitigation: Configure the proxy_audit_log table with an RLS policy that allows INSERT for coordinators but denies UPDATE and DELETE for all roles including service_role, enforced at the database level.

Contingency: If RLS cannot fully prevent updates, create a database trigger that reverts any UPDATE to the audit table and logs the attempt as a security event.