critical priority medium complexity database pending database specialist Tier 0

Acceptance Criteria

Migration file is created under supabase/migrations/ with a timestamped name and applies cleanly via `supabase db push` on a fresh and existing database
Column recorded_by_user_id is of type UUID, nullable, with a foreign key constraint referencing auth.users(id) ON DELETE SET NULL
An index (e.g. idx_activity_records_recorded_by_user_id) exists on the new column and is confirmed in pg_indexes
All existing rows in activity_records have recorded_by_user_id = NULL after migration — no data loss or constraint violations
RLS policy allows a coordinator (role = 'coordinator') to INSERT a row on behalf of any peer mentor within their chapter scope, verified by Supabase policy test or SQL unit test
RLS policy does NOT allow a peer mentor to set a recorded_by_user_id other than NULL or their own user ID
Migration is idempotent: running it twice does not produce an error
Rollback script (DOWN migration) removes the column, index, and updated RLS policies cleanly
Migration is reviewed and passes CI lint for SQL style and security

Technical Requirements

frameworks
Supabase CLI (supabase db diff, supabase db push)
PostgreSQL 15+
apis
Supabase Management API (for RLS policy updates)
auth.users system table
data models
activity_records
auth.users
user_roles / coordinator_assignments (chapter scope)
performance requirements
Index on recorded_by_user_id must support queries filtering by coordinator ID across large activity datasets (target: < 50 ms for 100k rows)
Migration must complete in < 30 seconds on a production-sized dataset (estimate: 500k rows)
security requirements
Foreign key ON DELETE SET NULL prevents orphaned references when a user is deleted
RLS policy must be row-level: coordinators can only write on behalf of peer mentors in their own chapter, never across chapters
No service_role bypass allowed in application code for this column — enforce through RLS only
Migration SQL must be reviewed for SQL injection vectors (parameterised DDL where applicable)

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use `supabase migration new add_recorded_by_user_id` to scaffold the file. The foreign key should reference auth.users(id) rather than a custom profiles table to avoid cross-schema FK issues. For chapter-scope enforcement in RLS, join against the coordinator_assignments (or equivalent) table using `auth.uid()`. Write the DOWN migration in the same PR.

Tag the migration with a comment referencing the Bufdir reporting requirement so future maintainers understand the compliance motivation. Coordinate with the team to ensure no other migration is in flight that touches activity_records simultaneously.

Testing Requirements

Write SQL-level unit tests (pgTAP or Supabase's built-in test framework) covering: (1) INSERT with recorded_by_user_id = NULL succeeds for any authenticated user, (2) coordinator can INSERT with recorded_by_user_id pointing to a peer mentor in their chapter, (3) coordinator cannot INSERT with recorded_by_user_id pointing to a peer mentor outside their chapter, (4) peer mentor cannot set recorded_by_user_id to another user's ID. Additionally, write a Flutter integration test that seeds the migration on a local Supabase instance and verifies the schema via a raw query.

CI must run the migration against a clean database on every PR.

Component
Batch Insert RPC Adapter
infrastructure medium
Epic Risks (2)
high impact medium prob security

Adding recorded_by_user_id to the activities table and writing correct RLS policies is error-prone: overly permissive policies would allow coordinators to record activities under arbitrary user IDs they do not manage, while overly restrictive policies would silently block valid proxy inserts. A policy defect here would either create a security vulnerability or break the entire proxy feature at runtime.

Mitigation & Contingency

Mitigation: Write RLS policies in a local Supabase emulator first. Include policy unit tests using pg_tap or supabase test helpers. Have a second reviewer check the migration SQL before merging. Explicitly test the three cases: coordinator inserting for their own mentors (should succeed), coordinator inserting for another chapter's mentors (should fail), peer mentor inserting for themselves (should succeed as before).

Contingency: If a policy defect is discovered in staging, roll back the migration with a down-migration script. Delay feature release until the policy is corrected and re-verified. Apply a feature flag to keep the proxy entry point hidden from coordinators until the fix is confirmed.

high impact low prob technical

The insert_bulk_activities RPC must behave atomically — a failure on row 7 of 12 must roll back rows 1–6. If Supabase's RPC transaction handling is misconfigured or if network interruptions cause partial acknowledgements, some peer mentors could receive duplicate or missing activity records, directly corrupting Bufdir statistics for the coordinator's chapter.

Mitigation & Contingency

Mitigation: Implement the RPC as a PostgreSQL function with explicit BEGIN/EXCEPTION/END block to guarantee atomicity. Add an integration test that inserts a batch where one row violates a unique constraint and asserts zero rows are committed. Document the transaction semantics in code comments.

Contingency: If atomicity cannot be guaranteed via RPC (e.g., due to Supabase plan limitations), fall back to a sequential insert loop with a compensating DELETE in case of partial failure, and surface a clear error to the coordinator listing which mentors failed and which succeeded.