core PK: id 16 required 1 unique

Description

Records travel expense and reimbursement claims submitted by peer mentors and coordinators, capturing amounts, distances, expense types, and approval status. Central to the financial compliance workflow connecting activity registration to reimbursement processing and Bufdir reporting.

31
Attributes
11
Indexes
12
Validation Rules
33
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Unique identifier for the expense record
PKrequiredunique
user_id uuid Reference to the user who submitted the expense claim (peer mentor or coordinator)
required
activity_id uuid Reference to the activity this expense is associated with; every expense must be linked to a registered activity
required
expense_type_id uuid Reference to the organisation-specific expense type from the expense type catalogue
required
organization_id uuid Organisation scope for multi-tenant isolation; derived from the submitting user's organisation
required
status enum Current lifecycle status of the expense claim
required
total_amount decimal Total calculated expense amount in NOK, sum of all cost components (distance cost + tolls + parking + public transport + other)
required
currency string ISO 4217 currency code, defaults to NOK for Norwegian organisations
required
distance_km decimal Kilometres driven for the activity; null if not a driving expense
-
km_rate decimal Kilometre reimbursement rate in NOK applied at time of submission, captured for audit trail
-
toll_amount decimal Toll fees in NOK; null or 0 if no tolls claimed
-
parking_amount decimal Parking costs in NOK; null or 0 if no parking claimed
-
public_transport_amount decimal Public transport costs in NOK (bus, train, taxi); mutually exclusive with distance_km per expense type rules
-
other_amount decimal Other reimbursable costs not covered by specific fields (e.g. driver honorarium for Blindeforbundet)
-
description text Free-text description or notes about the expense claim
-
expense_date datetime Date when the expense was incurred, typically matches the linked activity date
required
receipt_required boolean Whether a receipt attachment is mandatory for this expense, determined by expense type rules and amount thresholds
required
has_receipt boolean Whether at least one receipt image has been attached to this expense
required
declaration_accepted boolean Whether the user has accepted the required confidentiality or expense declaration for this claim
required
declaration_version_id string Version identifier of the declaration text accepted by the user, for audit compliance
-
auto_approved boolean Whether the expense was automatically approved by the auto-approval rule engine (under threshold)
required
auto_approval_rule_id uuid Reference to the auto-approval rule that approved this expense, null if manually reviewed
-
submitted_by uuid User who actually submitted the expense; differs from user_id when a coordinator submits on behalf of a peer mentor (proxy)
-
rejection_reason text Reason provided by the reviewer when rejecting the expense claim
-
reviewed_by uuid User who approved or rejected the expense, null if pending or auto-approved
-
reviewed_at datetime Timestamp when the expense was approved or rejected
-
external_reference_id string Reference ID from external accounting system after export (Xledger, Dynamics), used for idempotent re-export
-
exported_at datetime Timestamp when the expense was exported to the external accounting system
-
version integer Optimistic locking version counter to prevent concurrent modification conflicts during approval
required
created_at datetime Timestamp when the expense record was created
required
updated_at datetime Timestamp when the expense record was last modified
required

Database Indexes

idx_expenses_user_id
btree

Columns: user_id

idx_expenses_activity_id
btree

Columns: activity_id

idx_expenses_expense_type_id
btree

Columns: expense_type_id

idx_expenses_organization_id
btree

Columns: organization_id

idx_expenses_status
btree

Columns: status

idx_expenses_org_status
btree

Columns: organization_id, status

idx_expenses_expense_date
btree

Columns: expense_date

idx_expenses_org_date
btree

Columns: organization_id, expense_date

idx_expenses_user_status
btree

Columns: user_id, status

idx_expenses_created_at
btree

Columns: created_at

idx_expenses_external_ref
btree

Columns: external_reference_id

Validation Rules

positive_amounts error

Validation failed

positive_distance error

Validation failed

valid_expense_type_reference error

Validation failed

valid_activity_reference error

Validation failed

valid_user_reference error

Validation failed

expense_date_not_future error

Validation failed

expense_date_not_too_old warning

Validation failed

receipt_attachment_when_required error

Validation failed

currency_code_format error

Validation failed

description_max_length error

Validation failed

rejection_reason_required error

Validation failed

version_monotonic_increment error

Validation failed

Business Rules

expense_must_link_to_activity
on_create

Every expense claim must be linked to an existing registered activity. Expenses cannot exist independently of activities.

mutual_exclusivity_enforcement
on_create

Expense type mutual-exclusivity rules must be enforced: for example, kilometre reimbursement and public transport costs cannot be claimed simultaneously if the expense type rules prohibit it. Rules are organisation-specific.

receipt_required_above_threshold
on_create

Receipt photo attachment is mandatory when the total expense amount exceeds the organisation-configured threshold (e.g., HLF requires receipts for expenses over 100 NOK). Submission is blocked until receipt is attached.

auto_approval_under_threshold
on_create

Expenses under the organisation-configured auto-approval threshold (e.g., under 50 km with no additional costs at HLF) are automatically approved without manual review. The auto_approved flag and rule reference are recorded.

status_transition_validity
on_update

Expense status transitions must follow the valid lifecycle: draft → pending_review → approved/rejected, approved → reimbursed. Cancelled can be set from draft or pending_review only. No backward transitions except rejection followed by resubmission as a new record.

optimistic_locking_on_approval
on_update

Approval and rejection operations must use optimistic locking via the version field to prevent concurrent modification conflicts when multiple reviewers access the same expense.

organisation_scoping
always

All expense queries and operations must be scoped to the requesting user's organisation. Coordinators see expenses from their local association only; Org Admins see all expenses within their organisation.

declaration_required_for_submission
on_create

Certain expense types (e.g., driver expenses at Blindeforbundet) require an accepted confidentiality declaration before the expense can be submitted. declaration_accepted must be true.

proxy_submission_attribution
on_create

When a coordinator submits an expense on behalf of a peer mentor, user_id must reflect the peer mentor (expense owner) and submitted_by must record the coordinator. Both must belong to the same local association.

immutable_after_approval
on_update

Once an expense reaches approved or reimbursed status, its financial fields (amounts, distance, expense type) cannot be modified. Only status transitions and external reference updates are permitted.

audit_trail_on_status_change
on_update

Every status change (submission, approval, rejection, reimbursement, cancellation) must generate an audit log entry recording the actor, timestamp, and reason.

total_amount_calculation
on_create

The total_amount field must equal the sum of (distance_km × km_rate) + toll_amount + parking_amount + public_transport_amount + other_amount. Recalculated on every save.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
by_date
Retention
Permanent Storage

Components Managing This Entity

service Proxy Registration Service ["mobile"] service Proxy Registration Service ["mobile","backend"] data Expense Store ["mobile"] data Expense Store ["mobile"] infrastructure Accounting API Client ["backend"] service Expense Service ["mobile"] service Expense Service ["mobile"] ui Expense Form Screen ["mobile"] ui Expense Form Screen ["mobile"] service Receipt Validation Service ["mobile","backend"] service Expense Rule Evaluation Engine ["shared"] ui Expense Type Selector Widget ["mobile"] ui Expense Type Selector Widget ["mobile"] service Declaration Service ["mobile","backend"] service Declaration Service ["backend"] ui Declaration Screen ["mobile"] ui Declaration Screen ["mobile"] service Bufdir Report Service ["backend"] service Bufdir Report Service ["backend","mobile"] service Accounting API Client ["backend"] service Accounting API Client ["backend"] data Local SQLite Database ["mobile"] data Local SQLite Database ["mobile"] service Background Sync Service ["mobile"] service Background Sync Service ["mobile"] data Analytics Store ["backend"] data Analytics Store ["backend"] service KPI Aggregation Service ["backend"] service KPI Aggregation Service ["backend"] service Audit Log Service ["backend"] data Expense Approval Store ["backend"] data Expense Approval Store ["backend"] service Audit Log Service ["backend"] service Expense Approval Service ["backend"] service Expense Approval Service ["backend"] ui Expense Queue Page ["frontend"] ui Expense Queue Page ["frontend"] service Auto-Approval Rule Engine ["backend"] service Auto-Approval Rule Engine ["backend"] data Reimbursement Store ["backend"] service Reimbursement Service ["backend"] service Reimbursement Service ["backend"] ui Reimbursement Dashboard ["frontend"] ui Reimbursement Dashboard ["frontend"] service Report Generation Service ["backend"] service Report Generation Service ["backend"] service Bufdir Export Service ["backend"] service Bufdir Export Service ["backend"] service Custom Report Service ["backend"] service Custom Report Service ["backend"] service Accounting API Service ["backend"] service Accounting API Service ["backend"] service Audit Log Service ["backend"] service Audit Log Service ["backend"]