configuration PK: id 14 required 1 unique

Description

Defines the catalogue of allowable expense categories for peer mentor reimbursement claims. Each expense type carries organization-specific business rules including mutual exclusivity constraints, documentation requirements, amount thresholds, and auto-approval eligibility. Expense types are managed per organization to support divergent reimbursement policies across NHF, Blindeforbundet, HLF, and Barnekreftforeningen.

20
Attributes
4
Indexes
8
Validation Rules
21
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Primary key, generated at creation
PKrequiredunique
organization_id uuid FK to organizations. Expense types are always scoped to a single organization; different orgs may define entirely different catalogues.
required
code string Short machine-readable identifier for this type within the organization (e.g. 'km_allowance', 'toll', 'parking', 'public_transit', 'driver_honorarium'). Used as stable reference in business rule definitions and API payloads.
required
name string Human-readable display label shown in the mobile app expense form and admin portal. May be overridden by organization terminology system.
required
description text Optional longer description explaining when this expense type applies, shown as helper text in the expense form.
-
category enum High-level grouping for display and reporting purposes.
required
requires_receipt boolean When true, a receipt photo attachment is mandatory before the expense can be submitted. HLF requires receipts for claims above 100 NOK.
required
receipt_required_above_amount decimal If set, receipt is only required when the claimed amount exceeds this threshold (in NOK). NULL means receipt requirement is unconditional when requires_receipt=true. HLF configures this as 100.
-
requires_distance_km boolean When true, the expense form must capture a kilometre value. Applicable to km_allowance and toll types.
required
max_amount decimal Optional per-claim ceiling in NOK. Claims exceeding this are rejected at validation time.
-
max_distance_km decimal Optional per-claim maximum distance in km. HLF uses this for auto-approval threshold (claims ≤ configured km auto-approved).
-
auto_approvable boolean When true and auto-approval rules are configured for the organization, claims of this type may bypass manual review if they satisfy all rule thresholds.
required
requires_confidentiality_declaration boolean When true, the peer mentor must submit a confidentiality declaration before the expense is accepted. Used by Blindeforbundet for driver honorarium types.
required
exclusivity_group string Mutual exclusivity group identifier. Expense types sharing the same non-null group value cannot be selected simultaneously in a single expense claim. E.g. 'travel_mode' groups km_allowance and public_transit so both cannot be claimed for the same trip.
-
sort_order integer Display order within the expense type selector widget. Lower values appear first.
required
is_active boolean Soft-delete flag. Inactive types are hidden from the expense form but preserved for historical claim validation and reporting.
required
version integer Optimistic lock version counter incremented on every update. Enables the Expense Rule Validation Engine to detect and reject stale rule evaluations.
required
metadata json Extensible key-value store for organization-specific configuration that does not warrant a dedicated column (e.g. Xledger account code, Dynamics voucher code for accounting export mapping).
-
created_at datetime Timestamp when the record was first created.
required
updated_at datetime Timestamp of the most recent update, maintained by application logic on every write.
required

Database Indexes

idx_expense_type_org_active
btree

Columns: organization_id, is_active

idx_expense_type_org_code
btree unique

Columns: organization_id, code

idx_expense_type_exclusivity_group
btree

Columns: organization_id, exclusivity_group

idx_expense_type_org_sort
btree

Columns: organization_id, sort_order

Validation Rules

code_format_valid error

Validation failed

name_not_empty error

Validation failed

max_amount_positive error

Validation failed

receipt_threshold_consistent error

Validation failed

distance_fields_consistent error

Validation failed

exclusivity_group_format error

Validation failed

org_exists error

Validation failed

cache_staleness_check warning

Validation failed

Business Rules

mutual_exclusivity_enforced
on_create

Two or more expense types sharing the same exclusivity_group cannot be selected within a single expense claim. For example, kilometre allowance and public transit cannot be claimed simultaneously for the same trip. This prevents double-dipping on travel reimbursement and is technically enforced at both the mobile client and server-side validation layers.

org_scoped_catalogue
always

Every expense type belongs to exactly one organization. Queries for expense type catalogues must always include organization_id in the WHERE clause. Cross-organization type leakage is a data privacy violation.

active_only_in_new_claims
on_create

Only expense types with is_active=true are offered to users when creating a new expense claim. Inactive types may still appear on historical claims for read-only display.

version_increment_on_update
on_update

The version counter must be incremented on every UPDATE to support optimistic locking in the Expense Rule Validation Engine. The engine captures the version at the start of validation; if the version has changed by the time the expense is submitted, the validation is re-run.

Enforced by: Expense Type Service
confidentiality_declaration_gate
on_create

When requires_confidentiality_declaration=true, the peer mentor must have a valid, non-expired confidentiality declaration on file before the expense claim can be submitted. If no valid declaration exists, the Declaration Screen is presented inline before the expense form can be finalized.

receipt_threshold_enforced
on_create

When receipt_required_above_amount is set, the receipt requirement is evaluated dynamically at form submission time against the claimed amount. Below the threshold, the receipt is optional; at or above it, submission is blocked until a receipt is attached.

deactivation_preserves_history
on_delete

Expense types are never hard-deleted. Setting is_active=false is the only permitted removal path. This ensures all historical expense claims retain a valid expense_type_id reference for audit and Bufdir reporting.

code_unique_per_org
on_create

The combination of (organization_id, code) must be unique. This enables deterministic referencing of expense types in API payloads, accounting export mappings, and auto-approval rule configurations without relying on UUIDs.

Enforced by: Expense Type Service
auto_approvable_requires_rule
always

Setting auto_approvable=true on an expense type has no effect unless at least one enabled auto-approval rule exists for the organization that references this type. The Auto-Approval Rule Engine silently falls through to manual approval when no matching rule is found.

Storage Configuration

Storage Type
lookup_table
Location
main_db
Partitioning
No Partitioning
Retention
Permanent Storage