refactor(api): unify /api contract across frontend, nginx, and backend
Some checks failed
CI / build-and-test (pull_request) Has been cancelled

This commit is contained in:
Anton
2026-04-08 11:59:46 +03:00
parent 9f63b190f1
commit 8eaf006906
17 changed files with 103 additions and 81 deletions

View File

@@ -2,13 +2,10 @@
## 1. Base URL
```
VITE_API_BASE_URL=http://localhost:3001
```
SPA всегда отправляет запросы на относительный префикс `/api` текущего origin.
В коде SPA: `import.meta.env.VITE_API_BASE_URL`.
В Docker-стеке из репозитория образ фронта собирается с **`VITE_API_BASE_URL=/api`**: запросы идут на тот же origin, nginx проксирует `/api` на backend (см. `docker/nginx.frontend.conf`).
- В dev (`npm run dev`): Vite proxy отправляет `/api/*` на `http://localhost:3001/api/*`.
- В Docker/проде: nginx фронта проксирует `/api/*` на backend в той же сети.
## 2. CORS
@@ -22,7 +19,7 @@ CORS_ORIGIN=http://localhost:5173
## 3. Эндпоинты
### `GET /health`
### `GET /api/health`
Liveness-проверка (без обращения к БД).
@@ -34,7 +31,7 @@ Liveness-проверка (без обращения к БД).
---
### `GET /ready`
### `GET /api/ready`
Readiness-проверка (проверяет подключение к БД).
@@ -52,7 +49,7 @@ Readiness-проверка (проверяет подключение к БД).
---
### `GET /races`
### `GET /api/races`
Список забегов, отсортированных по дате.
@@ -70,7 +67,7 @@ Readiness-проверка (проверяет подключение к БД).
**Пример запроса:**
```
GET /races?year=2026&month=5
GET /api/races?year=2026&month=5
```
**Ответ 200:**
@@ -99,7 +96,7 @@ GET /races?year=2026&month=5
---
### `GET /races/:id`
### `GET /api/races/:id`
Одна запись по `id`.
@@ -113,7 +110,7 @@ GET /races?year=2026&month=5
---
### `POST /races`
### `POST /api/races`
Создание забега.
@@ -155,7 +152,7 @@ GET /races?year=2026&month=5
---
### `PATCH /races/:id`
### `PATCH /api/races/:id`
Частичное обновление — передавать **только** изменяемые поля.
@@ -188,7 +185,7 @@ GET /races?year=2026&month=5
---
### `DELETE /races/:id`
### `DELETE /api/races/:id`
Удаление забега.
@@ -220,7 +217,7 @@ GET /races?year=2026&month=5
| `createdAt` | string | — | — | ISO timestamp (read-only) |
| `updatedAt` | string \| null | — | — | ISO timestamp (read-only) |
## 5. Фильтрация списка (`GET /races`)
## 5. Фильтрация списка (`GET /api/races`)
- **`year`** — целое число, фильтрует по `EXTRACT(YEAR FROM race_date)`.
- **`month`** — целое число 112, фильтрует по `EXTRACT(MONTH FROM race_date)`.
@@ -234,7 +231,7 @@ Seed-скрипт (`npm run seed` в `backend/`) выполняет **upsert**
## 7. Поведение при недоступной БД
- `GET /health` — всегда `200` (не проверяет БД).
- `GET /ready` — при недоступной БД: `503 { "error": "database_unavailable", "db": "disconnected" }`. В режиме **`CALENDAR_RUN_MOCK_DB`** (dev/CI без Postgres) readiness возвращает успех без реального подключения — см. `docs/backend.md`.
- `GET /api/health` — всегда `200` (не проверяет БД).
- `GET /api/ready` — при недоступной БД: `503 { "error": "database_unavailable", "db": "disconnected" }`. В режиме **`CALENDAR_RUN_MOCK_DB`** (dev/CI без Postgres) readiness возвращает успех без реального подключения — см. `docs/backend.md`.
- Все остальные маршруты — `503 { "error": "database_unavailable" }`.
- В логах сервера: строка ошибки с контекстом маршрута.

View File

@@ -78,7 +78,7 @@ API слушает порт: **`PORT`** (если задан), иначе **`API
| `API_PORT` | Порт API-сервера | `3001` |
| `CORS_ORIGIN` | Разрешённый origin для CORS | `http://localhost:5173` |
Для локального Vite в корневом `.env.example` также указан **`VITE_API_BASE_URL`** (читает только фронт из `frontend/`). В Docker-стеке базовый URL API задаётся при **сборке** образа фронта (`/api`), не через этот файл.
Фронтенд всегда обращается к API по префиксу `/api` на текущем origin. В локальной разработке этот префикс проксирует Vite (`frontend/vite.config.ts`) на `http://localhost:3001`; в Docker-стеке — nginx фронта проксирует на backend.
**Без mock:** при отсутствии любой из `DB_*` процесс падает при старте: `Missing required environment variable: <NAME>`.
@@ -87,8 +87,8 @@ API слушает порт: **`PORT`** (если задан), иначе **`API
## Поведение при недоступной БД
- **Старт сервера** — проходит успешно (env валидирован, Express слушает порт).
- **`GET /health`** — всегда `200 { "status": "ok" }` (liveness, без обращения к БД).
- **`GET /ready`** — при обычном режиме пробует подключиться к БД; `200` если ОК, `503 { "error": "database_unavailable", ... }` если нет. В режиме **`CALENDAR_RUN_MOCK_DB`** readiness считается успешным без реального подключения (удобно для CI/smoke API).
- **`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" }`.
## Структура каталога
@@ -108,8 +108,8 @@ backend/
│ ├── mappers/
│ │ └── race.ts # snake_case ↔ camelCase
│ └── routes/
│ ├── health.ts # /health, /ready
│ └── races.ts # CRUD /races
│ ├── health.ts # /api/health, /api/ready, /api/meta
│ └── races.ts # CRUD /api/races
├── package.json
└── tsconfig.json
```