high priority low complexity backend pending backend specialist Tier 0

Acceptance Criteria

BulkParticipant is a final class extending Equatable
conflictStatus is a Dart enum with values: none, warning, duplicate
All fields are final: peerId (String), displayName (String), selected (bool, default true), conflictStatus (ConflictStatus, default none)
fromJson parses conflictStatus from string using a safe fallback to ConflictStatus.none for unrecognised values
toJson serialises conflictStatus as its name string (e.g., 'warning')
copyWith supports toggling selected and changing conflictStatus independently
Equatable props covers all four fields
Unit test: unknown conflictStatus string falls back to ConflictStatus.none without throwing
Unit test: round-trip serialisation for each ConflictStatus value
Unit test: default constructor sets selected=true and conflictStatus=none
File placed at lib/features/proxy_activity/models/bulk_participant.dart

Technical Requirements

frameworks
Flutter
equatable
data models
BulkParticipant
user_roles (peer_mentor)
performance requirements
Enum parsing must be O(1) — use a static lookup map or switch expression, not linear iteration
security requirements
displayName is display-only and must be escaped before rendering in any HTML/web context
peerId is a UUID — validate format if parsing from untrusted sources
ui components
BulkParticipantTile (checkbox list item showing displayName + conflict badge)

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Define ConflictStatus as an enum in the same file or in a separate enums file under the proxy_activity feature. Use a static extension or a switch expression for safe fromJson parsing: `ConflictStatus.values.firstWhere((e) => e.name == value, orElse: () => ConflictStatus.none)`. This is safer than direct index access. The selected field will be mutated frequently in UI state (checkbox toggling), so Riverpod or BLoC state will hold List and emit new lists via copyWith — ensure copyWith is correctly implemented.

Do not add mutable state to the model itself.

Testing Requirements

Write flutter_test unit tests in test/features/proxy_activity/models/bulk_participant_test.dart. Cover: (1) full round-trip for each of the three ConflictStatus values, (2) unknown status string falls back to none, (3) default values for selected and conflictStatus, (4) copyWith(selected: false) only changes selected, (5) copyWith(conflictStatus: ConflictStatus.warning) only changes status, (6) Equatable equality and inequality. Minimum 6 test cases.

Component
Proxy Activity Data Models
data low
Epic Risks (3)
high impact medium prob technical

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.

high impact medium prob security

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.

medium impact low prob technical

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.