Files
LMS/docker-compose.prod.yml
Vladislav Kopnin d04207302a Phase 7: deployment, data import, UI hardening and security fixes
Docker/prod deployment:
- multi-stage Dockerfile (JDK21 build, JRE21 run), docker-compose.prod.yml,
  nginx config for lms.our-place.ru, deploy.sh; DEPLOY/IMPORT guides (UI flow)
- Fix Docker 401: LMS_JWT_JWK_SET_URI for academic/progress; forward-headers

Variant distribution (lab page only):
- round-robin by student level, shared random queue across selected groups,
  least-used variants, manual pins always preserved; occupied/dup labels
- setup page: single form + one «Сохранить всё», batch level/variant for
  selected students (checkboxes)

Grades, defense, materials:
- publication gate + comment lists; defense CSV import (2/3 cols, quotes)
- additional task after defense ("начать заново"); enroll/unenroll students
  from group page; temporary-password lock (no navigation until changed) and
  persistent "Смена пароля"; forced change once
- chapter page /learn/{c}; header: LMS home, Войти, user -> dashboard,
  compact theme toggle; responsive mobile header
- markdown: single newlines are soft breaks; highlight.js with light/dark themes
- lab/content imports ZIP-only (lab.yaml+README+variants/assets,
  chapters tree+assets); duplicate lab numbers rejected; variant ordering
  and date defaults honored

Fixes:
- 500 on student create (@MapsId set before persist); broken dialogs/JS refs in group page
2026-09-15 00:09:28 +03:00

117 lines
3.7 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Production-стек LMS: PostgreSQL 18 + 5 сервисов.
# Java на сервере не нужна — всё собирается и запускается в контейнерах.
#
# Запуск:
# cp .env.prod.example .env.prod # и заполнить секреты
# docker compose --env-file .env.prod -f docker-compose.prod.yml up -d --build
#
# Наружу публикуется только web на 127.0.0.1:8090; его проксирует nginx (deploy/nginx).
name: lms
x-db-env: &db-env
LMS_DB_USER: ${LMS_DB_USER:-lms}
LMS_DB_PASSWORD: ${LMS_DB_PASSWORD:?Задайте LMS_DB_PASSWORD в .env.prod}
# Все backend-сервисы проверяют JWT по JWKS identity. В контейнерах это
# http://identity:8081, а не localhost (иначе 401 на авторизованных запросах).
x-jwt-env: &jwt-env
LMS_JWT_JWK_SET_URI: http://identity:8081/api/v1/auth/jwks.json
services:
postgres:
image: postgres:18
restart: unless-stopped
environment:
POSTGRES_DB: ${LMS_DB_NAME:-lms}
POSTGRES_USER: ${LMS_DB_USER:-lms}
POSTGRES_PASSWORD: ${LMS_DB_PASSWORD:?Задайте LMS_DB_PASSWORD в .env.prod}
volumes:
- lms_pgdata:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${LMS_DB_USER:-lms} -d ${LMS_DB_NAME:-lms}"]
interval: 5s
timeout: 3s
retries: 20
networks: [lms]
identity:
build: { context: ., target: identity }
image: lms-identity:latest
restart: unless-stopped
environment:
<<: *db-env
LMS_DB_URL: jdbc:postgresql://postgres:5432/${LMS_DB_NAME:-lms}?currentSchema=identity
depends_on:
postgres: { condition: service_healthy }
networks: [lms]
academic:
build: { context: ., target: academic }
image: lms-academic:latest
restart: unless-stopped
environment:
<<: [*db-env, *jwt-env]
LMS_DB_URL: jdbc:postgresql://postgres:5432/${LMS_DB_NAME:-lms}?currentSchema=academic
LMS_CONTENT_ASSETS_DIR: /data/content-assets
volumes:
- lms_assets:/data/content-assets
depends_on:
postgres: { condition: service_healthy }
identity: { condition: service_started }
networks: [lms]
progress:
build: { context: ., target: progress }
image: lms-progress:latest
restart: unless-stopped
environment:
<<: [*db-env, *jwt-env]
LMS_DB_URL: jdbc:postgresql://postgres:5432/${LMS_DB_NAME:-lms}?currentSchema=progress
LMS_SUBMISSIONS_DIR: /data/submissions
LMS_IDENTITY_URI: http://identity:8081
LMS_ACADEMIC_URI: http://academic:8082
volumes:
- lms_submissions:/data/submissions
depends_on:
postgres: { condition: service_healthy }
identity: { condition: service_started }
academic: { condition: service_started }
networks: [lms]
gateway:
build: { context: ., target: gateway }
image: lms-gateway:latest
restart: unless-stopped
environment:
LMS_IDENTITY_URI: http://identity:8081
LMS_ACADEMIC_URI: http://academic:8082
LMS_PROGRESS_URI: http://progress:8083
LMS_JWT_JWK_SET_URI: http://identity:8081/api/v1/auth/jwks.json
depends_on:
identity: { condition: service_started }
academic: { condition: service_started }
progress: { condition: service_started }
networks: [lms]
web:
build: { context: ., target: web }
image: lms-web:latest
restart: unless-stopped
environment:
LMS_GATEWAY_URL: http://gateway:8080
SERVER_PORT: 8090
ports:
- "127.0.0.1:${LMS_WEB_PORT:-8090}:8090"
depends_on:
gateway: { condition: service_started }
networks: [lms]
networks:
lms:
volumes:
lms_pgdata:
lms_submissions:
lms_assets: