core PK: id 8 required 4 unique

Description

Core identity record for all platform users across Meander Mobile App and Admin Web Portal. Represents Peer Mentors, Coordinators, Organization Admins, and Global Admins. Organization context is set during onboarding — users never choose their organization at login.

25
Attributes
7
Indexes
8
Validation Rules
46
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Primary key, globally unique user identifier
PKrequiredunique
email string Email address used for login and notifications. Normalized to lowercase.
requiredunique
password_hash string Argon2id hash of the user's password. Null for users who authenticate exclusively via BankID, Vipps, or Passkeys.
-
full_name string User's full display name as entered during onboarding or set by admin.
required
phone_number string Mobile phone number in E.164 format. Used for SMS notifications and as secondary contact.
-
national_id string Norwegian national identity number (personnummer). Populated via BankID or Vipps login. Encrypted at rest. Used for Bufdir reporting and member system reconciliation.
-
role enum Primary platform role. Determines which product surfaces the user may access.
required
status enum Account lifecycle state. Inactive users cannot authenticate.
required
avatar_url string URL to profile photo stored in cloud storage. Optional.
-
preferred_language string BCP-47 language tag for UI localization. Defaults to 'nb' (Norwegian Bokmål).
-
accessibility_preferences json User-level accessibility overrides: font_scale, high_contrast, reduce_motion. Applied on top of system settings.
-
bankid_subject string BankID subject identifier returned after successful BankID authentication. Enables account linking without storing the national ID in plaintext.
unique
vipps_subject string Vipps subject identifier returned after successful Vipps login.
unique
invited_by_user_id uuid FK to the admin user who sent the invitation. Null for seed/system-created accounts.
-
invitation_token_hash string SHA-256 hash of the one-time invitation token. Cleared after first login.
-
invitation_expires_at datetime Expiry timestamp for the pending invitation link. Null once accepted.
-
email_verified_at datetime Timestamp when the user confirmed their email address. Null until verified.
-
last_login_at datetime Timestamp of most recent successful authentication. Updated on every login.
-
last_login_method enum Authentication method used in the most recent login.
-
paused_at datetime Timestamp when the user's status was set to paused. Null if not currently paused.
-
pause_reason enum Reason for the paused status.
-
is_test_user boolean Marks accounts belonging to the Norse Test Organization. Test user data is excluded from Bufdir reporting and external exports.
required
created_at datetime Record creation timestamp. Set once, never updated.
required
updated_at datetime Timestamp of last record modification. Managed by application layer.
required
deleted_at datetime Soft-delete timestamp. Non-null means the account is deactivated. GDPR erasure sets all PII fields to null and leaves only this tombstone.
-

Database Indexes

idx_users_email
btree unique

Columns: email

idx_users_bankid_subject
btree unique

Columns: bankid_subject

idx_users_vipps_subject
btree unique

Columns: vipps_subject

idx_users_role_status
btree

Columns: role, status

idx_users_status
btree

Columns: status

idx_users_deleted_at
btree

Columns: deleted_at

idx_users_invited_by
btree

Columns: invited_by_user_id

Validation Rules

email_unique_across_platform error

Validation failed

password_complexity error

Validation failed

phone_e164_format error

Validation failed

invitation_not_expired error

Validation failed

role_transitions_valid error

Validation failed

status_transitions_valid error

Validation failed

national_id_format_norwegian error

Validation failed

full_name_not_blank error

Validation failed

Business Rules

org_context_set_by_admin
on_create

A user's organization context is determined during invitation by an Org Admin. Users never select their organization at login time.

global_admin_no_org_data_access
always

Global Admins have no default access to any organization's operational data. Tenant separation is strict. Access requires an explicit time-bounded support_access_grant approved by the Org Admin.

Enforced by: RbacServiceAuthService
coordinator_and_peer_mentor_mobile_only
always

Peer Mentors and Coordinators are managed inside the admin portal but may never log in to it. Only org_admin and global_admin roles may authenticate to the Admin Web Portal.

org_admin_surfaced_as_coordinator_on_mobile
always

When an org_admin authenticates on the Mobile App, they receive the Coordinator mobile experience without a separate UI path.

pause_requires_coordinator_notification
on_update

When a Peer Mentor's status transitions to paused, the associated Coordinator must be notified via push notification.

certification_expiry_auto_pause
on_update

When a Peer Mentor's certification expires, their status is automatically set to paused and they are removed from public-facing coordinator listings.

test_user_excluded_from_bufdir
always

Users with is_test_user=true must be excluded from all Bufdir report snapshots and external exports.

soft_delete_only
on_delete

User records are never hard-deleted. Deactivation sets deleted_at. GDPR erasure nullifies all PII fields but retains the row for audit trail integrity.

invitation_single_use
on_update

The invitation token is one-time-use. It must be cleared (set to null) immediately after the user completes first login and sets a password.

vipps_national_id_backfill
on_update

When a user authenticates via Vipps for the first time, the returned personnummer is stored (encrypted) in national_id if not already set, enabling member system reconciliation.

Enforced by: VippsAuthService

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
Permanent Storage

Entity Relationships

user_organization_memberships
outgoing one_to_many
optional

Components Managing This Entity

service AuthService ["backend"] service BankIdAuthService ["backend"] service VippsAuthService ["backend"] service WebAuthnRegistrationService ["frontend","mobile"] service RbacService ["backend"] ui RoleGuardWidget ["frontend","mobile"] data ProfileRepository ["mobile"] service ProfileService ["mobile"] service ProfileSwitchService ["backend","mobile"] data StatisticsRepository ["mobile"] service StatisticsService ["mobile"] service TeamReportService ["mobile"] service AssignmentThresholdService ["backend"] data PeerMentorStatusRepository ["backend"] service PeerMentorStatusService ["backend"] service PeerMentorResumeService ["backend"] service AutoPauseTriggerService ["backend"] service CertificationExpiryMonitor ["backend"] service PushNotificationService ["backend"] data NotificationPreferenceRepository ["mobile"] service NotificationPreferenceService ["mobile","backend"] service RecruitmentTrackingService ["backend"] service AnnualSummaryService ["backend"] service AchievementService ["backend"] service HomeDashboardService ["backend"] data PreferencesRepository ["mobile"] service PreferencesService ["mobile"] service DashboardKpiService ["backend"] data AdminUserRepository ["backend"] service AdminUserService ["backend"] ui InviteUserModal ["frontend"] service AdminRoleService ["backend"] ui RoleAssignmentWidget ["frontend"] service BulkUserActionService ["backend"] service TeamReportService ["backend"] service BufdirReportService ["backend"] service BufdirExportService ["backend"] service MemberAssociationService ["backend"] service SecurityMetricsService ["backend"] service AuditLogService ["backend"] service SessionAdminService ["backend"]