core PK: id 14 required 2 unique

Description

Files attached to activity records by peer mentors — photos, PDF invitations, Facebook screenshots, and other supporting documents uploaded to substantiate activities for Bufdir audit trails and coordinator review.

22
Attributes
5
Indexes
7
Validation Rules
15
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Primary key
PKrequiredunique
activity_id uuid Foreign key to the activity this attachment belongs to
required
uploaded_by_user_id uuid User who uploaded the attachment (peer mentor or coordinator acting as proxy)
required
file_name string Original filename as provided by the client at upload time
required
file_size_bytes integer File size in bytes, recorded at upload for quota and display purposes
required
mime_type string MIME type of the uploaded file (e.g. image/jpeg, application/pdf)
required
attachment_type enum Semantic classification of the attachment for display and filtering
required
storage_key string Opaque key used to retrieve the file from cloud object storage (e.g. S3/GCS path). Never exposed directly to clients.
requiredunique
storage_bucket string Name of the cloud storage bucket holding this file, allowing bucket-per-tenant isolation
required
cdn_url string Signed CDN URL for direct client download. Nullable — generated on demand and not persisted long-term.
-
checksum_sha256 string SHA-256 hex digest of file contents for integrity verification and deduplication detection
required
status enum Lifecycle state of the attachment record
required
virus_scan_result enum Result from async virus/malware scan after upload
-
virus_scanned_at datetime Timestamp when the virus scan completed
-
organization_id uuid Denormalized organization scope for tenant isolation and multi-tenancy enforcement at the row level
required
sort_order integer Display order of attachments within the activity, user-adjustable via the attachment thumbnail strip
-
description text Optional free-text description added by the uploader to explain what the attachment shows
-
offline_temp_id string Temporary client-side ID assigned when the attachment was queued offline. Used by the ID mapping service to correlate after sync.
-
uploaded_at datetime Timestamp when the file was successfully received and stored
-
deleted_at datetime Soft-delete timestamp. Null means the record is active.
-
created_at datetime Record creation timestamp
required
updated_at datetime Last modification timestamp
required

Database Indexes

idx_activity_attachments_activity_id
btree

Columns: activity_id, deleted_at

idx_activity_attachments_organization_id
btree

Columns: organization_id, status

idx_activity_attachments_storage_key
btree unique

Columns: storage_key

idx_activity_attachments_uploaded_by
btree

Columns: uploaded_by_user_id, created_at

idx_activity_attachments_virus_scan
btree

Columns: virus_scan_result, status

Validation Rules

allowed_mime_types error

Validation failed

max_file_size_50mb error

Validation failed

file_name_sanitization error

Validation failed

checksum_integrity_on_store error

Validation failed

storage_key_uniqueness error

Validation failed

status_transition_forward_only error

Validation failed

activity_must_exist_and_be_active error

Validation failed

Business Rules

attachment_requires_completed_virus_scan
on_create

An attachment may not be displayed to any client until virus_scan_result is 'clean'. Attachments in 'pending' or 'virus_flagged' state must not be served via CDN URL.

max_attachments_per_activity
on_create

A single activity may have at most 10 active (non-deleted) attachments to prevent abuse and manage storage costs.

tenant_isolation
on_create

organization_id on the attachment must match organization_id of the parent activity. Cross-organization attachment access is forbidden at the API layer.

soft_delete_only
on_delete

Attachments are never hard-deleted from the database. Setting deleted_at performs a logical delete. The backing file in object storage is purged asynchronously after a 30-day grace period to support recovery.

offline_upload_queued_to_outbox
on_create

When the device is offline, attachment upload is serialized into the mutation outbox with an offline_temp_id. The ID mapping service resolves the final server-assigned ID upon sync and updates all local references.

bufdir_audit_retention
always

Attachments linked to activities used in Bufdir reports must be retained for a minimum of 5 years from the report submission date to satisfy Norwegian grant audit requirements.

uploader_must_own_or_proxy_activity
on_create

Only the peer mentor who owns the activity or a coordinator with proxy rights over that peer mentor may upload or delete attachments.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
archive_after_1year