core PK: id 7 required 4 unique

Description

A top-level member organization within the platform (NHF, Blindeforbundet, HLF, Barnekreftforeningen). Organizations own their own labels, settings, feature toggles, and reporting data. Serves as the multi-tenancy root — all data is scoped to an organization and its hierarchy.

14
Attributes
5
Indexes
21
Validation Rules
26
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Immutable primary key generated on creation. Used as the tenant identifier in JWT claims (organization_id) and as the foreign key anchor for all scoped data across the platform.
PKrequiredunique
name string Official display name of the organization (e.g., 'Norges Handikapforbund', 'Hørselsforbundet'). Used in UI headings, invitation emails, Bufdir reports, and analytics dashboards.
requiredunique
slug string URL-safe, lowercase, hyphenated short identifier for the organization (e.g., 'nhf', 'blindeforbundet', 'hlf', 'barnekreftforeningen'). Used in API paths, iCal feed tokens, deep links, and referral link namespacing. Immutable after creation.
requiredunique
logo_url string Absolute URL pointing to the organization's logo asset stored in cloud object storage. Rendered in the organization selection screen, onboarding flow, admin panel header, and generated Bufdir report headers.
-
feature_flags json JSONB map of feature toggle flags enabling or disabling optional platform capabilities per organization. Examples: { 'encrypted_assignments': true, 'bulk_registration': false, 'gamification': false, 'course_management': true, 'reimbursements': true }. Validated against the settings schema on every write.
-
settings json JSONB map of organization-specific operational configuration. Includes: reimbursement thresholds (auto_approve_km_threshold, auto_approve_amount_threshold_nok), receipt_required_above_nok, default_activity_duration_minutes, honorarium_tier_thresholds, max_association_memberships_per_user. Validated against the settings schema on every write.
-
contact_email string Primary administrative contact email for the organization. Used by the platform operator for billing, support escalation, and release communications. Not exposed to end users.
-
contact_phone string Primary administrative contact phone number in E.164 format (e.g., +4712345678). Used for billing and support escalation by the platform operator.
-
website_url string Public website URL for the organization. Displayed in the onboarding flow and organization settings screen for context.
-
bufdir_organization_code string The organization's official Bufdir grant recipient identifier code. Required when generating Bufdir compliance reports. Each of the four partner organizations has a unique code assigned by Bufdir.
unique
default_language string BCP-47 language tag representing the primary language for this organization's user interface and generated reports (e.g., 'nb-NO' for Norwegian Bokmål). Drives i18n defaults for label resolution.
required
is_active boolean Soft-delete flag. When false, the organization and all its members are locked out of the platform. No data is physically deleted. Used for contract suspension or offboarding. Defaults to true on creation.
required
created_at datetime UTC timestamp when the organization record was first created. Set once on insert and never modified. Used for audit trails and platform analytics.
required
updated_at datetime UTC timestamp of the most recent modification to any organization field. Auto-updated on every write via database trigger or ORM hook. Used for cache invalidation and optimistic concurrency checks.
required

Database Indexes

idx_organization_slug
btree unique

Columns: slug

idx_organization_name
btree unique

Columns: name

idx_organization_is_active
btree

Columns: is_active

idx_organization_bufdir_code
btree unique

Columns: bufdir_organization_code

idx_organization_created_at
btree

Columns: created_at

Validation Rules

name_non_empty_and_bounded error

Validation failed

name_non_empty_and_bounded_on_update error

Validation failed

slug_format_validation error

Validation failed

slug_uniqueness error

Validation failed

name_uniqueness error

Validation failed

name_uniqueness_on_update error

Validation failed

logo_url_format_validation error

Validation failed

logo_url_format_validation_on_update error

Validation failed

contact_email_format_validation error

Validation failed

contact_email_format_validation_on_update error

Validation failed

contact_phone_e164_format error

Validation failed

contact_phone_e164_format_on_update error

Validation failed

default_language_valid_bcp47 error

Validation failed

default_language_valid_bcp47_on_update error

Validation failed

bufdir_code_uniqueness error

Validation failed

bufdir_code_uniqueness_on_update error

Validation failed

feature_flags_no_unknown_keys error

Validation failed

feature_flags_no_unknown_keys_on_update error

Validation failed

settings_threshold_values_positive error

Validation failed

settings_threshold_values_positive_on_update error

Validation failed

bufdir_code_required_for_report_generation warning

Validation failed

Business Rules

slug_immutable_after_creation
on_update

The slug field cannot be modified after the organization record is first created. It is used as a stable external identifier in deep links, API paths, iCal tokens, and referral namespaces. Any attempt to update the slug must be rejected with a validation error.

tenant_data_isolation
always

All queries against any entity that has a foreign key relationship to organizations must include an organization_id scope filter. No cross-organization data access is permitted at any layer. The multi-tenancy infrastructure middleware enforces this by attaching a TenantContext to every request derived from the authenticated user's JWT claims.

organization_requires_active_admin
on_update

An organization must retain at least one active user with the Organization Administrator or Global Administrator role. Attempts to deactivate or demote the last admin must be rejected. This prevents organizations from becoming permanently inaccessible.

deactivation_is_soft_delete_only
on_delete

Organizations are never physically deleted from the database. Setting is_active = false is the only permitted deactivation mechanism. All historical data — activities, reports, reimbursements, assignments — must remain queryable for audit and Bufdir compliance purposes.

feature_flags_validated_against_schema
on_create

The feature_flags JSONB field must conform to the known feature flags schema on every write. Unknown keys are rejected. This prevents silent misconfiguration that could expose features to organizations not licensed or configured for them.

feature_flags_validated_against_schema_on_update
on_update

The feature_flags JSONB field must conform to the known feature flags schema on every update. Unknown keys are rejected.

logo_stored_via_object_storage
on_create

The logo_url field must reference a URL in the platform's configured cloud object storage domain. Base64-encoded inline images or external CDN URLs not under the platform's control are not permitted. This enforces consistent access control, retention, and CDN delivery for all organization branding assets.

logo_stored_via_object_storage_on_update
on_update

The logo_url field update must reference a URL in the platform's configured cloud object storage domain.

settings_validated_against_schema
on_create

The settings JSONB field must conform to the known settings schema on every write. Numeric threshold values (km, NOK) must be positive integers within defined min/max bounds. Invalid settings are rejected before persistence.

settings_validated_against_schema_on_update
on_update

The settings JSONB field must conform to the known settings schema on every update.

organization_id_embedded_in_jwt
always

On every successful authentication, the user's current organization_id must be embedded as a claim in the issued JWT token. The multi-tenancy middleware uses this claim to construct the TenantContext for the request lifecycle. Sessions without a valid organization_id claim are rejected by all protected routes.

labels_cache_invalidated_on_settings_change
on_update

When an organization's settings or feature_flags are updated, the labels cache for that organization must be invalidated. This ensures that mobile clients receive updated terminology and feature availability on next app foreground or explicit refresh.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
Permanent Storage

Entity Relationships

activity_type
outgoing one_to_many

An organization defines and owns the set of activity types available to its members

required
badge
outgoing one_to_many

An organization defines its own badge catalog and recognition program for peer mentors

required
bufdir_report
outgoing one_to_many

An organization generates multiple Bufdir compliance reports across reporting periods

required
course
outgoing one_to_many

An organization manages its own catalog of training courses and certification programs

required
expense_type
outgoing one_to_many

An organization configures the available expense types and their validation rules for its peer mentors

required
external_resource
outgoing one_to_many

An organization curates its own list of external resource links for peer mentors

required cascade delete
integration
outgoing one_to_many

An organization can have multiple external system integrations (accounting, portals) configured independently

optional
local_association
outgoing one_to_many

An organization owns all its local associations directly, supporting direct org-to-association queries bypassing region

required
organization_label
outgoing one_to_many

An organization owns a set of terminology overrides customizing app labels throughout the platform

required cascade delete
region
outgoing one_to_many

An organization has multiple regional groupings that aggregate local associations

required
report
outgoing one_to_many

An organization has many team and coordinator-level operational reports generated within it

required
toolbox_card
outgoing one_to_many

An organization maintains its own library of talking cards and toolbox content for peer mentors

required cascade delete
user_organization_role
outgoing one_to_many

An organization has many user role assignments scoped to it

required