feat(backend): implement REST API for races calendar
Express + TypeScript backend with PostgreSQL: CRUD endpoints for /races (GET list with year/month filters, GET by id, POST, PATCH, DELETE), health/readiness probes, SQL migration runner, seed script with upsert from CSV, camelCase/snake_case mapper, CORS, env validation, docker-compose, and API docs for frontend. Made-with: Cursor
This commit is contained in:
107
docs/backend.md
Normal file
107
docs/backend.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# 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 слушает порт из `API_PORT` (по умолчанию `3001`).
|
||||
|
||||
## Переменные окружения
|
||||
|
||||
| Переменная | Описание | По умолчанию |
|
||||
|---|---|---|
|
||||
| `DB_HOST` | Хост PostgreSQL | — (обязательна) |
|
||||
| `DB_PORT` | Порт PostgreSQL | — (обязательна) |
|
||||
| `DB_NAME` | Имя базы данных | — (обязательна) |
|
||||
| `DB_USER` | Пользователь БД | — (обязательна) |
|
||||
| `DB_PASSWORD` | Пароль БД | — (обязательна) |
|
||||
| `API_PORT` | Порт API-сервера | `3001` |
|
||||
| `CORS_ORIGIN` | Разрешённый origin для CORS | `http://localhost:5173` |
|
||||
|
||||
При отсутствии любой из `DB_*` процесс падает при старте с сообщением `Missing required environment variable: <NAME>`.
|
||||
|
||||
## Поведение при недоступной БД
|
||||
|
||||
- **Старт сервера** — проходит успешно (env валидирован, Express слушает порт).
|
||||
- **`GET /health`** — всегда `200 { "status": "ok" }` (liveness, без обращения к БД).
|
||||
- **`GET /ready`** — пробует подключиться к БД; возвращает `200` если ОК, `503 { "error": "database_unavailable" }` если нет.
|
||||
- **Все остальные маршруты** при ошибке БД возвращают `503 { "error": "database_unavailable" }`.
|
||||
|
||||
## Структура каталога
|
||||
|
||||
```
|
||||
backend/
|
||||
├── migrations/
|
||||
│ └── 001_create_races.sql
|
||||
├── src/
|
||||
│ ├── config.ts # загрузка и валидация env
|
||||
│ ├── db.ts # pg Pool
|
||||
│ ├── index.ts # точка входа Express
|
||||
│ ├── migrate.ts # раннер миграций
|
||||
│ ├── seed.ts # разовый импорт CSV
|
||||
│ ├── mappers/
|
||||
│ │ └── race.ts # snake_case ↔ camelCase
|
||||
│ └── routes/
|
||||
│ ├── health.ts # /health, /ready
|
||||
│ └── races.ts # CRUD /races
|
||||
├── package.json
|
||||
└── tsconfig.json
|
||||
```
|
||||
Reference in New Issue
Block a user