Build proxy vs self-registered audit query helpers
epic-proxy-activity-registration-core-services-task-006 — Add query helper methods to activity-attribution-service that enable audit report generation distinguishing proxy-entered records from self-registered ones. Implement getProxyRegisteredByCoordinator(coordinatorId, dateRange) and getSelfRegisteredByMentor(mentorId, dateRange) methods. These helpers are required by the coordinator stats dashboard and Bufdir export pipeline to correctly attribute activity counts to the responsible submitter.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Both methods are read-only query helpers on SupabaseActivityAttributionService. For getProxyRegisteredByCoordinator: query activities where registered_by = coordinatorId AND attributed_to != coordinatorId AND activity_date >= dateRange.from AND activity_date <= dateRange.to AND status != 'voided'. For getSelfRegisteredByMentor: query where registered_by = mentorId AND attributed_to = mentorId AND same date/status filters. Consider adding an overloaded variant accepting ProxyAuditQueryFilter for more complex filtering (used by Bufdir export).
For Bufdir compliance specifically, the distinction is: proxy records = coordinator registered on behalf of mentor (registered_by != attributed_to), self-registered = mentor logged their own activity (registered_by == attributed_to). Expose both as Riverpod FutureProviders with the coordinatorId/mentorId and DateRange as family parameters so the coordinator stats BLoC can subscribe reactively. Pagination: add optional page and pageSize parameters with defaults of page=0 and pageSize=50.
Testing Requirements
Unit tests with mocked Supabase client: coordinator with proxy records in range, coordinator with no records in range, date range boundary (inclusive), voided records excluded, self-registered records correctly excluded from proxy query, mentor self-registered records correctly include only self-attributed entries, null date range defaults applied correctly, pagination returns correct page. Integration test against Supabase test project with pre-seeded mixed record set (proxy and self-registered) verifying correct split between both methods. flutter_test with mocktail. 85%+ branch coverage.
Also manually validate that the results of both methods sum to total non-voided records for a given date range (completeness check).
Overly strict duplicate matching (exact date + type) may flag legitimate back-to-back sessions of the same activity type on the same day as duplicates, frustrating coordinators and undermining trust in the feature.
Mitigation & Contingency
Mitigation: Confirm with product owners whether the matching key should be (mentor_id, date, activity_type_id) only or should also consider duration and time-of-day. Document the chosen threshold in the service and surface it in the duplicate warning dialog for transparency.
Contingency: If false-positive rates are high in user testing, add a duration-window tolerance parameter to the detection query that can be tuned without code changes.
If the current session token is invalidated between the coordinator starting the proxy form and submitting it, the activity-attribution-service may fail to resolve the coordinator's user ID, causing a silent attribution error.
Mitigation & Contingency
Mitigation: Read the coordinator's user ID from the session at service call time rather than at form-open time. Validate the session is still active before committing the insert, and surface a clear re-authentication prompt if it has expired.
Contingency: If a mis-attributed record is detected post-submission, the audit log retains the original session metadata, allowing a corrective record to be created with accurate attribution.