Files
classroomio/docker/docker-compose.yaml
T
Abdulmuizz Hamzat 5e2dcf71f4 docs: add dev setup guide and make package scripts cross-platform (Windows) (#664)
* chore: update README with environment setup instructions and demo account credentials

fix: replace rm -rf with rimraf in build scripts for cross-platform compatibility

fix: add shell option to pnpm command in db-setup script for Windows compatibility

chore: update package.json files to use rimraf instead of rm -rf for consistency

chore: add rimraf dependency to pnpm-lock.yaml

feat: add postinstall script to install lefthook git hooks in a cross-platform manner

* docs(qa): add QA test plan, flow checklists, and bug-report workflow

Add a repo-native QA execution layer on top of FEATURE_AUDIT.md (the
feature map). Test cases live in the repo; bugs live in GitHub Issues, so
there is no duplicate tracker to keep in sync.

QA system:
- FEATURE_AUDIT.md: the feature map - every feature, its user flow, and
  edge cases with file:line citations.
- qa/README.md: the workflow, severity/difficulty rubrics, label setup,
  and a static feature -> flow coverage map proving all 42 audited
  features have a test plan.
- qa/flows/01..13: per-flow happy-path checklists covering signup &
  onboarding, course authoring, people/invites/roles, student ->
  certificate, AI assistant & tutor, programs/attendance, community,
  org public site, media & import, org settings, public API/MCP,
  enterprise SSO/licensing, and billing & AI credits.
- .github/ISSUE_TEMPLATE/qa-bug.yml: a QA Bug template requiring
  severity, difficulty, area, repro steps, and a screen recording.

Dev tooling:
- package.json: add db:studio and docker:build scripts.
- packages/db: add db:studio (drizzle-kit studio); fix db:reset on
  Windows by spawning the pnpm.cmd shim with shell:true (Node's
  CVE-2024-27980 fix blocks spawning .cmd/.bat without a shell).

* chore: update QA bug template and README for clarity and improved workflow

* docs: enhance DEV_SETUP_NOTES and README for clarity on prerequisites and email setup
chore: update package.json scripts for cross-platform compatibility
feat: add cross-platform Prettier check script for pre-commit hook

* Remove QA documentation and flow files for ClassroomIO

- Deleted the entire QA README.md file which contained the QA process, bug filing guidelines, and feature coverage map.
- Removed all flow files (01 to 13) that detailed the QA testing processes for various features including admin signup, course authoring, people management, student learning, AI assistant, programs, community, org public site, media management, org settings, public API, enterprise SSO, billing, and AI credits.

* fix: update postinstall script
2026-06-15 17:40:06 +01:00

165 lines
5.9 KiB
YAML

services:
postgres:
image: postgres:16-alpine
container_name: cio-postgres
# Bound to localhost only so host tools (pnpm api:dev, db:setup) can reach it
# without exposing the database to the LAN.
ports:
- "127.0.0.1:5432:5432"
environment:
POSTGRES_DB: ${POSTGRES_DB:-classroomio}
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
# Require a successful query so we only pass once Postgres is out of recovery
# (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'",
]
interval: 5s
timeout: 5s
retries: 15
start_period: 10s
redis:
image: redis:7-alpine
container_name: cio-redis
# Bound to localhost only (see postgres note above).
ports:
- "127.0.0.1:6379:6379"
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
start_period: 5s
minio:
image: minio/minio:latest
container_name: cio-minio
command: server /data --console-address ":9001"
ports:
- "9000:9000"
- "9001:9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin}
volumes:
- minio-data:/data
profiles:
- minio
minio-init:
image: minio/mc:latest
container_name: cio-minio-init
depends_on:
- minio
entrypoint: >
/bin/sh -c "
echo 'Waiting for MinIO to be ready...';
sleep 5;
mc alias set local http://minio:9000 $${MINIO_ROOT_USER:-minioadmin} $${MINIO_ROOT_PASSWORD:-minioadmin};
mc mb local/videos --ignore-existing;
mc mb local/documents --ignore-existing;
mc mb local/media --ignore-existing;
mc anonymous set download local/media;
echo 'MinIO buckets created';
exit 0;
"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin}
profiles:
- minio
api:
build:
context: ..
dockerfile: docker/Dockerfile.api
container_name: cio-api
ports:
- "3081:3081"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3081
PUBLIC_SERVER_URL: ${PUBLIC_SERVER_URL:-http://localhost:3081}
TRUSTED_ORIGINS: ${TRUSTED_ORIGINS:-}
DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@postgres:5432/${POSTGRES_DB:-classroomio}
PRIVATE_DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@postgres:5432/${POSTGRES_DB:-classroomio}
REDIS_URL: redis://redis:6379
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-docker-local-client-id}
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-docker-local-client-secret}
SMTP_HOST: ${SMTP_HOST:-}
SMTP_USER: ${SMTP_USER:-}
SMTP_PASSWORD: ${SMTP_PASSWORD:-}
SMTP_PORT: ${SMTP_PORT:-}
SMTP_SENDER: ${SMTP_SENDER:-}
CLOUDFLARE_BUCKET_DOMAIN: ${CLOUDFLARE_BUCKET_DOMAIN:-}
CLOUDFLARE_ACCESS_KEY: ${CLOUDFLARE_ACCESS_KEY:-}
CLOUDFLARE_SECRET_ACCESS_KEY: ${CLOUDFLARE_SECRET_ACCESS_KEY:-}
CLOUDFLARE_ACCOUNT_ID: ${CLOUDFLARE_ACCOUNT_ID:-}
CLOUDFLARE_IMAGE_BUCKET_DOMAIN: ${CLOUDFLARE_IMAGE_BUCKET_DOMAIN:-}
CLOUDFLARE_RENDERING_API_KEY: ${CLOUDFLARE_RENDERING_API_KEY:-}
OBJECT_STORAGE_ENDPOINT: ${OBJECT_STORAGE_ENDPOINT:-}
OBJECT_STORAGE_PUBLIC_ENDPOINT: ${OBJECT_STORAGE_PUBLIC_ENDPOINT:-}
OBJECT_STORAGE_ACCESS_KEY_ID: ${OBJECT_STORAGE_ACCESS_KEY_ID:-}
OBJECT_STORAGE_SECRET_ACCESS_KEY: ${OBJECT_STORAGE_SECRET_ACCESS_KEY:-}
OBJECT_STORAGE_FORCE_PATH_STYLE: ${OBJECT_STORAGE_FORCE_PATH_STYLE:-true}
OBJECT_STORAGE_MEDIA_PUBLIC_BASE_URL: ${OBJECT_STORAGE_MEDIA_PUBLIC_BASE_URL:-}
AUTH_BEARER_TOKEN: ${AUTH_BEARER_TOKEN:-local-dev-api-key}
PRIVATE_SERVER_KEY: ${PRIVATE_SERVER_KEY:-local-dev-api-key}
DASHBOARD_ORIGIN: ${DASHBOARD_ORIGIN:-}
LICENSE_KEY: ${LICENSE_KEY:-}
UNSPLASH_API_KEY: ${UNSPLASH_API_KEY:-}
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:-local-dev-only-secret-change-this}
SKIP_DB_SETUP: ${SKIP_DB_SETUP:-}
restart: unless-stopped
dashboard:
build:
context: ..
dockerfile: docker/Dockerfile.dashboard
args:
PUBLIC_IS_SELFHOSTED: ${PUBLIC_IS_SELFHOSTED:-true}
container_name: cio-dashboard
ports:
- "3082:3082"
depends_on:
api:
condition: service_started
environment:
NODE_ENV: production
PORT: 3082
ORIGIN: ${DASHBOARD_ORIGIN:-http://localhost:3082}
PUBLIC_IS_SELFHOSTED: ${PUBLIC_IS_SELFHOSTED:-true}
PRIVATE_SERVER_URL: ${PRIVATE_SERVER_URL:-http://api:3081}
PRIVATE_SERVER_KEY: ${PRIVATE_SERVER_KEY:-local-dev-api-key}
PRIVATE_APP_HOST: ${PRIVATE_APP_HOST:-localhost}
PRIVATE_APP_SUBDOMAINS: ${PRIVATE_APP_SUBDOMAINS:-app}
AUTH_BEARER_TOKEN: ${AUTH_BEARER_TOKEN:-}
ALLOWED_EXTERNAL_DOMAINS: ${ALLOWED_EXTERNAL_DOMAINS:-}
CSP_SCRIPT_SRC_DOMAINS: ${CSP_SCRIPT_SRC_DOMAINS:-}
CSP_STYLE_SRC_DOMAINS: ${CSP_STYLE_SRC_DOMAINS:-}
CSP_CONNECT_SRC_DOMAINS: ${CSP_CONNECT_SRC_DOMAINS:-}
CSP_FRAME_SRC_DOMAINS: ${CSP_FRAME_SRC_DOMAINS:-}
CSP_FONT_SRC_DOMAINS: ${CSP_FONT_SRC_DOMAINS:-}
CSP_MEDIA_SRC_DOMAINS: ${CSP_MEDIA_SRC_DOMAINS:-}
restart: unless-stopped
volumes:
postgres-data:
redis-data:
minio-data: