critical priority medium complexity backend pending backend specialist Tier 1

Acceptance Criteria

DriverAssignmentRepository Dart class implemented with Supabase client injected via constructor
createAssignment(DriverAssignment assignment) inserts a new row and returns the created entity with server-generated id and timestamps
getAssignmentsByDriver(String orgId, String driverId) returns all non-deleted assignments for the driver, sorted by assignment_date descending
getAssignmentsByContact(String orgId, String contactId) returns all non-deleted assignments for the assignee contact, sorted by assignment_date descending
updateStatus(String assignmentId, AssignmentStatus status) updates only the status field and returns the updated entity
softDelete(String assignmentId) sets deleted_at to current timestamp and returns void
getAssignmentById(String assignmentId) returns a single assignment including soft-deleted (for history display)
All queries include explicit org_id filter as defense-in-depth alongside RLS
All methods wrap Supabase errors in typed RepositoryException
DriverAssignment model and AssignmentStatus enum defined with all fields
Repository registered in Riverpod provider graph

Technical Requirements

frameworks
Dart
Flutter
Supabase
Riverpod
apis
Supabase REST API via supabase_flutter client
data models
DriverAssignment
AssignmentStatus
Organization
Contact
performance requirements
getAssignmentsByDriver must make exactly 1 network call with server-side sort
No client-side sorting of results — rely on ORDER BY in Supabase query
security requirements
softDelete must set deleted_at server-side using PostgreSQL now() — do not send client timestamp
updateStatus must validate the status value against AssignmentStatus enum before sending to Supabase
orgId parameter validated as non-empty before all queries
Typed RepositoryException must not expose raw Supabase error codes to calling code

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Define AssignmentStatus as a Dart enum with a toJson()/fromJson() string mapping matching the database CHECK constraint values exactly. For softDelete, use `.update({'deleted_at': DateTime.now().toUtc().toIso8601String()})` — or better, use a Supabase RPC function that sets `now()` server-side to avoid clock skew issues. For getAssignmentsByDriver and getAssignmentsByContact, filter soft-deleted rows with `.is_('deleted_at', null)`. The getAssignmentById intentionally omits the deleted_at filter to support history display — document this clearly in a code comment.

Follow the same Riverpod provider pattern established by DeclarationTemplateRepository (task-002) for consistency. Use `.select('*').single()` for create/update operations to return the full updated entity in one round-trip.

Testing Requirements

Unit tests with mocked Supabase client using flutter_test covering: (1) createAssignment maps response to DriverAssignment model correctly, (2) getAssignmentsByDriver filters by driverId and excludes soft-deleted rows, (3) getAssignmentsByContact filters by contactId and excludes soft-deleted rows, (4) updateStatus sends correct status value only, (5) softDelete sends deleted_at update, (6) getAssignmentById includes soft-deleted rows, (7) Supabase error propagates as RepositoryException, (8) empty result returns empty list not null. Aim for 100% method coverage.

Component
Driver Assignment Repository
data medium
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.