core PK: id 10 required 1 unique

Description

Represents an individual who is served by or associated with a peer mentor programme — a service recipient, family member, or professional referral. Contact records include profile fields, notes, and assignment history. Some fields (address, medical context) are encrypted at rest and require screen reader disclosure warnings before vocalization.

20
Attributes
7
Indexes
8
Validation Rules
24
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Primary key, generated server-side as a UUID v4
PKrequiredunique
organization_id uuid Foreign key to the organization that owns this contact record. Enforces multi-tenant data isolation via Supabase RLS. All queries must be scoped to this value.
required
first_name string Contact's given name. Stored in plain text. Used for display, search, and screen reader announcements.
required
last_name string Contact's family name. Stored in plain text. Combined with first_name for full-name search and display.
required
email string Contact's email address. Optional. Must pass RFC 5322 format validation when provided. Not unique globally; uniqueness is scoped per organization.
-
phone string Contact's phone number in Norwegian or international E.164 format. Optional. Used for coordinator lookup and assignment matching.
-
address_encrypted text Contact's physical address, encrypted at rest using organization-scoped keys. Must not be vocalized by screen readers without first triggering the sensitive field disclosure warning dialog. Decrypted on demand by field-encryption-utils.
-
medical_context_encrypted text Medical background or epikrise (clinical summary) relevant to the peer mentoring relationship, e.g., diagnosis or functional limitations. Encrypted at rest. Requires disclosure warning before vocalization. Used primarily by Blindeforbundet for home-visit context.
-
notes text Free-text notes about the contact written by coordinators or peer mentors. Indexed for full-text search within the organization. Not encrypted but access-controlled via RLS.
-
contact_type enum Categorizes the nature of the contact's relationship to the programme. Determines how the contact is filtered in role-specific list views.
required
status enum Lifecycle status of the contact record. Archived contacts are hidden from default list views but retained for reporting. Inactive contacts are not assignable.
required
date_of_birth datetime Contact's date of birth. Optional. Used for demographic reporting and eligibility checks. Must not be a future date.
-
gender string Self-reported gender identity. Optional, free-form to accommodate all identities. Used for Bufdir demographic reporting where required.
-
preferred_contact_method enum Preferred communication channel for reaching this contact. Informs coordinators and peer mentors before initiating outreach.
-
is_deleted boolean Soft-delete flag. When true, the contact is excluded from all standard queries and UI views. Hard deletion is never performed to preserve audit and reporting integrity.
required
deleted_at datetime Timestamp when is_deleted was set to true. Null for non-deleted records. Used for audit trails and compliance reporting.
-
created_by uuid User ID of the coordinator or admin who created the contact record. Immutable after creation.
required
updated_by uuid User ID of the last user to modify this contact record. Updated on every write operation.
-
created_at datetime UTC timestamp of record creation. Set server-side and immutable.
required
updated_at datetime UTC timestamp of the last update. Maintained via Supabase database trigger on every write.
required

Database Indexes

idx_contact_organization_id
btree

Columns: organization_id

idx_contact_org_status
btree

Columns: organization_id, status

idx_contact_org_name
btree

Columns: organization_id, last_name, first_name

idx_contact_org_email
btree

Columns: organization_id, email

idx_contact_is_deleted
btree

Columns: organization_id, is_deleted

idx_contact_created_at
btree

Columns: organization_id, created_at

idx_contact_notes_fts
gin

Columns: organization_id, notes

Validation Rules

first_last_name_required error

Validation failed

email_format error

Validation failed

phone_format error

Validation failed

organization_must_be_active error

Validation failed

date_of_birth_not_future error

Validation failed

chapter_count_max_five error

Validation failed

notes_length_limit error

Validation failed

status_transition_validity error

Validation failed

Business Rules

org_data_isolation
always

Every contact record must be scoped to exactly one organization_id. Supabase RLS policies enforce that authenticated users can only read or write contacts belonging to their active organization session. No cross-organization contact access is permitted.

max_chapter_affiliations
on_create

A contact may belong to a maximum of 5 local chapters simultaneously (NHF requirement). Attempting to add a sixth chapter affiliation must be rejected with a user-visible error. This limit is enforced both at the service layer and in the UI form validator.

encrypted_field_authorization
always

The address_encrypted and medical_context_encrypted fields may only be decrypted for users holding a coordinator or organization-admin role for the owning organization. Peer mentors receive these fields in their encrypted form only when explicitly authorized per assignment. Decryption is logged.

screen_reader_sensitive_field_warning
always

Before any screen reader (VoiceOver, TalkBack) vocalizes address_encrypted or medical_context_encrypted content, the sensitive-field-warning-dialog must be displayed and explicitly acknowledged by the user. This warning may be suppressed for the remainder of the session after first acknowledgement.

soft_delete_only
on_delete

Contact records are never physically deleted from the database. All delete operations set is_deleted=true and deleted_at=now(). This preserves referential integrity for activity records, assignments, and Bufdir reports that reference the contact.

read_receipt_on_field_reveal
on_update

Whenever a user explicitly reveals an encrypted field (address or medical context) in the UI, a read-receipt record must be written to Supabase with the user ID, field key, contact ID, and UTC timestamp. This supports Blindeforbundet's information security audit requirements.

cross_chapter_duplicate_detection
always

When a contact is affiliated with multiple chapters (NHF), the system must detect and warn if the same activity is registered for this contact by coordinators of different chapters within the same reporting period. This prevents double-counting in Bufdir submissions.

search_scope_isolation
always

Contact search results must always be filtered by the current user's organization_id. Full-text search on the notes field and ILIKE queries on name fields must include the organization_id predicate to prevent cross-tenant data leakage.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
Permanent Storage

Entity Relationships

assignment
outgoing one_to_many

A contact may be assigned to peer mentors sequentially or simultaneously depending on organizational rules

optional
contact_chapter
outgoing one_to_many

A contact (especially in NHF) may belong to up to 5 local chapters simultaneously through the contact_chapter junction

optional cascade delete
organization
incoming one_to_many

All contacts are scoped to a single organization for multi-tenant data isolation via Supabase RLS

required

Components Managing This Entity

service Permission Checker Service ["mobile"] data Proxy Contact List Provider ["mobile"] data Contact List Riverpod Provider ["mobile"] data Contact Repository ["mobile"] infrastructure Contact RLS Query Builder ["mobile"] service Contact List Service ["mobile"] service Contact Search Service ["mobile"] data Contact Detail Repository ["mobile"] infrastructure Contact Form Validator ["mobile"] infrastructure Field Encryption Utilities ["mobile"] service Contact Detail Service ["mobile"] service Contact Edit Service ["mobile"] service Read Receipt Service ["mobile"] ui Encrypted Field Display Widget ["mobile"] data Contact Chapter Repository ["mobile","backend"] data Cross-Chapter Activity Query ["mobile","backend"] infrastructure Duplicate Warning Event Logger ["mobile"] service Duplicate Activity Detection Service ["mobile","backend"] service Multi-Chapter Membership Service ["mobile","backend"] ui Duplicate Activity Warning Dialog ["mobile"] data Contact Cache Sync Repository ["mobile"] data Offline Contact Search Repository ["mobile"] data Supabase Contact Search Repository ["mobile"] service Contact Search Service ["mobile"] data Aggregation Query Builder ["backend"] data Admin Data Repository ["backend"] service Admin Row-Level Security Guard ["backend"] service User Management Service ["backend"] service Bufdir Activity Query Service ["backend"] data Sensitive Field Configuration ["mobile"] service Sensitive Field Privacy Guard ["mobile"] ui Sensitive Field Warning Dialog ["mobile"] infrastructure Supabase RLS Tenant Scope Configurator ["mobile"]