high priority low complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

ProxyAuditBadge is rendered on all activity cards where recorded_by_user_id differs from the attributed peer mentor's user_id
ProxyAuditBadge is NOT rendered on activity cards where recorded_by_user_id equals the attributed peer mentor's user_id
Badge is displayed in a consistent position (e.g., top-right corner) across peer mentor stats list, coordinator activity log viewer, and post-session report confirmation view
Activity cards without proxy data (null or missing recorded_by_user_id) render pixel-identically to their pre-change state — no layout shift, no extra whitespace, no missing elements
Badge passes both recorded_by_user_id and attributed actor user_id as required props; no other data is passed to the badge widget
All three card surfaces (stats list item, log viewer row, confirmation card) updated and verified in manual walkthrough
Screen reader semantic label on the badge is present and announces proxy authorship clearly (WCAG 2.2 AA)
No new lint warnings or analyzer errors introduced

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
data models
ActivityRecord
PeerMentorContact
UserProfile
performance requirements
Badge widget must build in O(1) — no async calls, no database reads inside the card widget
No rebuild cascade: only the badge itself should rebuild when proxy props change
security requirements
Do not expose full coordinator name or user_id in widget tooltip or visible text unless the viewing role is coordinator or admin
recorded_by_user_id must be received as a read-only prop — never mutated inside card widgets
ui components
ProxyAuditBadge (111-proxy-audit-badge)
ActivityCard
PeerMentorStatsListItem
CoordinatorActivityLogRow
PostSessionReportConfirmationCard

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use a simple conditional expression inside each card's build method: `if (recordedByUserId != null && recordedByUserId != attributedUserId) ProxyAuditBadge(...)`. Avoid introducing a helper function unless it is reused in 3+ places. Place the badge in a Stack overlay or as a trailing widget in a Row depending on the card layout — be consistent across all three surfaces. Do NOT fetch user data inside the card; all data must be passed as constructor params from the parent BLoC/provider state.

Check whether each card already receives the activity record model — if so, simply extract recorded_by_user_id from that model rather than adding a separate prop. The post-session confirmation view may use a different data flow (form state vs database record); ensure the recorded_by_user_id is propagated from the BLoC state at confirmation time.

Testing Requirements

Widget tests are covered by task-010. This task requires: (1) manual visual regression check on all three card surfaces with and without proxy data, (2) a quick flutter analyze pass with zero new warnings, (3) confirmation that golden tests (if present) are updated or annotated. No new test files are expected from this task alone.

Component
Proxy Audit Badge Widget
ui low
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.