core PK: id 14 required 2 unique

Description

Stores metadata and storage references for receipt images attached to expense claims. Each receipt links to a parent expense and tracks upload lifecycle, file properties, and storage location. Receipts serve as mandatory audit evidence for reimbursement claims above organization-defined thresholds and are required for Bufdir compliance reporting.

22
Attributes
7
Indexes
9
Validation Rules
19
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Unique identifier for the receipt record
PKrequiredunique
expense_id uuid Foreign key to the parent expense claim this receipt documents
required
file_name string Original file name as captured from camera or gallery picker
required
file_size_bytes integer File size in bytes after client-side compression
required
mime_type string MIME type of the uploaded file
required
storage_key string Object storage key (S3 path) for the receipt file in cloud storage
requiredunique
storage_bucket string Name of the S3-compatible bucket where the receipt is stored
required
upload_status enum Current upload lifecycle state of the receipt file
required
upload_progress decimal Upload progress percentage (0.00 to 100.00) for resumable uploads
-
upload_retry_count integer Number of upload retry attempts for failed or interrupted transfers
required
checksum_sha256 string SHA-256 hash of the uploaded file for integrity verification and deduplication
-
virus_scan_status enum Result of server-side virus scan on the uploaded file
required
virus_scan_at datetime Timestamp when virus scan completed
-
image_width integer Width of the receipt image in pixels after compression
-
image_height integer Height of the receipt image in pixels after compression
-
thumbnail_storage_key string Object storage key for the generated thumbnail used in approval queue previews
-
uploaded_by uuid User ID of the person who uploaded the receipt (may differ from expense owner in proxy scenarios)
required
description text Optional description or note about the receipt content
-
receipt_date datetime Date shown on the receipt, if different from upload date
-
organization_id uuid Organization scope for multi-tenant isolation, denormalized from parent expense
required
created_at datetime Timestamp when the receipt record was created
required
updated_at datetime Timestamp of the last update to the receipt record
required

Database Indexes

idx_expense_receipts_expense_id
btree

Columns: expense_id

idx_expense_receipts_organization_id
btree

Columns: organization_id

idx_expense_receipts_upload_status
btree

Columns: upload_status

idx_expense_receipts_uploaded_by
btree

Columns: uploaded_by

idx_expense_receipts_storage_key
btree unique

Columns: storage_key

idx_expense_receipts_virus_scan
btree

Columns: virus_scan_status, upload_status

idx_expense_receipts_created_at
btree

Columns: organization_id, created_at

Validation Rules

valid_mime_type error

Validation failed

max_file_size error

Validation failed

valid_expense_reference error

Validation failed

valid_uploader_reference error

Validation failed

checksum_format error

Validation failed

storage_key_uniqueness error

Validation failed

receipt_date_not_future warning

Validation failed

max_receipts_per_expense error

Validation failed

file_name_sanitization error

Validation failed

Business Rules

receipt_required_above_threshold
on_create

Expense claims above the organization-defined amount threshold (e.g., 100 NOK for HLF) must have at least one receipt attached before the expense can be submitted for approval

receipt_linked_to_single_expense
on_create

Each receipt must be associated with exactly one expense claim; a receipt cannot be shared across multiple expenses

virus_scan_before_availability
on_create

Receipt files must pass virus scanning before they are made available for viewing or download via pre-signed URLs; infected files are quarantined and the upload_status is set to virus_detected

Enforced by: Receipt Storage
immutable_after_expense_approval
on_update

Once the parent expense has been approved, the receipt record and its associated file become immutable and cannot be modified or deleted to preserve audit integrity

organization_tenant_isolation
always

Receipt records are scoped to the owning organization; queries must always filter by organization_id to enforce multi-tenant data isolation

client_side_compression_required
on_create

Receipt images must be compressed client-side to a target size under 500 KB before upload to reduce storage costs and transfer times

receipt_type_specific_requirements
on_create

Different expense types have different receipt requirements; some expense types mandate receipts regardless of amount while others only require them above thresholds, as configured per organization

cascade_delete_with_expense
on_delete

When an expense record is deleted, all associated receipt records and their cloud storage files must be deleted to prevent orphaned files

offline_queue_for_upload
on_create

When the device is offline, receipt metadata is saved locally and the file is queued for upload when connectivity is restored via the background sync service

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
archive_after_1year