high priority medium complexity backend pending backend specialist Tier 2

Acceptance Criteria

getActivitiesAttributedToMentor(mentorId, {dateRange}) returns all activity rows where peer_mentor_id == mentorId regardless of recorded_by_user_id value
Proxy-recorded activities (recorded_by_user_id != peer_mentor_id) are included and indistinguishable from self-recorded activities in the statistics output
recorded_by_user_id is NOT exposed in the statistics output model — the coordinator identity is excluded to prevent double-counting
getActivityCountsByMentor(chapterId, period) returns a map of peer_mentor_id → activity count for all mentors in the given chapter and period
period parameter supports: current_month, current_quarter, current_year, and arbitrary {startDate, endDate}
Chapter scoping uses the chapter's organization_unit_id to filter mentors via the contact_chapter membership table
A mentor's count includes both self-recorded and proxy-recorded activities — the sum must match the total stored rows for that peer_mentor_id
Zero-activity mentors in the chapter are included in getActivityCountsByMentor with a count of 0
Both methods return typed domain failures on Supabase error — no raw exceptions propagate to callers
Bufdir export logic consuming these methods produces totals consistent with manual SQL count verification

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
apis
Supabase PostgreSQL 15
Supabase Auth
data models
activity
assignment
contact_chapter
annual_summary
performance requirements
Index on peer_mentor_id and date columns required for getActivitiesAttributedToMentor
getActivityCountsByMentor should use a GROUP BY aggregate query rather than fetching all rows client-side
Chapter-scoped query must use a subquery or JOIN on contact_chapter, not multiple round trips
security requirements
RLS must allow coordinators to read activities for mentors in their chapter via peer_mentor_id — not by exposing recorded_by_user_id
Coordinator identity (recorded_by_user_id) must be stripped from all statistics-facing query results
chapterId must be validated against the authenticated coordinator's chapter memberships to prevent cross-chapter data access

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

For getActivityCountsByMentor, use Supabase's `.select('peer_mentor_id, count', { count: 'exact' }).eq('organization_id', orgId)` with group-by via a Postgres view or RPC if Supabase's PostgREST client cannot express GROUP BY directly. Consider a Supabase Edge Function or a DB view `mentor_activity_counts` if complex grouping is needed. For getActivitiesAttributedToMentor, a simple `.eq('peer_mentor_id', mentorId)` suffices. The statistics model should be a separate `MentorActivityStats` class distinct from `ProxyAuditRecord` to prevent accidental coordinator identity leakage.

Coordinate with the annual_summary table — these methods feed the data that eventually populates annual summaries.

Testing Requirements

Unit tests with flutter_test and mocked Supabase: (1) proxy-recorded activity appears in mentor's statistics, (2) coordinator identity absent from stats model, (3) getActivityCountsByMentor sums correctly across mixed self/proxy rows, (4) period filter boundaries are inclusive on both ends, (5) mentor with zero activities returns count 0 not absent, (6) invalid chapterId returns UnauthorizedFailure, (7) Supabase error maps to typed failure. Integration test: seed three mentors in one chapter — two with self-recorded, one with proxy-recorded activities — verify counts match expected totals.

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.