Export Log
Data Entity
Description
Immutable audit record of every Bufdir export operation — mobile one-click and admin portal — capturing who triggered the export, the resulting file, delivery status, and any error details. Supports compliance traceability, rate-limit enforcement, and download history display.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Surrogate primary key generated at insert time | PKrequiredunique |
bufdir_report_id |
uuid |
Foreign key to the bufdir_reports row that was exported | required |
organization_id |
uuid |
Denormalized tenant key for fast org-scoped queries without joining bufdir_reports | required |
exported_by_user_id |
uuid |
User who triggered the export; nullable only for system-initiated batch exports | - |
export_source |
enum |
Which product surface initiated the export | required |
export_format |
enum |
Output format of the generated file | required |
status |
enum |
Lifecycle state of the export job | required |
file_name |
string |
Human-readable filename presented to the user on download (e.g. bufdir-report-2025-q1.pdf) | - |
file_path |
string |
Storage path or cloud object key for the generated file; null until status = completed | - |
file_size_bytes |
integer |
Size of the exported file in bytes; populated on completion | - |
checksum_sha256 |
string |
SHA-256 hex digest of the exported file for integrity verification | - |
error_message |
text |
Human-readable error detail captured when status = failed; null on success | - |
error_code |
string |
Machine-readable error code for programmatic retry/alerting (e.g. RATE_LIMIT_EXCEEDED, AGGREGATION_TIMEOUT) | - |
download_count |
integer |
Number of times the completed export file has been downloaded | required |
last_downloaded_at |
datetime |
Timestamp of the most recent file download | - |
triggered_at |
datetime |
UTC timestamp when the export was requested; immutable after insert | required |
processing_started_at |
datetime |
UTC timestamp when the export job was picked up by the generation service | - |
completed_at |
datetime |
UTC timestamp when the export reached a terminal state (completed or failed) | - |
expires_at |
datetime |
UTC timestamp after which the stored file is eligible for deletion; typically triggered_at + 90 days | required |
report_period_label |
string |
Human-readable label of the reporting period included in the export (e.g. '2025-Q1'); denormalized for display in history lists without joining bufdir_reports | - |
metadata |
json |
Extensible bag for additional export context: row counts, page count, Bufdir schema version used, mobile OS version, etc. | - |
Database Indexes
idx_export_logs_bufdir_report_id
Columns: bufdir_report_id
idx_export_logs_organization_id_triggered_at
Columns: organization_id, triggered_at
idx_export_logs_exported_by_user_id
Columns: exported_by_user_id
idx_export_logs_status
Columns: status
idx_export_logs_expires_at
Columns: expires_at
Validation Rules
bufdir_report_must_exist
error
Validation failed
organization_id_matches_report
error
Validation failed
valid_status_transition
error
Validation failed
file_fields_required_on_completion
error
Validation failed
error_message_required_on_failure
error
Validation failed
expires_at_in_future
error
Validation failed
processing_timestamps_ordered
error
Validation failed
Business Rules
immutable_after_terminal_state
Once status reaches 'completed' or 'failed', all fields except download_count and last_downloaded_at are frozen. No updates are permitted.
no_delete_within_retention_window
Export log rows must not be hard-deleted before expires_at. They form part of the compliance audit trail required for Bufdir funding accountability.
rate_limit_enforcement
No more than 5 export requests per organization per hour. The export-rate-limiter component checks this before a new row is inserted and sets status = failed with error_code = RATE_LIMIT_EXCEEDED when breached.
file_expiry_set_on_create
expires_at must be set to triggered_at + 90 days at insert time. The object storage adapter and a scheduled cleanup job use this to purge files while the log row is retained for audit.
org_scoped_visibility
Users may only read export log rows where organization_id matches their session's tenant. Global admins may query across tenants only via the audit interface.
download_count_increment_only
download_count must only ever increase. Any update that decrements it is rejected. last_downloaded_at is updated atomically with each increment.