critical priority medium complexity backend pending backend specialist Tier 4

Acceptance Criteria

registerProxyActivity(coordinatorId, mentorId, activityData) is a single public method that orchestrates all sub-steps in order: permission check → duplicate detection → payload construction → repository persistence
Method signature uses the session coordinator ID (from auth context) as recorded_by_user_id, ignoring any coordinatorId passed in if it differs from the authenticated user
Returns ProxyRegistrationResult.success(recordId: String) when all steps succeed, carrying the created record's UUID
Returns ProxyRegistrationResult.permissionDenied(reason: String) when the coordinator does not have the mentor in scope — no further steps are executed after this failure
Returns ProxyRegistrationResult.duplicateWarning(warnings: List<MentorDuplicateWarning>, pendingPayload: ActivityPayload) when a duplicate is detected — the method does NOT persist the record, leaving the decision to the caller
Returns ProxyRegistrationResult.persistenceError(message: String) when the Supabase insert fails for any reason other than a constraint violation handled by duplicate detection
DuplicateWarning result is non-blocking: callers can call a separate confirmAndPersist(payload) method (or equivalent) to proceed despite the warning
payload.recorded_by_user_id is always set from the authenticated session, never from the activityData input — this must be enforced inside the method, not by the caller
All four result variants are sealed/exhaustive so that callers are forced to handle every case at compile time (sealed class or freezed union in Dart)
No business logic leaks into the repository layer — ProxyActivityRepository only performs database I/O
Method is async and returns Future<ProxyRegistrationResult>
No unhandled exceptions escape the method — all Supabase exceptions are caught and mapped to PersistenceError

Technical Requirements

frameworks
Flutter
Dart
BLoC
Riverpod
freezed (for sealed result types)
apis
Supabase REST API (via supabase_flutter client)
Supabase Auth (session.user.id for coordinator identity)
data models
ActivityPayload
ProxyRegistrationResult
MentorDuplicateWarning
PeerMentorScopeRecord
performance requirements
Total method execution time under 2 seconds on a standard mobile connection (permission check + duplicate query + insert = 3 sequential Supabase calls)
Duplicate detection uses a single IN-clause query (not N+1) even for single-mentor calls, to share the code path with bulk flow
No blocking I/O on the Flutter UI thread — method must be awaited from a BLoC event handler or Riverpod async notifier
security requirements
recorded_by_user_id is sourced exclusively from Supabase Auth session, never from caller-supplied input
Permission check must query the coordinator's actual mentor scope from the database — no client-side trust of coordinatorId parameter
Supabase RLS policies must be the final enforcement layer; the service-level permission check is defence-in-depth
No sensitive mentor PII is logged in error messages

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Use a freezed sealed class for ProxyRegistrationResult with four variants: success, permissionDenied, duplicateWarning, persistenceError. The duplicateWarning variant should carry both the List (for display) and the ActivityPayload (so the caller can call a confirm flow without reconstructing the payload). The method flow is strictly sequential: (1) validate permission — early return PermissionDenied if failed, (2) run duplicate detection — early return DuplicateWarning if duplicates exist, (3) build payload with session coordinator ID overwriting any provided ID, (4) call repository.insert() — wrap in try/catch and map exceptions to PersistenceError. Do not use a try/catch at the top level that swallows the PermissionDenied or DuplicateWarning paths — only wrap the Supabase persistence call.

Consider a thin ActivityPayloadBuilder helper to keep payload construction logic out of the service method. For NHF multi-coordinator chapter support, ensure the scope check queries against the chapter's coordinator-mentor assignments table, not a cached list.

Testing Requirements

Unit tests are handled in task-010. This task requires the implementation to be structured for testability: ProxyActivityRepository, ProxyDuplicateDetector, and the scope/permission validator must all be injected as constructor dependencies (not instantiated internally) so mocks can be substituted. Use flutter_test with mockito or mocktail for dependency injection in tests. Verify that the orchestration logic (ordering of calls, correct result mapping) can be tested without a live Supabase connection.

Component
Proxy Registration Service
service 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.