feat: configurable upload file size limits via .env (#695)

* feat: make upload file size limits configurable via .env

Add UPLOAD_MAX_*_MB environment variables for documents, images, videos,
exercise assignment files, AI assistant documents, landing page images,
and media thumbnails. API presign routes validate file size server-side;
dashboard UI reads the same limits from layout data.

* chore: wire upload limit env vars through Docker compose and docs

Pass UPLOAD_MAX_*_MB from the root .env into api and dashboard containers
in both compose files, document them in .env.example and self-hosting guides.

Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>

* docs: cross-link upload limits in README, Railway, Coolify, and Cloudflare guides

Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>

* fix: address PR review feedback on upload limits

- Restore 5 MB default for thumbnail uploads (edit-asset-dialog regression)
- Add getResolvedUploadLimits() fallback for Storybook/tests
- Cache core getUploadLimits() like the dashboard helper
- Document presign fileSize as advisory; allow zero-byte fileSize in schema
- Only send fileSize to presign when greater than zero

* docs: remove upload limits from Cloudflare setup guide

---------
This commit is contained in:
Rotimi Best
2026-06-29 12:48:51 +01:00
committed by GitHub
parent 65420320e7
commit a61942feb9
39 changed files with 411 additions and 79 deletions
+26 -12
View File
@@ -28,8 +28,8 @@ services:
# (pg_isready can pass while DB is still in recovery, causing 57P03 on sign-in)
test:
[
"CMD-SHELL",
"pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-classroomio} && psql -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-classroomio} -tAc 'SELECT 1'",
'CMD-SHELL',
"pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-classroomio} && psql -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-classroomio} -tAc 'SELECT 1'"
]
interval: 5s
timeout: 5s
@@ -39,11 +39,11 @@ services:
redis:
image: redis:7-alpine
container_name: cio-redis
command: ["redis-server", "--appendonly", "yes"]
command: ['redis-server', '--appendonly', 'yes']
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
test: ['CMD', 'redis-cli', 'ping']
interval: 5s
timeout: 3s
retries: 10
@@ -54,8 +54,8 @@ services:
container_name: cio-minio
command: server /data --console-address ":9001"
ports:
- "9000:9000"
- "9001:9001"
- '9000:9000'
- '9001:9001'
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin}
@@ -91,7 +91,7 @@ services:
image: classroomio/api:${CIO_VERSION:-latest}
container_name: cio-api
ports:
- "3081:3081"
- '3081:3081'
depends_on:
postgres:
condition: service_healthy
@@ -101,10 +101,10 @@ services:
# node:slim has no curl/wget; use Node's global fetch (Node 20+).
test:
[
"CMD",
"node",
"-e",
"fetch('http://localhost:3081/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))",
'CMD',
'node',
'-e',
"fetch('http://localhost:3081/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
]
interval: 10s
timeout: 5s
@@ -138,6 +138,12 @@ services:
DASHBOARD_ORIGIN: ${DASHBOARD_ORIGIN:-}
LICENSE_KEY: ${LICENSE_KEY:-}
UNSPLASH_API_KEY: ${UNSPLASH_API_KEY:-}
# Upload size limits (megabytes). Unset = built-in defaults — see .env.example.
UPLOAD_MAX_DOCUMENT_MB: ${UPLOAD_MAX_DOCUMENT_MB:-}
UPLOAD_MAX_IMAGE_MB: ${UPLOAD_MAX_IMAGE_MB:-}
UPLOAD_MAX_VIDEO_MB: ${UPLOAD_MAX_VIDEO_MB:-}
UPLOAD_MAX_EXERCISE_FILE_MB: ${UPLOAD_MAX_EXERCISE_FILE_MB:-}
UPLOAD_MAX_AGENT_DOCUMENT_MB: ${UPLOAD_MAX_AGENT_DOCUMENT_MB:-}
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:?set a strong BETTER_AUTH_SECRET in .env}
SKIP_DB_SETUP: ${SKIP_DB_SETUP:-}
restart: unless-stopped
@@ -146,7 +152,7 @@ services:
image: classroomio/dashboard:${CIO_VERSION:-latest}
container_name: cio-dashboard
ports:
- "3082:3082"
- '3082:3082'
depends_on:
api:
condition: service_healthy
@@ -166,6 +172,14 @@ services:
CSP_FRAME_SRC_DOMAINS: ${CSP_FRAME_SRC_DOMAINS:-}
CSP_FONT_SRC_DOMAINS: ${CSP_FONT_SRC_DOMAINS:-}
CSP_MEDIA_SRC_DOMAINS: ${CSP_MEDIA_SRC_DOMAINS:-}
# Upload size limits (megabytes). Unset = built-in defaults — see .env.example.
UPLOAD_MAX_DOCUMENT_MB: ${UPLOAD_MAX_DOCUMENT_MB:-}
UPLOAD_MAX_IMAGE_MB: ${UPLOAD_MAX_IMAGE_MB:-}
UPLOAD_MAX_VIDEO_MB: ${UPLOAD_MAX_VIDEO_MB:-}
UPLOAD_MAX_EXERCISE_FILE_MB: ${UPLOAD_MAX_EXERCISE_FILE_MB:-}
UPLOAD_MAX_AGENT_DOCUMENT_MB: ${UPLOAD_MAX_AGENT_DOCUMENT_MB:-}
UPLOAD_MAX_LANDING_IMAGE_MB: ${UPLOAD_MAX_LANDING_IMAGE_MB:-}
UPLOAD_MAX_THUMBNAIL_MB: ${UPLOAD_MAX_THUMBNAIL_MB:-}
restart: unless-stopped
# Background worker (BullMQ). Drains the Redis queue: video processing, transcription,