Skip to main content

ADR-008: Use MinIO for Object Storage

Status

Accepted

Context

Chilarai needs a storage solution for managing binary assets and documents.

Examples include:

  • Student Photos
  • Staff Photos
  • Admission Documents
  • Transfer Certificates
  • Report Cards
  • School Assets

The solution should:

  • Be open source
  • Support self-hosted deployments
  • Run easily in containers
  • Be cloud portable
  • Avoid vendor lock-in
  • Support secure document access
  • Work for both SaaS and on-premises deployments

The application already stores document metadata in PostgreSQL. Binary content should not be stored in the database.

Decision

Chilarai will use MinIO as the default object storage provider.

The application will access storage through a StorageProvider abstraction.

The initial implementation will use MinIO.

Future implementations may use:

  • Amazon S3
  • Cloudflare R2
  • Azure Blob Storage

without requiring changes to business logic.

The application will store object keys and metadata in PostgreSQL.

The application will not store binary file content in PostgreSQL.

Rationale

Open Source

MinIO is open source and can be self-hosted without dependency on a cloud provider.

Container Friendly

MinIO runs easily in:

  • Docker
  • Kubernetes
  • Virtual Machines

This aligns with Chilarai's self-hosting goals.

Cloud Portability

MinIO provides S3-compatible APIs.

This enables future migration to:

  • Amazon S3
  • Cloudflare R2
  • Other S3-compatible providers

with minimal code changes.

Vendor Neutrality

The StorageProvider abstraction prevents storage vendor lock-in.

Business modules remain independent of storage implementation details.

Security

MinIO supports:

  • Private Buckets
  • TLS
  • Encryption at Rest
  • Pre-Signed URLs

This allows secure access to student and school documents.

Storage Model

Database

Store:

  • ObjectKey
  • FileName
  • ContentType
  • FileSize

Do not store:

  • Images
  • PDFs
  • Binary Documents

inside PostgreSQL.

Access Pattern

Files will be stored in private buckets.

Applications will access files through temporary pre-signed URLs generated by the StorageProvider.

Example Object Keys

student-photos/student-123/profile.jpg

admission-documents/admission-456/birth-certificate.pdf

Consequences

Positive

  • Open source
  • Self-hostable
  • Cloud portable
  • Vendor neutral
  • Container friendly
  • Secure by default
  • Suitable for both SaaS and on-premises deployments

Negative

  • Additional service to operate
  • Backup and storage management become operational responsibilities
  • Monitoring and maintenance required for self-hosted deployments

Alternatives Considered

Amazon S3

Rejected as the default implementation due to cloud dependency and vendor lock-in concerns.

May be supported later through the StorageProvider abstraction.

Azure Blob Storage

Rejected as the default implementation due to vendor dependency and reduced portability.

May be supported later through the StorageProvider abstraction.

Cloudflare R2

Rejected as the default implementation because it is a managed service and not self-hostable.

May be supported later through the StorageProvider abstraction.

Local Filesystem Storage

Rejected because it does not scale well and complicates backup and multi-instance deployments.

Implementation Notes

Module structure:

<module>
├── domain
├── application
├── data
└── api

Storage implementations belong in the Data layer.

Example:

shared/data/storage

├── storage-provider.ts
└── minio-storage-provider.ts

Business modules should depend only on StorageProvider.