# Runbook поднятия отдельного проверочного сервера

## Паспорт документа

- Статус документа: working reference
- Актуально на: 1 апреля 2026 года
- Владелец: backend/platform-команда
- Пересмотр: при изменении deploy-контура `qadam-core`, `qadam-web`, env-модели или схемы staging/bootstrap сервера
- Область применения: быстрый и воспроизводимый подъём отдельного сервера, на котором одновременно работают backend и product web для UI-проверок
- Связанные документы:
  - [Runbook эксплуатации и деплоя](./deployment-runbook.md)
  - [Environment matrix](./environment-matrix.md)
  - [Текущее состояние](../project/current-state.md)
  - [Памятка для frontend-команды](../frontend/frontend-handoff.md)

## Цель документа

Этот документ нужен для случая, когда проект надо быстро поднять на отдельном сервере так, чтобы:

- backend и frontend работали вместе;
- UI можно было проверять в браузере как единый продукт;
- сборка и запуск не зависели от устного контекста;
- было ясно, что берётся из Git, а что надо переносить отдельно как runtime-конфигурацию.

## 1. Краткий вывод по готовности

На 1 апреля 2026 года проект уже можно забирать с Git на отдельный сервер.

Фактически подтверждено:

- `qadam-core` в рабочем дереве чистый и запушен в `origin/main`;
- `qadam-web` в рабочем дереве чистый и запушен в `origin/main`;
- в `qadam-core` уже лежат канонические Docker/compose/runtime-артефакты для `api`;
- в `qadam-web` уже лежат канонические Docker/compose/runtime-артефакты для `product web`;
- оба репозитория уже рассматриваются как source of truth вместо legacy checkout.

Проверенные HEAD на момент составления этого runbook:

- `qadam-core`: `a0bd363`
- `qadam-web`: `5af095d`

Важно: из Git забирается не весь runtime-контур. Вне Git всё ещё остаются:

- production/stage secrets;
- env-файлы;
- nginx-конфигурация;
- TLS;
- живая PostgreSQL/Redis инфраструктура;
- object storage credentials;
- любые данные БД и загруженные product media.

Итог:

- код и deploy-артефакты можно брать из Git уже сейчас;
- новый сервер нельзя считать полностью самоподнимаемым только после `git clone`, пока не подготовлены env, домен и инфраструктурные зависимости.

## 2. Что рекомендуется поднимать на новом сервере

Для отдельного проверочного сервера рекомендуется такой минимальный контур:

- один публичный stage-домен, например `stage-qadam.example.com`;
- один `nginx`, который проксирует:
  - `/api/*` на backend;
  - `/*` на product web;
- PostgreSQL и Redis на этом же сервере или как внешние managed сервисы;
- `qadam-core/api` как container runtime;
- `qadam-web` как container runtime;
- `qadam-roadmap` на этом сервере не обязателен, если цель именно UI-проверка продукта.

Почему именно так:

- одна origin-схема упрощает cookie auth;
- backend уже лучше всего подготовлен к контейнерному запуску;
- product web уже имеет registry/build/smoke baseline и может быть поднят рядом;
- для UI-проверок не нужен отдельный docs-service, если нет задачи тестировать сам roadmap.

## 3. Что обязательно должно быть вне Git

### Инфраструктурные зависимости

- PostgreSQL
- Redis
- домен или хотя бы публичный IP
- `nginx`
- `Docker Engine` и `docker compose`
- Node.js 20+
- `pnpm` 9.15.4+

### Секреты и runtime env

Минимально нужны:

- `DATABASE_URL`
- `REDIS_URL`
- `JWT_SECRET`
- `CORS_ORIGIN`
- `NEXT_PUBLIC_API_URL`
- `API_URL`
- `OBJECT_STORAGE_DRIVER`
- `S3_*`, если stage должен работать с реальным object storage

Опционально:

- `AXIOM_*`
- `TELEGRAM_*`
- backup/monitoring env

Полный состав и границы ownership описаны в [environment-matrix.md](./environment-matrix.md).

## 4. Рекомендуемая схема каталогов на новом сервере

```text
/srv/qadam-core
/srv/qadam-web
/etc/qadam/qadam.env
/etc/qadam/qadam-api-runtime.env
/etc/qadam/qadam-web-runtime.env
```

Если на сервере есть отдельный большой диск под Docker/build cache, его надо использовать как `data-root`, а не корневой раздел.

## 5. Порядок развертывания

### Шаг 1. Подготовить сервер

Нужны:

- `git`
- `curl`
- `docker`
- `docker compose`
- `node`
- `pnpm`
- `nginx`
- `postgresql-client`

Если PostgreSQL и Redis локальные, они тоже должны быть установлены и доступны.

### Шаг 2. Клонировать репозитории

```bash
git clone https://git.2fab.app/eldar/qadam-core.git /srv/qadam-core
git clone https://git.2fab.app/eldar/qadam-web.git /srv/qadam-web
```

Для воспроизводимого поднятия лучше сразу фиксировать commit SHA:

```bash
git -C /srv/qadam-core checkout <core-sha>
git -C /srv/qadam-web checkout <web-sha>
```

### Шаг 3. Подготовить env-файлы

#### `/etc/qadam/qadam.env`

Это основной runtime env для backend.

Минимальный шаблон:

```env
NODE_ENV=production
PORT=5002
HOSTNAME=127.0.0.1

DATABASE_URL=postgresql://...
REDIS_URL=redis://127.0.0.1:6379
JWT_SECRET=...

CORS_ORIGIN=https://stage-qadam.example.com
PUBLIC_WEB_BASE_URL=https://stage-qadam.example.com

OBJECT_STORAGE_DRIVER=s3
S3_ENDPOINT=...
S3_REGION=...
S3_BUCKET=...
S3_ACCESS_KEY_ID=...
S3_SECRET_ACCESS_KEY=...
S3_PUBLIC_BASE_URL=...
S3_FORCE_PATH_STYLE=false
S3_OBJECT_ACL=public-read
```

#### `/etc/qadam/qadam-api-runtime.env`

```env
QADAM_API_IMAGE=qadam-core-api:git-<commit-sha>
QADAM_API_ENV_FILE=/etc/qadam/qadam.env
QADAM_API_PORT=5002
QADAM_API_HOSTNAME=127.0.0.1
QADAM_API_COMPOSE_PROJECT=qadam-api-stage
```

#### `/etc/qadam/qadam-web-runtime.env`

```env
NODE_ENV=production
API_URL=http://host.docker.internal:5002/api/v1
NEXT_PUBLIC_API_URL=https://stage-qadam.example.com/api/v1
```

Если домен ещё не настроен и тест идёт по IP, временно допустимо:

```env
NEXT_PUBLIC_API_URL=http://<SERVER_IP>/api/v1
```

Но для cookie auth и итоговой UI-проверки лучше сразу использовать один stage-домен.

### Шаг 4. Поднять backend

```bash
cd /srv/qadam-core
pnpm install --frozen-lockfile
pnpm check-types
pnpm test
pnpm build
pnpm export:openapi
pnpm docker:build:api
```

Применить миграции:

```bash
cd /srv/qadam-core
set -a
source /etc/qadam/qadam-api-runtime.env
set +a

docker compose \
  -f deploy/compose/docker-compose.api-runtime.yml \
  --project-name "${QADAM_API_COMPOSE_PROJECT}" \
  --profile ops \
  run --rm migrate
```

Если БД новая и нужен базовый справочный контур:

```bash
cd /srv/qadam-core
set -a
source /etc/qadam/qadam-api-runtime.env
set +a

docker compose \
  -f deploy/compose/docker-compose.api-runtime.yml \
  --project-name "${QADAM_API_COMPOSE_PROJECT}" \
  --profile ops \
  run --rm seed
```

Поднять API runtime:

```bash
cd /srv/qadam-core
set -a
source /etc/qadam/qadam-api-runtime.env
set +a

docker compose \
  -f deploy/compose/docker-compose.api-runtime.yml \
  --project-name "${QADAM_API_COMPOSE_PROJECT}" \
  up -d api
```

Проверка:

```bash
curl -fsS http://127.0.0.1:5002/api/v1/health/live
curl -fsS http://127.0.0.1:5002/api/v1/health/ready
```

### Шаг 5. Синхронизировать OpenAPI и поднять frontend

Сначала синхронизировать frontend с текущим backend artifact:

```bash
cp /srv/qadam-core/apps/api/openapi/openapi.json /srv/qadam-web/openapi/openapi.json
```

Затем собрать web:

```bash
cd /srv/qadam-web
pnpm install --frozen-lockfile
pnpm generate:api-contract
pnpm check-types
pnpm build
pnpm docker:build:web
```

Поднять web runtime:

```bash
cd /srv/qadam-web
QADAM_WEB_IMAGE=qadam-web:git-$(git rev-parse --short=12 HEAD) \
QADAM_WEB_ENV_FILE=/etc/qadam/qadam-web-runtime.env \
QADAM_WEB_PORT=3002 \
QADAM_WEB_BIND_HOST=127.0.0.1 \
QADAM_WEB_COMPOSE_PROJECT=qadam-web-stage \
docker compose \
  -f deploy/compose/docker-compose.web-runtime.yml \
  --project-name qadam-web-stage \
  up -d web
```

Проверка:

```bash
curl -fsS http://127.0.0.1:3002/api/health
curl -I http://127.0.0.1:3002
```

## 6. Минимальный nginx для одного stage-домена

Идея простая:

- `/api/` уходит на `127.0.0.1:5002`
- `/` уходит на `127.0.0.1:3002`

Минимальный контур:

```nginx
server {
    listen 80;
    server_name stage-qadam.example.com;

    location /api/ {
        proxy_pass http://127.0.0.1:5002;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location / {
        proxy_pass http://127.0.0.1:3002;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
```

После этого уже можно навешивать TLS через `certbot`.

## 7. Smoke checklist после поднятия

### Backend

```bash
curl -fsS http://127.0.0.1:5002/api/v1/health/live
curl -fsS http://127.0.0.1:5002/api/v1/health/ready
curl -I http://127.0.0.1:5002/api/docs
```

### Frontend

```bash
curl -I http://127.0.0.1:3002
curl -fsS http://127.0.0.1:3002/api/health
```

### Через публичный домен

```bash
curl -I https://stage-qadam.example.com
curl -I https://stage-qadam.example.com/api/docs
curl -fsS https://stage-qadam.example.com/api/v1/health/ready
```

### UI-проверка в браузере

Минимально проверить:

- открывается главная страница;
- грузятся CSS и JS чанки;
- работает login/register flow хотя бы до transport-слоя;
- seller/public pages не падают на SSR;
- `/api/docs` доступен и совпадает с ожидаемым backend-контрактом.

## 8. Что уже готово в Git, а что ещё не полностью упаковано

### Уже готово

- `qadam-core`: код, Dockerfile, compose runtime, build/publish/smoke scripts
- `qadam-web`: код, Dockerfile, compose runtime, build/publish/smoke scripts
- OpenAPI artifact и contract workflow
- Prisma migrations и seed baseline
- документация по env и deploy-контуру

### Ещё не полностью упаковано в Git как turnkey bootstrap

- готовые nginx vhost-файлы для нового stage-домена;
- готовые systemd units именно для нового stage-контура `qadam-web`;
- секреты и runtime env;
- dump/данные БД для предметного UI-теста с наполнением;
- roadmap runtime, если нужно тащить и его.

Это не блокирует подъём нового сервера, но означает, что staging всё ещё требует осознанного инфраструктурного шага, а не только `git clone`.

## 9. Канонический вывод

Если задача — быстро поднять отдельный сервер, на котором backend и frontend уже можно проверять вместе в браузере, проект к этому готов.

Самый короткий практический путь сейчас такой:

1. взять оба репозитория из Git;
2. подготовить env и инфраструктурные зависимости;
3. поднять `api` на `127.0.0.1:5002`;
4. поднять `web` на `127.0.0.1:3002`;
5. свести их под один stage-домен через `nginx`.

Для этой задачи текущий Git-контур уже достаточен. Не хватает не кода, а только stage-specific runtime-конфигурации и секретов.
