critical priority low complexity database pending database specialist Tier 0

Acceptance Criteria

Migration script creates declaration_templates table with columns: id (uuid, PK), org_id (uuid, FK to organizations), version (integer, not null), template_content (jsonb, not null), is_active (boolean, default false), deleted_at (timestamptz, nullable), created_at (timestamptz, default now()), updated_at (timestamptz, default now()), created_by (uuid, FK to auth.users)
Composite unique constraint enforces (org_id, version) uniqueness
Index exists on org_id for fast org-scoped queries
Index exists on (org_id, version) for fast version lookups
RLS policy: authenticated users can SELECT only rows where org_id matches their JWT org claim
RLS policy: only users with coordinator or admin role can INSERT/UPDATE rows for their org
RLS policy: DELETE is blocked for all users (soft-delete only via deleted_at)
Soft-deleted rows (deleted_at IS NOT NULL) are excluded from the default active template query but remain retrievable by explicit version ID query
Migration script is idempotent (safe to run twice without error)
Migration script is committed to the supabase/migrations directory with a timestamped filename

Technical Requirements

frameworks
Supabase
PostgreSQL
apis
Supabase Migrations CLI
Supabase RLS
data models
DeclarationTemplate
Organization
User
performance requirements
Query for active template by org_id must execute in under 10ms with index
Query for specific version by (org_id, version) must use composite index
security requirements
RLS must be enabled on the table (ALTER TABLE ... ENABLE ROW LEVEL SECURITY)
No direct DELETE permission — enforce audit trail via soft-delete only
org_id must be validated against JWT claim, not user-supplied parameter
created_by must reference auth.users to maintain audit integrity

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use Supabase CLI `supabase migration new declaration_templates` to generate the migration file. The is_active flag approach for 'current version' requires a trigger or application logic to ensure only one row per org has is_active=true at a time — consider a partial unique index `WHERE is_active = true` instead of a boolean flag, or enforce via application layer. The template_content column should store the full JSON schema of the declaration form to support rendering without additional lookups. Add a comment on the table (`COMMENT ON TABLE declaration_templates IS '...'`) for discoverability.

Ensure the migration includes `ALTER TABLE declaration_templates ENABLE ROW LEVEL SECURITY;` as a separate statement after table creation.

Testing Requirements

Write SQL-level tests or Supabase edge function tests verifying: (1) INSERT succeeds for authorized org user, (2) INSERT fails for user from different org, (3) SELECT returns only rows for the authenticated user's org, (4) DELETE attempt returns error (RLS blocks it), (5) soft-deleted row is excluded from default active query, (6) historical version is still retrievable by explicit ID after soft-delete. Run migration against a clean Supabase test project to confirm idempotency.

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.