high priority low complexity backend pending backend specialist Tier 3

Acceptance Criteria

formatWarnings(rawResults: List<DuplicateQueryResult>, candidates: List<MentorActivityCandidate>) is a pure function (no async, no I/O) that maps raw DB results to List<MentorDuplicateWarning>
Each MentorDuplicateWarning contains: mentorId (UUID), mentorName (String), conflictingDate (DateTime or String), conflictingActivityType (String), existingRecordId (UUID), originalRecordedByCoordinatorId (UUID)
mentorName is resolved from the candidates list or a name lookup map passed as a parameter — not fetched from the database inside this method
originalRecordedByCoordinatorId is populated from the raw query result's recorded_by_user_id field — enables NHF multi-coordinator chapter cross-coordinator duplicate display
Returns an empty List<MentorDuplicateWarning> (not null) when rawResults is empty — callers never need to null-check the return value
If a raw result cannot be mapped (missing required field), it is skipped with a debug-level log — the method does not throw
MentorDuplicateWarning is an immutable value object (freezed or const) with structural equality
The formatter is a private method or separate class within the ProxyDuplicateDetector, not exposed as a public API beyond the detector's checkDuplicates() entry point

Technical Requirements

frameworks
Flutter
Dart
freezed (for MentorDuplicateWarning value object)
data models
MentorDuplicateWarning
DuplicateQueryResult
MentorActivityCandidate
performance requirements
Pure synchronous mapping — no async operations, no database calls
O(n) mapping for n raw results — no nested loops
security requirements
mentorName must not be sourced from the raw DB result if the activities table does not store names — join to the profile/users table only in the query layer (task-011), not here
originalRecordedByCoordinatorId is displayed in the UI for NHF chapter admin awareness but must not be used for any access control decision

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Keep this method as a pure transformation — no side effects, no I/O. If mentorName is not available in the raw query result (because the activities table stores only mentorId), resolve names from a Map mentorNameLookup parameter populated in checkDuplicates() before calling the formatter. Use a for-loop with try/catch per item rather than list.map() so that a single malformed record does not abort the entire mapping. MentorDuplicateWarning should be defined with freezed: @freezed class MentorDuplicateWarning with _$MentorDuplicateWarning.

For the conflictingDate field, store as a Dart DateTime (UTC midnight) for consistency with the rest of the app's date handling — parse from the Supabase ISO 8601 string in this formatter.

Testing Requirements

Since formatWarnings is a pure function, unit tests require no mocks. Test directly with constructed DuplicateQueryResult and MentorActivityCandidate lists. Test cases (covered in task-013): exact full mapping, missing optional fields skipped gracefully, empty input returns empty list, NHF cross-coordinator field populated correctly. Use expect() with equals() on freezed MentorDuplicateWarning objects to verify structural equality.

Component
Proxy Duplicate Detector
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.