high priority low complexity backend pending backend specialist Tier 2

Acceptance Criteria

BulkRegistrationDefaultsProvider is a Riverpod StateNotifierProvider<BulkRegistrationDefaults> accessible app-wide
On first app launch (no persisted data), defaults are: date = today (device local date), duration = 30 minutes, organisation_id = authenticated coordinator's org id, activity_type = null
After a successful bulk registration, the last-used activity_type is persisted to SharedPreferences and loaded on next app start
reset() restores state to fresh defaults (today's date, 30 min, coordinator org, null activity type) without clearing SharedPreferences history
applyDefaults(BulkRegistrationRequest) returns a new BulkRegistrationRequest with any null/unset fields populated from current defaults, leaving explicitly set fields unchanged
Organisation id is always sourced from the authenticated session, never hardcoded or from SharedPreferences
SharedPreferences key namespace is prefixed to avoid collisions (e.g., 'bulk_reg_defaults.')
Provider correctly reinitialises defaults when the authenticated user changes (coordinator switches account)
Unit tests cover initial state, persistence round-trip, reset(), and applyDefaults() merge logic

Technical Requirements

frameworks
Flutter
Riverpod
apis
SharedPreferences (flutter package)
Supabase Auth (coordinator org id)
data models
BulkRegistrationRequest
BulkRegistrationDefaults (state class)
ActivityType enum
performance requirements
SharedPreferences read/write must be async and must not block the UI thread during form initialisation
Provider state initialisation must complete before the bulk registration form renders its first frame — use AsyncNotifier or FutureProvider if needed
security requirements
Do not persist any personally identifiable information (peer mentor names, participant data) in SharedPreferences
Organisation id must be re-read from session on each app start, not from SharedPreferences, to prevent cross-account data leakage

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use StateNotifier with a dedicated state class (immutable, copyWith). Initialise async state in the StateNotifier constructor via an init() method called from the provider's create callback — or use AsyncNotifier for cleaner async init. Only persist the last-used activity_type to SharedPreferences; derive date and duration from constants at runtime to avoid stale data bugs. Use a const for the default duration (30 minutes) defined in a shared constants file.

The applyDefaults() method should follow a 'fill-in-blanks' pattern: iterate over BulkRegistrationRequest fields and substitute defaults only where the field is null. Keep SharedPreferences interaction behind an abstraction (e.g., DefaultsPersistence interface) so unit tests can inject a fake without platform channel overhead.

Testing Requirements

Unit tests with flutter_test and a mocked SharedPreferences instance (using shared_preferences_platform_interface test stubs). Test scenarios: (1) fresh install — verify all defaults match specification; (2) persist activity type after registration — verify correct key is written; (3) cold restart — verify activity_type is restored, date is today (not persisted date), duration is 30 min; (4) reset() — verify state reverts to spec defaults; (5) applyDefaults() with a fully populated request — verify no fields are overwritten; (6) applyDefaults() with a partially populated request — verify only null/unset fields are filled; (7) coordinator account change — verify org id updates to new coordinator's org.

Component
Bulk Registration Defaults Provider
infrastructure 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.