Define Contact and PeerMentor typed Dart models
epic-contact-list-management-foundation-task-005 — Create the immutable Contact and PeerMentor Dart model classes with all fields required by the contact list feature (id, name, organization_id, role, notes, chapter affiliations, assignment status). Implement fromJson factory constructors that safely parse Supabase JSON responses, handling null values and optional fields gracefully.
Acceptance Criteria
Technical Requirements
Implementation Notes
Define ContactRole and AssignmentStatus as Dart enums with a static fromString(String) factory that uses a switch with a default case — never throw on unknown values from the server. Use the freezed or equatable package if already in pubspec for == and copyWith boilerplate; otherwise implement manually to keep dependencies minimal. Place models in lib/features/contacts/domain/models/. PeerMentor should be a separate class (not a subclass of Contact) to avoid Liskov substitution issues with the role field — share a common ContactBase interface instead.
The Supabase contacts table likely uses snake_case column names; ensure fromJson maps organization_id → organizationId etc. Document the exact Supabase column names as constants at the top of each model file.
Testing Requirements
Unit tests using flutter_test covering: (1) Contact.fromJson with complete valid JSON, (2) Contact.fromJson with all optional fields null, (3) Contact.fromJson with unknown role string defaults gracefully, (4) PeerMentor.fromJson correctly sets certificationStatus and assignedMemberCount, (5) toJson → fromJson round-trip equality, (6) copyWith produces new instance with expected field change. Target 100% branch coverage on fromJson parsing logic.
Existing Supabase RLS policies for the contacts and peer_mentors tables may not align with the application-level UserRole model, causing ContactRLSQueryBuilder to construct filter expressions that are redundant, conflicting, or that allow over-fetching. In a multi-chapter context (NHF), this could expose contacts belonging to other chapters.
Mitigation & Contingency
Mitigation: Audit and document the existing RLS policies against the UserRole enum before writing a single line of query builder code. Write integration tests asserting cross-organization data isolation using separate test user tokens for each role.
Contingency: If RLS policies are misaligned at runtime, add an explicit application-level organization_id equality check in ContactRepository as a secondary guard while the database policies are corrected in a coordinated migration.
The Supabase schema for contacts and peer_mentors tables may differ from the expected typed models — missing columns, renamed fields, or type mismatches — causing deserialization failures that surface only at runtime during integration testing.
Mitigation & Contingency
Mitigation: Document expected schema fields upfront and validate against the live Supabase schema at sprint start. Use freezed and json_serializable for compile-time-safe deserialization with explicit required/optional field declarations.
Contingency: Introduce nullable fields with safe defaults for any schema mismatches discovered in testing; log deserialization errors to the monitoring service so schema drift is caught before production deployment.