Attachment
Data Entity
Description
A file attached to an activity record — such as event invitations, Facebook screenshots, or supporting documents required for Bufdir audit verification. Attachments are stored in cloud object storage and referenced by metadata records in the primary database.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key — randomly generated UUID for each attachment record | PKrequiredunique |
activity_id |
uuid |
Foreign key referencing the parent activity this file is attached to | required |
organization_id |
uuid |
Tenant isolation key — denormalised from the parent activity for efficient access control queries | required |
uploaded_by_user_id |
uuid |
UUID of the user who uploaded the file (peer mentor or coordinator) | required |
file_name |
string |
Original filename as provided by the uploader (e.g. invitation.pdf, screenshot.png) | required |
file_key |
string |
Object storage key (path) used to locate the file in cloud storage. Format: attachments/{organization_id}/{activity_id}/{uuid}.{ext} | requiredunique |
mime_type |
string |
MIME content type of the uploaded file (e.g. image/jpeg, application/pdf) | required |
file_size_bytes |
integer |
File size in bytes, recorded at upload time for quota enforcement and display | required |
attachment_type |
enum |
Categorises the nature of the attached file for filtering and display | required |
description |
text |
Optional free-text description of the attachment provided by the uploader | - |
uploaded_at |
datetime |
UTC timestamp when the file was successfully uploaded and the record created | required |
is_deleted |
boolean |
Soft-delete flag — deleted attachments are hidden from users but retained for audit trail | required |
deleted_at |
datetime |
UTC timestamp when the attachment was soft-deleted. Null if not deleted | - |
deleted_by_user_id |
uuid |
UUID of the user who performed the soft deletion. Null if not deleted | - |
Database Indexes
idx_attachments_activity_id
Columns: activity_id
idx_attachments_organization_id
Columns: organization_id
idx_attachments_uploaded_by_user_id
Columns: uploaded_by_user_id
idx_attachments_file_key
Columns: file_key
idx_attachments_activity_not_deleted
Columns: activity_id, is_deleted
Validation Rules
allowed_mime_types
error
Validation failed
max_file_size_10mb
error
Validation failed
max_attachments_per_activity
error
Validation failed
file_name_sanitised
error
Validation failed
file_key_unique
error
Validation failed
activity_id_required
error
Validation failed
description_max_length
error
Validation failed
Business Rules
attachment_must_belong_to_valid_activity
An attachment can only be created for an activity that exists and is owned by the same organization as the uploading user. Cross-tenant uploads are rejected.
uploader_must_have_access_to_activity
Only the peer mentor who owns the activity, or a coordinator/admin with access to that organization, may attach files to it.
deletion_restricted_to_owner_or_coordinator
Soft deletion of an attachment is permitted only by the original uploader, a coordinator overseeing the activity, or an organization admin. Global admins do not delete operational data.
deleted_attachment_retained_for_audit
Soft-deleted attachments (is_deleted=true) remain in the database and object storage for audit and Bufdir verification purposes. Physical deletion from storage is deferred to the retention policy lifecycle.
attachment_deletion_cascades_with_activity
When a parent activity is hard-deleted (rare admin action), all related attachment records are cascade-deleted. Soft-deleted activities do not cascade attachment deletion.
attachment_immutable_after_activity_approval
Once the parent activity has been approved by a coordinator or auto-approved, the attachment list becomes read-only. New attachments cannot be added and existing ones cannot be deleted without re-opening the activity.