# Backend — эксплуатация

## Стек

- **Node.js LTS** + TypeScript
- **Express** (HTTP-фреймворк)
- **pg** (PostgreSQL клиент)
- **csv-parse** (парсинг CSV для seed)

## Быстрый старт

### 1. Поднять PostgreSQL

```bash
# из корня проекта
docker-compose up -d
```

Параметры подключения берутся из `.env` (см. `.env.example` в корне).

### 2. Установить зависимости

```bash
cd backend
npm install
```

### 3. Создать `.env`

Скопировать `.env.example` из корня проекта и при необходимости отредактировать:

```bash
cp ../.env.example ../.env
```

### 4. Миграции

```bash
npm run db:migrate
```

Миграционный раннер — собственный скрипт `src/migrate.ts`:
- хранит историю применённых файлов в таблице `_migrations`;
- идемпотентный — повторный запуск не применяет уже выполненные миграции;
- файлы миграций: `backend/migrations/*.sql`, применяются в алфавитном порядке.

### 5. Seed (начальный набор данных)

```bash
npm run seed
```

- Читает `import/races_2026_calendar.csv` из корня репо.
- Генерирует стабильный `id` в формате `{date}-{slug}`.
- Выполняет **upsert** (`INSERT … ON CONFLICT DO UPDATE`) — безопасно для повторного запуска.

### 6. Запуск API

```bash
npm run dev      # dev-режим через ts-node
npm run build    # компиляция в dist/
npm start        # запуск из dist/
```

API слушает порт: **`PORT`** (если задан), иначе **`API_PORT`**, иначе **`3001`**.

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

| Переменная | Описание | По умолчанию |
|---|---|---|
| `DB_HOST` | Хост PostgreSQL | — (обязательна без mock, см. ниже) |
| `DB_PORT` | Порт PostgreSQL | — (обязательна без mock) |
| `DB_NAME` | Имя базы данных | — (обязательна без mock) |
| `DB_USER` | Пользователь БД | — (обязательна без mock) |
| `DB_PASSWORD` | Пароль БД | — (обязательна без mock) |
| `CALENDAR_RUN_MOCK_DB` | `1` или `true` — режим без PostgreSQL для HTTP API (dev/CI) | выкл. |
| `PORT` | Порт API (приоритетнее `API_PORT`) | — |
| `API_PORT` | Порт API-сервера | `3001` |
| `CORS_ORIGIN` | Разрешённый origin для CORS | `http://localhost:5173` |

Фронтенд всегда обращается к API по префиксу `/api` на текущем origin. В локальной разработке этот префикс проксирует Vite (`frontend/vite.config.ts`) на `http://localhost:3001`; в Docker-стеке — nginx фронта проксирует на `runners-calendar-backend:3000`.

**Без mock:** при отсутствии любой из `DB_*` процесс падает при старте: `Missing required environment variable: <NAME>`.

**С `CALENDAR_RUN_MOCK_DB=1`:** переменные `DB_*` не обязательны; реальный пул не поднимается. **Не использовать** mock для `npm run db:migrate` и `npm run seed` — нужен настоящий Postgres и корректные `DB_*`.

## Поведение при недоступной БД

- **Старт сервера** — проходит успешно (env валидирован, Express слушает порт).
- **`GET /api/health`** — всегда `200 { "status": "ok" }` (liveness, без обращения к БД).
- **`GET /api/ready`** — при обычном режиме пробует подключиться к БД; `200` если ОК, `503 { "error": "database_unavailable", ... }` если нет. В режиме **`CALENDAR_RUN_MOCK_DB`** readiness считается успешным без реального подключения (удобно для CI/smoke API).
- **Все остальные маршруты** при ошибке БД возвращают `503 { "error": "database_unavailable" }`.

## Структура каталога

```
backend/
├── migrations/
│   ├── 001_create_races.sql
│   └── 002_finish_place_and_registered_status.sql
├── src/
│   ├── app.ts             # фабрика Express (тесты)
│   ├── config.ts          # загрузка и валидация env
│   ├── db.ts              # pg Pool или mock
│   ├── index.ts           # запуск сервера
│   ├── migrate.ts         # раннер миграций
│   ├── seed.ts            # разовый импорт CSV
│   ├── mappers/
│   │   └── race.ts        # snake_case ↔ camelCase
│   └── routes/
│       ├── health.ts      # /api/health, /api/ready, /api/meta
│       └── races.ts       # CRUD /api/races
├── package.json
└── tsconfig.json
```

## Docker: стек backend + frontend

Файл [`docker-compose.stack.yml`](../docker-compose.stack.yml) поднимает API и nginx со статикой SPA в **внешней** сети Docker (рядом с уже запущенным Postgres). Переменные — в **корневом** `.env` (шаблон [`.env.example`](../.env.example)): как минимум `DB_*`, `CORS_ORIGIN` (для выдачи фронта на порту 3033 задайте `http://localhost:3033`). Перед первым `up` файл `.env` должен существовать.

Порядок после старта контейнеров: `node dist/migrate.js` и `node dist/seed.js` внутри сервиса `runners-calendar-backend` (см. комментарии в compose-файле).
