core PK: id 9 required 2 unique

Description

Core identity entity representing all platform users across Peer Mentor, Coordinator, Organization Admin, and Global Admin roles. Central to all operational data in the Meander platform.

24
Attributes
6
Indexes
7
Validation Rules
26
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Primary key, globally unique user identifier
PKrequiredunique
email string User's email address, used for login and notifications
requiredunique
password_hash string Bcrypt hash of user's password. NULL if user authenticates exclusively via BankID, Vipps, or passkeys
-
first_name string User's given name
required
last_name string User's family name
required
phone_number string User's phone number, used for SMS notifications and Vipps auth matching
-
national_id string Norwegian national identity number (personnummer). Populated via Vipps/BankID authentication. Stored encrypted. Used for member system matching.
-
status enum Account lifecycle status
required
primary_role enum The user's primary platform role determining their access surface (mobile app vs admin portal)
required
language_preference string Preferred UI language code (e.g. 'nb', 'nn', 'se')
-
accessibility_preferences json User accessibility settings: font size scale, high contrast mode, reduced motion. Supports WCAG 2.2 AA personalization.
-
avatar_url string URL to user's profile photo stored in cloud storage
-
invited_by_user_id uuid FK to the admin or coordinator who created the invitation for this user
-
invitation_token string One-time token sent via email during onboarding. Cleared after first login.
-
invitation_expires_at datetime Expiry timestamp for the invitation token
-
last_login_at datetime Timestamp of the user's most recent successful authentication
-
last_active_at datetime Timestamp of most recent API activity, used for session monitoring and inactivity detection
-
biometric_enabled boolean Whether the user has enabled biometric unlock (Face ID / fingerprint) on their device
required
push_token string Device push notification token (FCM/APNs). Updated on each app launch.
-
push_token_updated_at datetime When the push_token was last refreshed
-
deactivated_at datetime Timestamp when the account was deactivated. NULL if active.
-
deactivated_by_user_id uuid FK to the admin who performed the deactivation
-
created_at datetime Record creation timestamp
required
updated_at datetime Record last-updated timestamp
required

Database Indexes

idx_users_email
btree unique

Columns: email

idx_users_status
btree

Columns: status

idx_users_primary_role
btree

Columns: primary_role

idx_users_invitation_token
btree

Columns: invitation_token

idx_users_last_login_at
btree

Columns: last_login_at

idx_users_invited_by
btree

Columns: invited_by_user_id

Validation Rules

email_unique_and_valid error

Validation failed

invitation_expiry error

Validation failed

password_strength error

Validation failed

national_id_format error

Validation failed

primary_role_immutable_after_invitation error

Validation failed

status_transition_validity error

Validation failed

phone_number_format warning

Validation failed

Business Rules

global_admin_no_org_data_access
always

Global Admins have no default access to any organization's operational data (users, activities, contacts). Access requires an explicit time-bounded support grant from the org, stored in support_access_grants.

org_admin_surfaced_as_coordinator_on_mobile
always

Users with primary_role=org_admin are surfaced as Coordinators in the mobile app. They use the coordinator mobile experience; admin-only capabilities exist exclusively in the admin portal.

peer_mentor_mobile_only
always

Users with primary_role=peer_mentor or coordinator may only authenticate to the mobile app. Attempts to access the admin portal must be rejected with a redirect to the no-access screen.

no_organization_selection_at_login
on_create

Organization context is determined by the user's account (set during invitation). Users do NOT choose their organization at login — there is no organization selection screen.

deactivation_preserves_historical_data
on_update

Deactivating a user sets status=inactive and records deactivated_at/deactivated_by. Historical activities, expenses, and contacts created by the user are preserved and remain queryable by admins.

invitation_single_use
on_update

invitation_token is cleared immediately upon first successful login. Expired or already-used tokens must be rejected.

Enforced by: AdminUserService
paused_peer_mentor_excluded_from_dispatch
always

Users with status=paused must not appear in assignment dispatch, coordinator proxy-reporting selectors, or geographic map views. Restored to active via resume flow.

vipps_national_id_sync
on_update

When a user authenticates via Vipps for the first time, the returned personnummer must be stored encrypted in national_id if not already present. This enables member system reconciliation.

support_access_time_bounded
always

Global Admin support access to an org's data is time-bounded via support_access_grants. Every action during a support session must be logged in the org's audit_logs.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
Permanent Storage

Entity Relationships

organizations
outgoing many_to_many
optional