Dart model: BulkRegistrationRequest
epic-proxy-activity-registration-foundation-task-007 — Implement the `BulkRegistrationRequest` Dart class that wraps a list of `BulkParticipant` and a shared `ProxyActivityRecord` template. Fields: participants (List<BulkParticipant>), activityTemplate (ProxyActivityRecord), submittedAt, organizationId. Include `fromJson`/`toJson`, `copyWith`, and Equatable. Write unit tests for participant filtering helpers.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
The toJson output must align with the expected payload structure of the bulk_register_activities Supabase RPC (defined in task-002). Coordinate with the RPC definition to ensure field names match exactly. Suggested toJson structure: `{'participants': participants.map((p) => p.toJson()).toList(), 'activity_template': activityTemplate.toJson(), 'submitted_at': submittedAt?.toIso8601String(), 'organization_id': organizationId}`. The activityTemplate in toJson should omit the id field (it will be null pre-insert) and the createdAt field.
Use `List.unmodifiable(participants)` in the constructor to prevent external mutation. The Equatable props list comparison works correctly with Equatable for List fields as long as the list elements are themselves Equatable — which BulkParticipant and ProxyActivityRecord are.
Testing Requirements
Write flutter_test unit tests in test/features/proxy_activity/models/bulk_registration_request_test.dart. Cover: (1) selectedParticipants returns empty list when none selected, (2) selectedParticipants returns all when all selected, (3) selectedParticipants returns subset for mixed selection, (4) hasConflicts false when all ConflictStatus.none, (5) hasConflicts true when any warning or duplicate, (6) blockingConflicts returns only duplicates, (7) round-trip serialisation including nested objects, (8) copyWith replaces participants and preserves other fields. Minimum 8 test cases.
The activities table migration adding registered_by and attributed_to columns may conflict with existing RLS policies or FK constraints if the user profile table structure differs from assumptions, blocking all subsequent epics.
Mitigation & Contingency
Mitigation: Review existing activities table schema and RLS policies before writing the migration. Run the migration against a staging database clone first. Write rollback scripts alongside the migration.
Contingency: If migration fails in staging, isolate the conflict with a targeted schema audit, adjust FK references or RLS policy scope, and re-run before touching production.
The RLS policy must filter proxy inserts to the coordinator's chapter scope. If the chapter-scope resolver pattern differs between organisations (multi-chapter coordinators in NHF vs single-chapter in HLF), the policy may be too broad or too restrictive.
Mitigation & Contingency
Mitigation: Design the RLS policy to accept a coordinator's full set of assigned chapter IDs (array) rather than a single chapter_id. Validate the policy against NHF multi-chapter test fixtures during the integration test phase.
Contingency: If the policy is found to be incorrect after deployment, introduce a server-side validation edge function as a safety net while the RLS policy is corrected.
The bulk_register_activities RPC function may time out or cause lock contention when inserting large participant batches (e.g. 40+ peer mentors in a single group session), degrading the user experience.
Mitigation & Contingency
Mitigation: Benchmark the RPC function with 50-participant batches during development. Use unnest-based bulk insert rather than row-by-row PL/pgSQL loops. Set a reasonable statement_timeout.
Contingency: If performance is insufficient, split the client-side submission into chunks of 20 participants with progress feedback, rather than a single RPC call.