Skip to content

Развёртывание

Docker Compose

Проект использует раздельные Compose-файлы для разработки и продакшна.

Разработка (docker-compose.yml) — только инфраструктура

Приложения запускаются на хосте. PostgreSQL, Redis, MinIO и другие сервисы — в Docker.

yaml
# docker-compose.yml
services:
  postgres:
    image: postgres:16-alpine
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  mailpit:
    image: axllent/mailpit:latest
    ports:
      - "1025:1025"
      - "8025:8025"

  minio:
    image: minio/minio:latest
    ports:
      - "9000:9000"
      - "9001:9001"

  livekit:
    image: livekit/livekit-server:latest
    network_mode: host

Продакшн (docker-compose.prod.yml) — только приложения

Инфраструктура — внешние управляемые сервисы (RDS, ElastiCache и т.д.).

yaml
# docker-compose.prod.yml
services:
  migration:
    image: ${REGISTRY_HOST}/planner-migration:latest
    profiles: [migrate]

  backend:
    image: ${REGISTRY_HOST}/planner-backend:latest
    expose:
      - "4000"

  frontend:
    image: ${REGISTRY_HOST}/planner-frontend:latest
    expose:
      - "80"

  website:
    image: ${REGISTRY_HOST}/planner-website:latest
    expose:
      - "8080"

  docs:
    image: ${REGISTRY_HOST}/planner-docs:latest

Раннер миграций

Лёгкий Docker-образ для запуска Prisma-миграций и заполнения данными в продакшне.

bash
# Запуск миграций
docker compose --profile migrate run --rm migration

# Заполнение данными после миграций
docker compose --profile migrate run --rm migration seed

Образ миграций (docker/Dockerfile.migration) основан на node:22-alpine с prisma, tsx и dotenv. Точка входа (docker/entrypoint.sh) поддерживает две команды:

  • migrate (по умолчанию) — npx prisma migrate deploy
  • seednpx prisma db seed (запускает tsx prisma/seed.ts)

Бэкенд также запускает prisma migrate deploy при старте как страховочная сетка (идемпотентно).

Продакшн-развёртывание

bash
docker compose -f docker-compose.prod.yml up -d

Файл продакшн-сборки использует оптимизированные Dockerfile (Dockerfile.backend.prod) с многоэтапной сборкой для уменьшения размера образов.

Dockerfile

Все Dockerfile основаны на node:22-alpine с единой системой наименования этапов:

ЭтапОписание
baseБазовый образ Node
depsУстановка зависимостей
devРежим разработки
builderСборка приложения
runnerПродакшн-среда выполнения

Бэкенд Dockerfile (docker/Dockerfile.backend)

dockerfile
FROM node:22-alpine AS base
# ... стандартная настройка pnpm с corepack
WORKDIR /app

FROM base AS deps
COPY pnpm-lock.yaml package.json pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile

FROM base AS dev
COPY --from=deps /app/node_modules ./node_modules
COPY . .
CMD ["sh", "-c", "cd apps/backend && pnpm dev"]

Переменные окружения

ПеременнаяПо умолчаниюОписание
DATABASE_URLpostgresql://planner:planner@localhost:5432/plannerПодключение к PostgreSQL
JWT_SECRET(обязательно)Секрет для подписи JWT
REDIS_PASSWORDplanner_redisПароль Redis
SMTP_HOST(опционально)SMTP сервер для писем
SMTP_PORT1025SMTP порт
SMTP_USER(опционально)SMTP пользователь
SMTP_PASS(опционально)SMTP пароль
SMTP_FROMnoreply@planner.appEmail отправителя
CORS_ORIGINS(обязательно)Разрешённые источники (через запятую)
UPLOAD_DIR./uploadsДиректория загрузки файлов

Безопасность

HTTPS / SSL

Продакшн-развёртывание использует Caddy reverse proxy с автоматическим Let's Encrypt SSL. Порт 80 должен быть доступен для валидации домена. Весь трафик шифруется через TLSv1.2/TLSv1.3.

Заголовки безопасности

  • CSP: Content Security Policy ограничивает источники скриптов, стилей, шрифтов, изображений и подключений
  • HSTS: max-age=31536000; includeSubDomains; preload (только продакшн)
  • X-Content-Type-Options: nosniff на всех ответах
  • CORS: Белый список через CORS_ORIGINS, credentials: true

Ограничение запросов

  • Глобально: 60 запросов/минуту через Redis
  • На эндпоинты: регистрация (5/мин), вход (10/мин), обновление токена (20/мин), забыли пароль (3/мин), сброс пароля (5/мин), подтверждение email (5/мин), повторная отправка (3/мин)
  • Блокировка: 5 неудачных попыток → блокировка на 15 минут

Загрузка файлов

  • Макс. размер: 50MB (документы), 2MB (аватары)
  • Валидация magic bytes (JPEG, PNG, PDF и т.д.)
  • SVG файлы заблокированы (XSS риск)
  • Документы отдаются с Content-Disposition: attachment
  • S3 ACL: аватары public-read, документы private

Документация API

Swagger UI доступен по /api/docs только в режиме разработки. Отключён в продакшне (NODE_ENV === 'production').

Порт маппинг

СервисВнутренний портВнешний порт
Бэкенд40004000
Фронтенд30003000
Сайт80808080
Документация80808081
PostgreSQL54325432

Проверка здоровья

Все сервисы отвечают HTTP 200 при работе:

bash
curl http://localhost:4000/api/health
curl http://localhost:3000
curl http://localhost:8080
curl http://localhost:8081

Эндпоинт здоровья проверяет подключение к БД, Redis, LiveKit и S3. Детали ошибок скрыты в продакшне.