Define ProxyRegistration domain types and result contracts
epic-proxy-activity-registration-orchestration-task-001 — Define all strongly-typed Dart classes for ProxyRegistrationRequest, ProxyRegistrationResult, and the discriminated union result variants (ProxyRegistrationSuccess, ProxyRegistrationDuplicateConflict, ProxyRegistrationError). These types form the contract boundary between the service layer and the BLoC, ensuring the BLoC can map results directly to UI states without additional business logic.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 6 - 158 tasks
Can start after Tier 5 completes
Implementation Notes
Use Dart's sealed classes (Dart 3.0+) for ProxyRegistrationResult to enable exhaustive pattern matching in the BLoC — this eliminates the need for an 'else' branch and ensures new variants are caught at compile time. If the codebase targets Dart < 3.0, use a manual union pattern with a private constructor and static factory methods. Define ProxyRegistrationErrorCode as an enum (not string constants) so the BLoC switch statement is exhaustive. Keep validation logic in ProxyRegistrationRequest's constructor (or a validate() factory) rather than in the service, so the BLoC receives a validated request and the service can assume inputs are structurally correct.
Place all types in lib/features/proxy_registration/domain/types/ to keep the domain layer clean and free of framework dependencies.
Testing Requirements
Unit tests using flutter_test. Test ProxyRegistrationRequest construction with valid data (succeeds), with duration_minutes = 0 (throws ArgumentError), with a future activity_date beyond threshold (throws ArgumentError). Test the discriminated union: use pattern matching (switch on result type) to verify each variant is distinguishable and carries its expected payload. Test equality: two ProxyRegistrationSuccess instances with the same record are equal.
Test copyWith on all classes. Full test file under test/services/proxy_registration_types_test.dart.
If the Supabase batch RPC partial-inserts some records before encountering an error and does not roll back cleanly, the bulk service may report failure while orphaned records exist in the database, corrupting reporting data.
Mitigation & Contingency
Mitigation: Wrap the bulk insert in an explicit Supabase transaction via the RPC function. Write an integration test that simulates a mid-batch constraint violation and asserts zero records were written.
Contingency: If a partial-write incident occurs, the registered_by audit field allows identification and deletion of the orphaned records. Implement a coordinator-facing bulk submission status screen to surface any such anomalies.
When a bulk submission of 15 participants has 4 duplicates, the aggregated conflict summary may be too complex for coordinators to process quickly, leading to blanket override decisions that defeat the purpose of duplicate detection.
Mitigation & Contingency
Mitigation: Design the conflict result type to support per-participant override flags, so the UI can present a clear list of conflicting participants with individual cancel/override toggles rather than a single global decision.
Contingency: If coordinator usability testing reveals the conflict review screen is too complex, simplify to a 'skip all conflicts and submit the rest' mode as an immediate fallback while a more granular UI is designed.
If the coordinator role check inside proxy-registration-service is inconsistent with the route-level guard, a regression in the guard could allow peer mentors to call the service directly via deep links, submitting records with incorrect attribution.
Mitigation & Contingency
Mitigation: Enforce role authorization at both the route guard level (coordinator-role-guard) and inside each service method independently. Write a security test that calls the service directly with a peer mentor session token and asserts rejection.
Contingency: If a bypass is discovered, immediately enable the server-side RLS policy as the final enforcement layer and audit any records written during the exposure window using the registered_by field.