core PK: id 7 required 2 unique

Description

Records the approval lifecycle for peer mentor expense claims, tracking reviewer decisions, timestamps, rejection reasons, and audit trail for reimbursement workflows in the Admin Web Portal.

17
Attributes
6
Indexes
6
Validation Rules
12
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Primary key
PKrequiredunique
expense_id uuid Foreign key to the expense being reviewed
requiredunique
status enum Current approval status of the expense
required
reviewed_by_user_id uuid ID of the admin or coordinator who reviewed the expense; null if auto-approved
-
reviewed_at datetime Timestamp when the review decision was made
-
auto_approved boolean True when approval was triggered by an auto-approval rule (under threshold, no receipts required)
required
auto_approval_rule_id uuid Reference to the approval rule that triggered auto-approval; null for manual reviews
-
rejection_reason text Free-text reason provided by reviewer when rejecting or requesting more information
-
rejection_category enum Structured rejection category for reporting and analytics
-
organization_id uuid Organization the expense belongs to, denormalized for tenant isolation and query performance
required
reimbursement_amount decimal Approved reimbursement amount in NOK; may differ from claimed amount if partially approved
-
currency string ISO 4217 currency code for the reimbursement amount
-
accounting_export_id uuid Reference to accounting_sync_logs record when this approval has been exported to accounting system
-
exported_at datetime Timestamp when approval record was exported to accounting system
-
reviewer_notes text Internal notes from the reviewer visible only to admins, not exposed to the peer mentor
-
created_at datetime Timestamp when the approval record was created (usually on expense submission)
required
updated_at datetime Timestamp of last status change or update
required

Database Indexes

idx_expense_approvals_expense_id
btree unique

Columns: expense_id

idx_expense_approvals_organization_status
btree

Columns: organization_id, status

idx_expense_approvals_reviewed_by
btree

Columns: reviewed_by_user_id

idx_expense_approvals_reviewed_at
btree

Columns: reviewed_at

idx_expense_approvals_accounting_export
btree

Columns: accounting_export_id

idx_expense_approvals_auto_approved
btree

Columns: organization_id, auto_approved, status

Validation Rules

valid_status_transition error

Validation failed

reviewed_at_not_future error

Validation failed

reimbursement_amount_positive error

Validation failed

currency_iso_format error

Validation failed

reviewer_must_be_org_admin_or_coordinator error

Validation failed

rejection_category_with_rejection_reason warning

Validation failed

Business Rules

one_approval_per_expense
on_create

Each expense may have exactly one approval record. The expense_id column is unique — a second approval record for the same expense is rejected at the database level.

auto_approval_threshold
on_create

Expenses meeting all criteria defined in an active approval rule (e.g. distance under 50 km, no receipts, known expense type) are automatically approved without reviewer action. auto_approved is set true and auto_approval_rule_id is populated.

reviewer_required_for_manual_approval
on_update

When status transitions to approved or rejected manually, reviewed_by_user_id and reviewed_at must be set. Auto-approved records are exempt.

rejection_reason_required_on_reject
on_update

When status is set to rejected or requires_info, rejection_reason must be provided so the peer mentor understands the outcome.

no_deletion_of_approvals
on_delete

Approval records are never deleted — they form part of the financial audit trail. Status changes replace deletion.

tenant_isolation
always

All reads and writes must be scoped by organization_id matching the authenticated user's organization. Cross-tenant access is rejected.

approved_amount_not_exceed_claimed
on_update

reimbursement_amount on approval may not exceed the amount on the linked expense record.

audit_log_on_status_change
on_update

Every status transition writes an entry to audit_logs including previous status, new status, reviewer identity, and timestamp.

exported_approval_immutable
on_update

Once an approval record has been exported to the accounting system (exported_at is set), its status and reimbursement_amount may not be changed without a corrective workflow.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
Permanent Storage