Files
sciagent/docker-compose.yml
Thinh Lam 688fac73e9
CI/CD / backend (push) Failing after 2m8s
CI/CD / frontend (push) Failing after 1m40s
CI/CD / deploy (push) Has been skipped
sciagent code + Gitea Actions CI/CD
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 09:38:30 +07:00

286 lines
13 KiB
YAML

services:
minio:
image: quay.io/minio/minio:latest
container_name: minio
# Host 9000/9001 are often taken; map to free ports on your machine (S3 API / web UI).
ports:
- "19000:9000" # API / S3 endpoint → http://localhost:19000
- "19001:9001" # Web console → http://localhost:19001
environment:
MINIO_ROOT_USER: minio_user
MINIO_ROOT_PASSWORD: minio_password # Use strong password in real projects!
# Community MinIO has no per-bucket PutBucketCors (AiStor-only). Browsers need global API CORS for presigned GETs.
MINIO_API_CORS_ALLOW_ORIGIN: ${MINIO_API_CORS_ALLOW_ORIGIN:-*}
volumes:
- ./assets/minio-data:/data
command: server /data --console-address ":9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
networks:
profyt-net:
ipv4_address: "10.5.0.3"
# One-shot: ensure buckets. Browser CORS is MINIO_API_CORS_ALLOW_ORIGIN on the minio service (not mc cors set).
minio-cors:
image: quay.io/minio/mc:latest
container_name: minio-cors
depends_on:
minio:
condition: service_healthy
entrypoint: ["/bin/sh", "-c"]
command:
- |
mc alias set local http://minio:9000 minio_user minio_password
for b in initiative-attachments initiative-exports initiative-quarantine imagehub-blobs; do
mc mb -p "local/$$b" 2>/dev/null || true
done
echo "MinIO buckets ensured."
networks:
profyt-net:
ipv4_address: "10.5.0.5"
restart: "no"
postgres:
image: postgres:16-alpine
container_name: initiative-postgres
# Host 5432 is often taken by a local Postgres; map a different port for host access.
ports:
- "15432:5432"
environment:
POSTGRES_USER: initiative
POSTGRES_PASSWORD: initiative_secret
POSTGRES_DB: initiatives
volumes:
- initiative_pg_data:/var/lib/postgresql/data
# Schema lives under be0 (dyd/0backend/migrations is not in this repo).
- ./be0/migrations/001_initiative_schema.sql:/docker-entrypoint-initdb.d/01_initiative_schema.sql:ro
- ./be0/migrations/002_application_storage_extensions.sql:/docker-entrypoint-initdb.d/02_application_storage_extensions.sql:ro
- ./be0/migrations/003_review_documents.sql:/docker-entrypoint-initdb.d/03_review_documents.sql:ro
- ./be0/migrations/004_evidence_artifact_review.sql:/docker-entrypoint-initdb.d/04_evidence_artifact_review.sql:ro
- ./be0/migrations/004_application_admin_results.sql:/docker-entrypoint-initdb.d/05_application_admin_results.sql:ro
- ./be0/migrations/006_user_notifications.sql:/docker-entrypoint-initdb.d/06_user_notifications.sql:ro
- ./be0/migrations/007_user_roles_email_policy_admin.sql:/docker-entrypoint-initdb.d/07_user_roles_email_policy_admin.sql:ro
- ./be0/migrations/008_audit_events.sql:/docker-entrypoint-initdb.d/08_audit_events.sql:ro
- ./be0/migrations/009_backup_artifact_roles_storage_kind.sql:/docker-entrypoint-initdb.d/09_backup_artifact_roles_storage_kind.sql:ro
- ./be0/migrations/010_user_staff_profiles.sql:/docker-entrypoint-initdb.d/10_user_staff_profiles.sql:ro
- ./be0/migrations/011_academic_titles_vn.sql:/docker-entrypoint-initdb.d/11_academic_titles_vn.sql:ro
- ./be0/migrations/012_password_reset.sql:/docker-entrypoint-initdb.d/12_password_reset.sql:ro
- ./be0/migrations/013_email_verification.sql:/docker-entrypoint-initdb.d/13_email_verification.sql:ro
- ./be0/migrations/014_registration_otp.sql:/docker-entrypoint-initdb.d/14_registration_otp.sql:ro
- ./be0/migrations/015_document_templates.sql:/docker-entrypoint-initdb.d/15_document_templates.sql:ro
- ./be0/migrations/016_research_projects.sql:/docker-entrypoint-initdb.d/16_research_projects.sql:ro
- ./be0/migrations/017_imagehub_datasets.sql:/docker-entrypoint-initdb.d/17_imagehub_datasets.sql:ro
- ./be0/migrations/018_imagehub_segmentation_links.sql:/docker-entrypoint-initdb.d/18_imagehub_segmentation_links.sql:ro
- ./be0/migrations/019_imagehub_cloud_import.sql:/docker-entrypoint-initdb.d/19_imagehub_cloud_import.sql:ro
- ./be0/migrations/020_imagehub_dataset_stages.sql:/docker-entrypoint-initdb.d/20_imagehub_dataset_stages.sql:ro
- ./be0/migrations/021_imagehub_task_pipeline.sql:/docker-entrypoint-initdb.d/21_imagehub_task_pipeline.sql:ro
- ./be0/migrations/022_imagehub_task_annotations.sql:/docker-entrypoint-initdb.d/22_imagehub_task_annotations.sql:ro
- ./be0/migrations/023_imagehub_dataset_members.sql:/docker-entrypoint-initdb.d/23_imagehub_dataset_members.sql:ro
- ./be0/migrations/024_imagehub_dataset_project_link.sql:/docker-entrypoint-initdb.d/24_imagehub_dataset_project_link.sql:ro
- ./be0/migrations/025_imagehub_task_review_events.sql:/docker-entrypoint-initdb.d/25_imagehub_task_review_events.sql:ro
- ./be0/migrations/026_imagehub_file_folder_path.sql:/docker-entrypoint-initdb.d/26_imagehub_file_folder_path.sql:ro
- ./be0/migrations/027_imagehub_dataset_label_map.sql:/docker-entrypoint-initdb.d/27_imagehub_dataset_label_map.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U initiative -d initiatives"]
interval: 3s
timeout: 5s
retries: 20
start_period: 10s
restart: unless-stopped
networks:
profyt-net:
ipv4_address: "10.5.0.10"
# ── Frontends ───────────────────────────────────────────────────────────────
# Two SPAs built from the npm workspace (shared kernel + each app). The browser
# calls same-origin /api/*; Vite proxies to be0 (localhost:4402 is wrong inside the
# container). Build context is the repo ROOT — the workspace — not the app dir, so
# `@ump/shared` (../shared/src) resolves. Dev mode: bind-mount the workspace + reinstall
# on start so new deps land in the isolated node_modules volume.
frontend_user:
build:
context: .
dockerfile: frontend_user/Dockerfile
container_name: frontend_user
ipc: host
ports:
- 8081:5173
environment:
- GENERIC_TIMEZONE=UTC
- VITE_DEV_PROXY_TARGET=http://be0:4402
# When unset, Vite allows all hosts. Set e.g. YOUR_IP,localhost for cloud/LAN dev.
- VITE_ALLOWED_HOSTS=${VITE_ALLOWED_HOSTS:-}
volumes:
- ./package.json:/app/package.json
- ./package-lock.json:/app/package-lock.json
- ./shared:/app/shared
- ./frontend_user:/app/frontend_user
- ./frontend_admin:/app/frontend_admin
- ./frontend_investigator:/app/frontend_investigator
- ./frontend_publisher:/app/frontend_publisher
# Isolated workspace-hoisted node_modules (not shadowed by the host).
- /app/node_modules
command: ["sh", "-c", "npm install && npm run dev -w frontend_user -- --host 0.0.0.0 --port 5173"]
depends_on:
be0:
condition: service_started
networks:
profyt-net:
ipv4_address: "10.5.0.4"
frontend_admin:
build:
context: .
dockerfile: frontend_admin/Dockerfile
container_name: frontend_admin
ipc: host
ports:
- 8082:5174
environment:
- GENERIC_TIMEZONE=UTC
- VITE_DEV_PROXY_TARGET=http://be0:4402
- VITE_ALLOWED_HOSTS=${VITE_ALLOWED_HOSTS:-}
volumes:
- ./package.json:/app/package.json
- ./package-lock.json:/app/package-lock.json
- ./shared:/app/shared
- ./frontend_user:/app/frontend_user
- ./frontend_admin:/app/frontend_admin
- ./frontend_investigator:/app/frontend_investigator
- ./frontend_publisher:/app/frontend_publisher
- /app/node_modules
command: ["sh", "-c", "npm install && npm run dev -w frontend_admin -- --host 0.0.0.0 --port 5174"]
depends_on:
be0:
condition: service_started
networks:
profyt-net:
ipv4_address: "10.5.0.6"
frontend_investigator:
build:
context: .
dockerfile: frontend_investigator/Dockerfile
container_name: frontend_investigator
ipc: host
ports:
- 8083:5175
environment:
- GENERIC_TIMEZONE=UTC
- VITE_DEV_PROXY_TARGET=http://be0:4402
- VITE_ALLOWED_HOSTS=${VITE_ALLOWED_HOSTS:-}
volumes:
- ./package.json:/app/package.json
- ./package-lock.json:/app/package-lock.json
- ./shared:/app/shared
- ./frontend_user:/app/frontend_user
- ./frontend_admin:/app/frontend_admin
- ./frontend_investigator:/app/frontend_investigator
- ./frontend_publisher:/app/frontend_publisher
- /app/node_modules
command: ["sh", "-c", "npm install && npm run dev -w frontend_investigator -- --host 0.0.0.0 --port 5175"]
depends_on:
be0:
condition: service_started
networks:
profyt-net:
ipv4_address: "10.5.0.7"
frontend_publisher:
build:
context: .
dockerfile: frontend_publisher/Dockerfile
container_name: frontend_publisher
ipc: host
ports:
- 8084:5176
environment:
- GENERIC_TIMEZONE=UTC
- VITE_DEV_PROXY_TARGET=http://be0:4402
- VITE_ALLOWED_HOSTS=${VITE_ALLOWED_HOSTS:-}
volumes:
- ./package.json:/app/package.json
- ./package-lock.json:/app/package-lock.json
- ./shared:/app/shared
- ./frontend_user:/app/frontend_user
- ./frontend_admin:/app/frontend_admin
- ./frontend_investigator:/app/frontend_investigator
- ./frontend_publisher:/app/frontend_publisher
- /app/node_modules
command: ["sh", "-c", "npm install && npm run dev -w frontend_publisher -- --host 0.0.0.0 --port 5176"]
depends_on:
be0:
condition: service_started
networks:
profyt-net:
ipv4_address: "10.5.0.8"
be0:
build:
context: ./be0
dockerfile: Dockerfile
container_name: be0
ipc: host
ports:
- 4402:4402
environment:
# Dev stack: hot-reload API when bind-mounting ./be0
- UVICORN_RELOAD=1
- GENERIC_TIMEZONE=UTC
- INITIATIVE_DATABASE_URL=postgresql+asyncpg://initiative:initiative_secret@postgres:5432/initiatives
- APPLICATION_DRAFT_DIR=/app/assets/application-drafts
# Shared with fe0 `public/submitted-initiatives` so PDFs written by be0 are served by Vite static.
- SUBMITTED_INITIATIVES_DIR=/app/submitted-initiatives
# From inside the be0 container, reach MinIO on the shared Docker network (not localhost:19000).
- S3_ENDPOINT_URL=http://minio:9000
- S3_ACCESS_KEY=minio_user
- S3_SECRET_KEY=minio_password
- S3_BUCKET_ATTACHMENTS=initiative-attachments
- S3_BUCKET_EXPORTS=initiative-exports
- S3_BUCKET_QUARANTINE=initiative-quarantine
# Presigned « Xem / tải » links in the browser must hit the host-mapped MinIO port, not minio:9000.
- S3_PUBLIC_ENDPOINT_URL=${S3_PUBLIC_ENDPOINT_URL:-http://localhost:19000}
# Optional: comma-separated; merged with localhost defaults (e.g. http://YOUR_IP:8081 for LAN deploys).
- CORS_ORIGINS=${CORS_ORIGINS:-}
# Optional: comma-separated institutional admin emails. When unset, auth_api uses built-in UMP allow-list.
- AUTH_ADMIN_EMAILS=${AUTH_ADMIN_EMAILS:-}
# SMTP (Option A) — OTP + password-reset email. Set SMTP_HOST (and secrets) in repo-root .env; see .env.example.
- SMTP_HOST=${SMTP_HOST:-}
- SMTP_PORT=${SMTP_PORT:-587}
- SMTP_USER=${SMTP_USER:-}
- SMTP_PASSWORD=${SMTP_PASSWORD:-}
- AUTH_MAIL_FROM=${AUTH_MAIL_FROM:-}
- SMTP_USE_TLS=${SMTP_USE_TLS:-1}
- AUTH_PUBLIC_WEB_ORIGIN=${AUTH_PUBLIC_WEB_ORIGIN:-http://localhost:8081}
# Dev-only: OTP/link in stdout instead of SMTP — leave unset when using SMTP above.
- AUTH_MAIL_LOG_ONLY=${AUTH_MAIL_LOG_ONLY:-}
# DOCX mẫu hồ sơ (Xem lại) — cùng file với fe0/public/…/template_application_form.docx
- TEMPLATE_APPLICATION_FORM_DOCX=/app/template_application_form.docx
volumes:
- ./be0:/app
- ./assets:/app/assets
- ./assets/submitted-initiatives:/app/submitted-initiatives
- ./fe0/public/assets/template_application_form.docx:/app/template_application_form.docx:ro
depends_on:
postgres:
condition: service_healthy
minio:
condition: service_healthy
# One-shot minio-cors must finish first so buckets exist (Compose v2.13+).
minio-cors:
condition: service_completed_successfully
networks:
profyt-net:
ipv4_address: "10.5.0.2"
volumes:
initiative_pg_data:
networks:
profyt-net:
driver: bridge
ipam:
config:
- subnet: "10.5.0.0/16"