Expenses
Data Entity
Description
Travel and out-of-pocket expense claims registered by peer mentors and coordinators against a logged activity, classified by expense type and routed through approval to reimbursement.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key for the expense record | PKrequiredunique |
activity_id |
uuid |
Foreign key to the activity this expense is claimed against | required |
expense_type_id |
uuid |
Foreign key to the configured expense type (e.g. mileage, toll, parking, transit, driver-honorarium) | required |
user_id |
uuid |
User who submitted the expense (peer mentor or coordinator on behalf) | required |
organization_id |
uuid |
Tenant organization scope for multi-tenant isolation | required |
amount |
decimal |
Monetary amount claimed in NOK | required |
currency |
string |
ISO 4217 currency code | required |
distance_km |
decimal |
Distance in kilometers for mileage-type expenses; null for non-mileage types | - |
expense_date |
datetime |
Date the expense was incurred | required |
description |
text |
Optional free-text note describing the expense | - |
status |
enum |
Lifecycle status of the expense claim | required |
auto_approved |
boolean |
Whether the expense was automatically approved by rules engine (below threshold and no receipt required) | required |
requires_receipt |
boolean |
Whether a receipt is required based on expense type and amount threshold (e.g. >100 NOK for HLF) | required |
approver_id |
uuid |
User who approved or rejected the expense | - |
approved_at |
datetime |
Timestamp of approval/rejection decision | - |
rejection_reason |
text |
Reason text when status is rejected | - |
created_at |
datetime |
Record creation timestamp | required |
updated_at |
datetime |
Record last update timestamp | required |
synced_at |
datetime |
Timestamp when offline-created record was synced to backend | - |
Database Indexes
idx_expenses_activity_id
Columns: activity_id
idx_expenses_user_id
Columns: user_id
idx_expenses_organization_id
Columns: organization_id
idx_expenses_expense_type_id
Columns: expense_type_id
idx_expenses_status
Columns: status
idx_expenses_org_status
Columns: organization_id, status
idx_expenses_expense_date
Columns: expense_date
Validation Rules
amount_non_negative
error
Validation failed
distance_required_for_mileage
error
Validation failed
expense_date_not_future
error
Validation failed
valid_expense_type
error
Validation failed
valid_status_transition
error
Validation failed
rejection_reason_required
error
Validation failed
currency_iso_code
error
Validation failed
Business Rules
expense_must_link_to_activity
Every expense must be attached to an existing activity record
auto_approval_under_threshold
Expenses under 50 km mileage with no receipt requirement are auto-approved per HLF rule; configurable per organization
manual_approval_above_threshold
Expenses above the configured threshold require manual approval by Org Admin
receipt_required_above_amount
When amount exceeds the receipt-required threshold (e.g. 100 NOK), a receipt must be attached before submission
mutually_exclusive_expense_types
Mutually exclusive expense type combinations (e.g. mileage and transit ticket for the same trip) are rejected by the type rules
no_modification_after_reimbursement
Reimbursed expenses are immutable
tenant_isolation
Expenses are scoped to the submitter's organization and never visible across tenants