core PK: id 8 required 1 unique

Description

A person being supported by a peer mentor — the primary beneficiary of the peer mentoring program. Contacts have personal details, associated activities, notes, and caregiver relationships. Contact data is role-scoped: peer mentors see only their own contacts, coordinators see all contacts in their association.

17
Attributes
7
Indexes
10
Validation Rules
41
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Globally unique identifier for the contact record, generated server-side on creation
PKrequiredunique
local_association_id uuid Foreign key to local_associations — defines which local association this contact belongs to, used as the primary scope boundary for role-based access control and Bufdir reporting aggregation
required
created_by_user_id uuid Foreign key to users — the peer mentor or coordinator who created this contact record. Used to enforce peer-mentor-scoped visibility (peer mentors only see contacts they created)
required
first_name string Contact's given name. Required for identification in the contact list, activity wizard contact step, and coordinator reports
required
last_name string Contact's family name. Required for full-name display and FTS5 search indexing
required
phone string Contact's primary phone number in E.164 format (e.g. +4791234567). Used by peer mentors to initiate contact and displayed in caregiver detail screens
-
email string Contact's email address. Optional — many contacts (elderly, low-digital-literacy) may not have one. Stored lowercased
-
address text Full postal address as a freeform text field. Used by Location Service for geographic matching (geocoding to lat/lng for coordinator map view) and by Blindeforbundet coordinators when dispatching encrypted assignments
-
date_of_birth datetime Contact's date of birth (date portion only, stored as timestamp at midnight UTC). Used to compute age for Bufdir demographic reporting and to identify contacts requiring caregiver relationships (children, elderly)
-
gender enum Contact's gender identity. Collected for Bufdir demographic reporting which requires participant breakdown by gender category
-
preferred_contact_method enum How the contact prefers to be reached by their peer mentor. Informs the activity registration wizard defaults and coordinator matching
-
is_active boolean Whether this contact is currently active and available for activity registration. Inactive contacts are hidden from the activity wizard contact step but remain accessible in contact detail for historical records
required
notes_preview string Cached snippet of the most recent note for display in contact card widgets and list screens. Populated server-side after note creation/update. Not user-editable directly — updated by Notes Service
-
last_activity_at datetime Timestamp of the most recent activity registered for this contact. Denormalized field updated after each activity save for efficient sorting in contact list screens without joins. Used by the scenario-based reminder system to detect contacts with no recent interaction (10-day follow-up alert)
-
created_at datetime Timestamp when the contact record was first created. Set server-side, immutable
required
updated_at datetime Timestamp of the most recent update to any contact field. Updated automatically on every write
required
deleted_at datetime Soft-delete timestamp. NULL means active; a non-null value means the contact has been soft-deleted (GDPR erasure or coordinator deactivation). Soft-deleted contacts are excluded from all normal queries but retained for audit log integrity until the retention period expires
-

Database Indexes

idx_contact_local_association_id
btree

Columns: local_association_id

idx_contact_created_by_user_id
btree

Columns: created_by_user_id

idx_contact_local_association_last_name
btree

Columns: local_association_id, last_name

idx_contact_deleted_at
btree

Columns: deleted_at

idx_contact_last_activity_at
btree

Columns: last_activity_at

idx_contact_local_association_active
btree

Columns: local_association_id, is_active, deleted_at

idx_contact_fts5_name
fts5

Columns: first_name, last_name

Validation Rules

first_name_required error

Validation failed

last_name_required error

Validation failed

phone_e164_format error

Validation failed

email_format error

Validation failed

date_of_birth_not_future error

Validation failed

date_of_birth_minimum error

Validation failed

local_association_exists error

Validation failed

at_least_one_contact_detail warning

Validation failed

update_requires_role_permission error

Validation failed

address_length error

Validation failed

Business Rules

role_scoped_visibility
always

Peer mentors may only read and write contacts that they created (created_by_user_id = current user). Coordinators can access all contacts within their local_association_id scope. Organization admins and global admins have read access across their full organizational scope. This rule is enforced at both the service layer and via SQL WHERE clauses in the repository.

local_association_immutable_after_create
on_update

The local_association_id of a contact cannot be changed after creation. Moving a contact between associations would break activity, note, and assignment history integrity and cross-association data isolation.

soft_delete_only
on_delete

Contacts must never be hard-deleted. Deletion sets deleted_at to the current timestamp. Soft-deleted contacts are excluded from all list and search queries but retained for activity history integrity, audit logs, and GDPR data subject access requests.

last_activity_at_denormalization
on_update

The last_activity_at field must be updated whenever a new activity is created, updated, or deleted for this contact. This denormalization enables efficient sorting in contact list screens and powers the 10-day no-contact reminder scenario without requiring an expensive join on the activities table.

notes_preview_cache_invalidation
on_update

The notes_preview field must be refreshed whenever a note linked to this contact is created, updated, or soft-deleted. The Notes Service is responsible for triggering this update after successful note persistence.

multi_coordinator_duplicate_detection
on_create

When registering an activity for a contact, the Duplicate Detection Service checks whether the same peer mentor has already registered an activity with the same contact on the same date and of the same activity type (with a ±1 day fuzzy window). This addresses NHF's requirement to prevent double-reporting across multiple coordinators in the same local association.

caregiver_relationship_required_for_minors
on_create

For organizations supporting children (Barnekreftforeningen) or contacts identified as minors based on date_of_birth, the system emits a warning if a caregiver record has not been associated. Not a hard block — coordinators can dismiss and proceed.

offline_queue_sync
always

Contact create and update operations performed while the device is offline are enqueued in the offline queue and replicated to PostgreSQL on next connectivity restore via the Sync Service. Conflict resolution uses server-wins policy.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
Permanent Storage

Entity Relationships

activity
outgoing one_to_many

A contact (person being supported) is the subject of many activities registered by peer mentors

optional
assignment
outgoing one_to_many

A contact may be the subject of multiple encrypted assignments dispatched to different peer mentors

optional
caregiver
outgoing one_to_many

A contact can have multiple caregivers or next-of-kin associated with them

optional
note
outgoing one_to_many

A contact is the subject of many notes capturing qualitative context from interactions

required

Components Managing This Entity

infrastructure Auth Middleware ["backend"] service Role Guard Service ["mobile"] service Activity Service ["mobile"] service Default Values Provider ["mobile"] data Contact Repository Cache ["mobile"] service Activity Service ["mobile"] service Wizard State Manager ["mobile"] ui Contact Step Screen ["mobile"] ui Summary Step Screen ["mobile"] service Proxy Registration Service ["mobile","backend"] data Contact Repository ["mobile"] infrastructure FTS5 Full-Text Search Index Infrastructure ["mobile"] service Contact Service ["mobile"] service Role Guard Service ["mobile"] service Search Service ["mobile"] ui Contact Card Widget ["mobile"] ui Contact Search Bar Widget ["mobile"] ui Contacts List Screen ["mobile"] data Contact Repository ["mobile"] service Contact Service ["mobile"] ui Contact Detail Screen ["mobile"] ui Contact Form Widget ["mobile"] ui Edit Contact Screen ["mobile"] data Caregiver Repository ["backend"] service Caregiver Service ["backend"] service Notes Service ["mobile","backend"] service Location Service ["mobile","backend"] service Statistics Service ["mobile"] service Report Aggregation Service ["backend"] service Duplicate Detection Service ["backend"] ui Participant List Widget ["mobile"] service Annual Summary Aggregation Job ["backend"] service Annual Summary Service ["mobile","backend"] service Statistics Service ["backend"] data Local Cache Repository ["mobile"] data Offline Queue Repository ["mobile"] infrastructure Local Database Infrastructure ["mobile"] service Conflict Resolution Service ["mobile"] service Sync Service ["mobile"]