Assignment
Data Entity
Description
An encrypted sensitive data dispatch from a coordinator to a peer mentor, containing personal information about a contact (name, address, medical summary/epikrise). Tracks the full lifecycle from dispatch through read confirmation and contact establishment, and feeds the threshold-based honorarium counting system used by Blindeforbundet.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key — stable identifier for the assignment record | PKrequiredunique |
organization_id |
uuid |
Tenant scoping — every assignment belongs to exactly one organization; enforces row-level isolation | required |
contact_id |
uuid |
The contact whose sensitive data is enclosed in this assignment; maps to the contacts table | required |
assigned_to_user_id |
uuid |
Peer mentor who receives and acts on the assignment; null until a specific mentor is chosen | - |
dispatched_by_user_id |
uuid |
Coordinator or org admin who created and dispatched the assignment | required |
title |
string |
Short, non-sensitive label visible before decryption (e.g. 'Home visit assignment – Oslo Nord'); max 200 chars | required |
encrypted_payload |
text |
AES-256-GCM encrypted blob containing the sensitive personal data: full name, address, and medical summary (epikrise). Only decryptable by the assigned peer mentor using the key referenced by encryption_key_id. | required |
encryption_key_id |
string |
Reference to the symmetric key in the secure key store used to encrypt the payload; rotated per assignment | required |
status |
enum |
Lifecycle stage of the assignment. Follows a strict forward-only state machine. | required |
accounting_period |
string |
Accounting period used for threshold counting, formatted YYYY-QN (e.g. '2025-Q2'). Honorarium tier is evaluated per mentor per period. | - |
threshold_count_at_dispatch |
integer |
Snapshot of the mentor's completed assignment count at the moment of dispatch for this period. Used to determine honorarium tier without requiring a count query at pay time. | - |
geographic_region |
string |
Free-text region hint used by geographic-match-service to rank eligible mentors; derived from contact address at dispatch time | - |
consent_required |
boolean |
Whether the peer mentor must complete a Progressive Digital Consent flow before the payload is decrypted; always true for medical data | required |
dispatched_at |
datetime |
UTC timestamp when the assignment was sent to the peer mentor's inbox; null until status transitions to dispatched | - |
read_at |
datetime |
UTC timestamp when the peer mentor first opened and decrypted the payload; triggers delivery confirmation | - |
contact_established_at |
datetime |
UTC timestamp when the peer mentor confirmed first contact with the assigned person; resets the 10-day reminder clock | - |
completed_at |
datetime |
UTC timestamp when the assignment was marked completed by the peer mentor; used for threshold counting and Bufdir reporting | - |
expires_at |
datetime |
UTC deadline after which the assignment is auto-expired; typically 90 days after dispatch unless configured otherwise per org | - |
reminder_sent_at |
datetime |
UTC timestamp of the most recent 10-day follow-up reminder to the coordinator; null if reminder has not been triggered | - |
coordinator_notes |
text |
Internal non-encrypted notes from the dispatching coordinator; not shown to the peer mentor; supports coordinator handoff context | - |
created_at |
datetime |
UTC record creation timestamp | required |
updated_at |
datetime |
UTC last-modified timestamp; updated on every status transition | required |
Database Indexes
idx_assignments_organization_id
Columns: organization_id
idx_assignments_assigned_to_user_id
Columns: assigned_to_user_id
idx_assignments_contact_id
Columns: contact_id
idx_assignments_status
Columns: status
idx_assignments_organization_status
Columns: organization_id, status
idx_assignments_user_period_status
Columns: assigned_to_user_id, accounting_period, status
idx_assignments_expires_at
Columns: expires_at
Validation Rules
encrypted_payload_non_empty
error
Validation failed
contact_belongs_to_organization
error
Validation failed
assignee_is_peer_mentor
error
Validation failed
accounting_period_format
error
Validation failed
status_transition_timestamp_consistency
error
Validation failed
expires_at_after_dispatched_at
error
Validation failed
Business Rules
dispatch_role_guard
Only users with Coordinator or Organization Admin role within the same organization may create and dispatch assignments. Peer mentors cannot create assignments.
payload_decrypt_only_for_assignee
The encrypted_payload may only be decrypted for the peer mentor whose id matches assigned_to_user_id. Any other user — including other coordinators — must never receive the plaintext payload.
consent_gate_before_decryption
When consent_required is true, the encrypted_payload is unlocked only after the peer mentor has completed and persisted the Progressive Digital Consent flow (assignment_consents record with status = accepted).
payload_immutable_after_dispatch
Once status transitions to dispatched, the encrypted_payload and encryption_key_id fields are immutable. A cancelled assignment must be recreated — not edited — to resend corrected data.
ten_day_contact_reminder
If contact_established_at remains null 10 days after dispatched_at, a reminder notification is sent to the dispatching coordinator and reminder_sent_at is recorded. Triggered by a scheduled job.
threshold_honorarium_counting
On transition to completed status, the system increments the mentor's assignment count for the accounting_period. Count = 3 triggers first-tier office honorarium; count = 15 triggers the higher-rate honorarium. The snapshot threshold_count_at_dispatch is captured at dispatch time.
forward_only_status_transitions
Status must advance through: pending → dispatched → read → in_progress → completed. Lateral transitions to expired or cancelled are allowed from any non-terminal state, but reverting to an earlier state is prohibited.
organization_tenant_isolation
Assignments, contacts, and mentors involved must all belong to the same organization_id. Cross-organization assignment dispatch is prohibited.