core PK: id 11 required 2 unique

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.

14
Attributes
5
Indexes
7
Validation Rules
17
CRUD Operations

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
btree

Columns: activity_id

idx_attachments_organization_id
btree

Columns: organization_id

idx_attachments_uploaded_by_user_id
btree

Columns: uploaded_by_user_id

idx_attachments_file_key
btree unique

Columns: file_key

idx_attachments_activity_not_deleted
btree

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
on_create

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
on_create

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
on_delete

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
on_delete

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
on_delete

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
on_create

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.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
Permanent Storage