high priority medium complexity database pending database specialist Tier 0

Acceptance Criteria

Repository fetches full contact profile including all base fields (name, email, phone, address, personnummer) and returns a typed ContactDetailModel
NHF-specific metadata fields are included in the response when org context is NHF, including chapter_affiliations array (up to 5 entries) and role_badges array
Blindeforbundet-specific metadata includes sensitive_field_identifiers list marking which fields are encrypted
All Supabase queries respect Row Level Security (RLS) policies — unauthorized access returns a typed PermissionDeniedError, not a raw Postgres error
Repository exposes a getContactDetail(String contactId) method returning Future<Either<ContactDetailFailure, ContactDetailModel>>
Network errors, Supabase client errors, and empty-result cases each map to distinct ContactDetailFailure subtypes
Chapter affiliation arrays are deserialized correctly from Supabase jsonb columns, including graceful handling of null or empty arrays
Sensitive field identifiers list is returned as a Set<String> of field keys, never including decrypted values
Repository is unit-testable via a Supabase client interface/mock — no direct static Supabase calls inside the class
Response models are fully immutable (using freezed or equivalent) with copyWith support

Technical Requirements

frameworks
Flutter
Riverpod
freezed
dartz (Either)
apis
Supabase PostgREST REST API
Supabase RLS policies
data models
ContactDetailModel
ChapterAffiliation
RoleBadge
ContactDetailFailure
performance requirements
Single Supabase query with joined tables (avoid N+1 queries)
Response deserialization under 50ms for typical contact records
Support prefetch call on route push to meet 500ms total load target
security requirements
Never fetch or log raw encrypted field values in repository layer
All queries must pass through authenticated Supabase client (JWT present)
RLS policies must be the enforcement boundary — repository must not implement its own visibility filtering as the sole control
Do not cache raw sensitive field values in memory beyond the immediate request lifecycle

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use the repository pattern with an abstract interface (ContactDetailRepository) and a concrete SupabaseContactDetailRepository. Inject the Supabase client via constructor for testability. Use a single `.from('contacts').select('*, chapter_affiliations(*), role_badges(*)')` style query with Supabase's relationship expansion rather than multiple round-trips. For org-specific fields, use a strategy pattern or org-context parameter to select the correct column set at query build time — avoid runtime `if (org == NHF)` branches scattered throughout.

Map all Supabase exceptions in a dedicated _mapException() private method. Use freezed for ContactDetailModel and all failure types to ensure immutability and exhaustive pattern matching at call sites.

Testing Requirements

Unit tests using flutter_test with a mocked Supabase client interface. Test cases must cover: successful fetch with NHF org context (verify chapter_affiliations populated), successful fetch with Blindeforbundet org context (verify sensitive_field_identifiers populated), network timeout mapped to NetworkFailure, RLS denial (403) mapped to PermissionDeniedFailure, empty result (contact not found) mapped to NotFoundFailure, malformed jsonb in chapter_affiliations handled without crash. Integration test against a local Supabase instance (or staging) verifying RLS rules reject cross-org access. Aim for 90%+ line coverage on the repository class.

Component
Contact Detail Screen
ui medium
Epic Risks (2)
low impact medium prob dependency

The Peer Mentor Profile tab on the contact detail screen depends on the peer-mentor-detail-screen-widget being delivered by the separate Peer Mentor Detail feature. If that feature is delayed, the navigation affordance will be present but lead to a stub screen, which may confuse coordinators in the TestFlight pilot.

Mitigation & Contingency

Mitigation: Implement the peer mentor tab with a feature flag guard. When the Peer Mentor Detail feature is incomplete, the flag disables the tab. Coordinate delivery timelines with the team responsible for Peer Mentor Detail to align TestFlight releases.

Contingency: If the Peer Mentor Detail feature is significantly delayed, ship the contact detail screen without the peer mentor tab in the first TestFlight build and add it as an incremental update once the dependent screen is ready.

medium impact medium prob technical

The contact detail screen must adapt its layout significantly based on organisation context: NHF shows affiliation chips, Blindeforbundet shows encrypted fields and assignment status, standard contacts show neither. Managing this conditional rendering without introducing bugs in each variant is complex and increases the risk of organisation-specific regressions.

Mitigation & Contingency

Mitigation: Define a ContactDetailViewModel that resolves all org-specific flags (showEncryptedFields, showAssignmentStatus, showMultiChapterChips) from the organisation config before the widget tree renders. Widget tests must cover all three organisation variants as separate test cases to catch regressions.

Contingency: If conditional rendering logic grows unwieldy, refactor into separate composable section widgets (ProfileHeaderSection, AffiliationSection, EncryptedFieldsSection) that are conditionally included by the parent screen, isolating org-specific logic to individual components.