critical priority low complexity backend pending backend specialist Tier 1

Acceptance Criteria

DeclarationTemplateRepository class is implemented in Dart with a Supabase client injected via constructor
getActiveTemplate(String orgId) returns the single active DeclarationTemplate for the org, or null if none exists
getTemplateByVersion(String orgId, int version) returns the specific version, including soft-deleted historical versions
listAllVersions(String orgId) returns all versions (excluding soft-deleted) ordered by version descending
All methods throw a typed RepositoryException (not generic Exception) on Supabase errors
All queries include org_id filter even though RLS enforces it — defense in depth
DeclarationTemplate model class is defined with all table columns mapped correctly including nullable deleted_at
Repository is registered in the dependency injection / Riverpod provider graph
No raw SQL strings in the Dart code — use Supabase client builder API only

Technical Requirements

frameworks
Dart
Flutter
Supabase
Riverpod
apis
Supabase REST API via supabase_flutter client
data models
DeclarationTemplate
Organization
performance requirements
getActiveTemplate must make exactly 1 network call
Repository methods must not perform N+1 queries
security requirements
orgId parameter must be validated as non-empty before query execution
Never expose raw Supabase error messages to UI — wrap in typed exceptions
Repository must use the authenticated Supabase client, not anon key directly

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Define a DeclarationTemplate Dart class with a fromJson factory constructor that maps all database columns. Use Riverpod Provider or StateNotifierProvider to expose the repository — align with the pattern used by other repositories in the codebase. For getActiveTemplate, use `.eq('org_id', orgId).eq('is_active', true).maybeSingle()` to safely handle the no-result case without throwing. For getTemplateByVersion, explicitly include `.eq('deleted_at', null).or('deleted_at.not.is.null')` — or simply omit the deleted_at filter — to retrieve historical versions regardless of soft-delete status.

Wrap all Supabase calls in try/catch and rethrow as `RepositoryException(message: e.message, code: e.code)`.

Testing Requirements

Unit tests with mocked Supabase client for: (1) getActiveTemplate returns correct model when row exists, (2) getActiveTemplate returns null when no active template, (3) getTemplateByVersion returns correct historical version, (4) getTemplateByVersion returns soft-deleted version (historical accuracy requirement), (5) listAllVersions returns descending order, (6) Supabase error propagates as typed RepositoryException. Use flutter_test. Aim for 100% method coverage.

Component
Declaration Template Repository
data low
Epic Risks (3)
high impact medium prob security

Row-level security policies for driver assignments and declarations must correctly scope data to the coordinator's chapter without leaking records across organizations. An incorrect RLS predicate could silently return empty result sets or, worse, expose cross-org data, both of which are difficult to detect in unit tests.

Mitigation & Contingency

Mitigation: Write dedicated RLS integration test scenarios with multiple org fixtures asserting both data isolation and correct data visibility. Use Supabase's built-in policy testing utilities and review policies with a second developer.

Contingency: If RLS policies prove too complex to get right quickly, implement application-layer org scoping as a temporary guard while RLS is fixed in a follow-up, with an explicit security review gate before production deployment.

high impact medium prob security

The declaration audit logger must produce tamper-evident records. If the database allows updates or deletes on audit rows, the compliance guarantee is broken. Supabase does not natively prevent row deletion by default.

Mitigation & Contingency

Mitigation: Implement an insert-only RLS policy on the audit table that denies UPDATE and DELETE for all roles including the service role. Add a database trigger that rejects mutation attempts and logs the attempt itself.

Contingency: If immutability cannot be enforced at the database level within the sprint, store audit entries in an append-only Supabase Edge Function log stream as a temporary alternative, with a migration plan to the proper table once constraints are implemented.

medium impact low prob technical

The org-feature-flag-service caches flag values to avoid repeated database reads. If the cache is not invalidated promptly after an admin toggles the flag, coordinators may see stale UI state — either seeing driver features when they should not, or not seeing them when they should.

Mitigation & Contingency

Mitigation: Use a Supabase Realtime subscription to listen for changes on the driver_feature_flag_config table and invalidate the in-memory cache immediately on change. Set a short TTL (60 seconds) as a safety net.

Contingency: If Realtime subscription proves unreliable, expose a manual cache-bust endpoint accessible from the admin toggle action, ensuring the cache is cleared synchronously on every flag change.