high priority medium complexity integration pending integration specialist Tier 2

Acceptance Criteria

insertBatch accepts a List<ProxyActivityRecord> with 1 to 100 items; batches exceeding 100 are rejected with a ValidationFailure before any network call
Each record in the batch independently carries recorded_by_user_id and peer_mentor_id — these are never shared or defaulted across records
The Supabase RPC function is called as a single atomic transaction — either all rows in the batch commit or none do (on DB-level failure)
On partial validation failure (invalid fields in one record), the failed record is excluded and the remaining valid records are still submitted, with per-row results returned
BatchInsertResult contains a list of per-row outcomes: { index, record_id (if success), success: bool, errorMessage: String? }
A fully successful batch returns BatchInsertResult where all items have success == true
A total RPC failure (network error, auth error) returns a typed domain failure, not a partial result
recorded_by_user_id is sourced from the server-side JWT claim inside the RPC function — the client payload value is validated against it
Batch insert performance: 50 records must complete in under 3 seconds on a standard Supabase plan
Duplicate detection: if two records in the same batch reference the same (peer_mentor_id, date, activity_type_id), the second is flagged as DuplicateFailure in per-row results

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
apis
Supabase PostgreSQL 15
Supabase Edge Functions (Deno)
Supabase Auth
data models
activity
assignment
performance requirements
Batch of 50 rows must complete in under 3 seconds
Single RPC call — no loop of individual inserts
Serialization of List<ProxyActivityRecord> to JSON must handle all field types including nullable notes
security requirements
recorded_by_user_id must be validated server-side against auth.uid() in the RPC function — client-supplied value treated as advisory only
RPC function must enforce that coordinator has chapter-level write permission for each peer_mentor_id in the batch
Batch payload must not contain sensitive PII beyond what the activity schema requires
Service role key used in RPC must never be passed through mobile client

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

The Supabase RPC function should be defined as `insert_proxy_activity_batch(records jsonb[])` in Postgres using `INSERT INTO activities SELECT * FROM jsonb_populate_recordset(null::activities, $1)`. Wrap in a transaction with EXCEPTION handling to capture per-row errors if the DB function supports it. On the Dart side, serialize each `ProxyActivityRecord` to a `Map` and pass as a list to `supabase.rpc('insert_proxy_activity_batch', params: {'records': serializedList})`. The `BatchInsertResult` should be a simple value class with `List rows` and a convenience getter `bool allSucceeded`.

Consider a 30-second timeout for large batches. Coordinate with the RPC function author (task-002 scope) to align on the function name and parameter schema.

Testing Requirements

Unit tests with flutter_test and mocked Supabase RPC client: (1) valid batch of 5 returns all-success result, (2) batch exceeding 100 items rejected before RPC call, (3) one invalid record excluded and rest submitted successfully, (4) RPC network failure maps to typed domain failure, (5) duplicate within batch flagged correctly, (6) each record in result carries correct index, (7) empty batch returns ValidationFailure. Integration test against local Supabase: seed a coordinator with 3 mentors, submit a 3-record batch, verify all rows persisted with correct dual-identity fields.

Component
Proxy Activity Repository
data medium
Epic Risks (2)
high impact low prob security

The Proxy Registration Service must verify that the coordinator has a legitimate assignment relationship with the target peer mentor before creating a record. If this check is implemented only in application code and not enforced at the DB/RLS level, a compromised or buggy client could bypass it by calling the Supabase endpoint directly, creating fraudulent proxy records for arbitrary peer mentors.

Mitigation & Contingency

Mitigation: Implement permission validation at two levels: (1) application-layer check in Proxy Registration Service that queries the assignments table before constructing the payload, and (2) RLS policy on the activities table that restricts INSERT to rows where recorded_by_user_id matches the authenticated user AND peer_mentor_id is in the set of peer mentors assigned to that coordinator. The RLS policy is the authoritative guard; the service-layer check provides early user-facing feedback.

Contingency: If RLS policy implementation is blocked by Supabase plan constraints, implement a Supabase Edge Function as a proxy endpoint that enforces the permission check server-side before forwarding to the DB. Disable direct client inserts entirely for proxy activities.

medium impact medium prob technical

For a bulk session with 30 selected peer mentors, the Proxy Duplicate Detector must query existing activities for each mentor. If implemented as 30 sequential Supabase queries, round-trip latency could make the bulk confirmation screen feel slow (>3s), degrading coordinator experience and potentially causing timeouts.

Mitigation & Contingency

Mitigation: Implement the duplicate check as a single Supabase query using an IN clause on peer_mentor_id combined with the activity_type and date filters, returning all potential duplicates for the entire batch in one network round-trip. Group results client-side by mentor ID to produce the per-mentor warning structure.

Contingency: If the single-query approach returns too much data for very large chapters, add a database index on (peer_mentor_id, activity_type, date) and profile query time. If still insufficient, accept a short loading state on the confirmation screen with a progress indicator rather than pre-loading duplicates before navigation.