core PK: id 8 required 1 unique

Description

Junction record linking a user to an organization with a specific role, status, and tenure. Supports multi-organization membership (e.g. NHF members in up to 5 local associations) and drives RBAC scoping, module visibility, and Bufdir reporting boundaries.

19
Attributes
5
Indexes
8
Validation Rules
28
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Primary key
PKrequiredunique
user_id uuid Foreign key to users table
required
organization_id uuid Foreign key to organizations table
required
role enum The user's functional role within this organization
required
status enum Membership lifecycle state
required
is_primary_organization boolean Whether this is the user's primary organization. Used to resolve default context when user belongs to multiple organizations.
required
invited_at datetime Timestamp when the invitation was sent by an org admin
-
accepted_at datetime Timestamp when the user accepted the invitation
-
deactivated_at datetime Timestamp when the membership was deactivated
-
paused_at datetime Timestamp when the membership was paused (peer mentor pause function)
-
paused_until datetime Optional scheduled resume date set at pause time
-
pause_reason text Optional free-text reason for pause, visible to coordinator
-
deactivation_reason text Reason for deactivation recorded by org admin
-
invited_by_user_id uuid User ID of the org admin who sent the invitation
-
local_association_label string Human-readable label for the specific local association within the organization (e.g. 'Oslo Lokallag'). Supports NHF's 1400-lokallag structure.
-
sub_organization_id uuid Optional reference to a child node in org_hierarchy for multi-tier organizations (e.g. NHF region or lokallag)
-
metadata json Extensible key-value bag for org-specific membership attributes without schema changes
-
created_at datetime Row creation timestamp
required
updated_at datetime Row last-updated timestamp
required

Database Indexes

idx_uom_user_org
btree unique

Columns: user_id, organization_id

idx_uom_user_id
btree

Columns: user_id

idx_uom_org_id
btree

Columns: organization_id

idx_uom_org_role_status
btree

Columns: organization_id, role, status

idx_uom_status
btree

Columns: status

Validation Rules

user_id_must_exist error

Validation failed

organization_id_must_exist error

Validation failed

role_must_be_valid_enum error

Validation failed

status_transition_must_be_valid error

Validation failed

pause_timestamps_consistent error

Validation failed

deactivation_timestamp_consistent error

Validation failed

invited_by_must_be_org_admin error

Validation failed

sub_organization_belongs_to_organization error

Validation failed

Business Rules

one_membership_per_user_per_org
on_create

A user may hold at most one membership record per organization. Attempting to create a duplicate (user_id + organization_id) must be rejected.

exactly_one_primary_organization
on_update

Each user must have exactly one membership flagged is_primary_organization=true at all times. When a new primary is set, the previous primary is automatically cleared.

global_admin_no_org_context
on_create

Users with role=global_admin must not have is_primary_organization=true or an organization_id scoped to a specific tenant org. Global admins authenticate without org context and gain time-bounded org access only via support_access_grants.

coordinator_and_peer_mentor_mobile_only
always

Memberships with role=peer_mentor or role=coordinator grant access to the Mobile App only. These roles must not be granted admin portal login. Org admin surfaces as coordinator on mobile.

pause_requires_coordinator_notification
on_update

When status transitions to paused, the user's coordinator(s) in the same organization must receive a notification.

auto_pause_on_certification_expiry
on_update

When a peer mentor's certification expires, the system automatically sets status=paused and records paused_at. Coordinator is notified.

deactivated_membership_excludes_from_reports
always

Deactivated memberships (status=deactivated) must be excluded from Bufdir reports, activity aggregations, and coordinator team views. Norse Test Organization data is always excluded from Bufdir exports regardless of status.

max_five_org_memberships_per_user
on_create

A single user may belong to at most 5 organizations simultaneously (NHF multi-lokallag constraint). Reject create if the user already has 5 active or paused memberships.

invited_status_expires
always

Memberships in status=invited that have not been accepted within 30 days should be flagged as expired. The org admin must be notified and may re-invite.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
Permanent Storage

Entity Relationships

users
incoming one_to_many
optional