162 lines
12 KiB
Markdown
162 lines
12 KiB
Markdown
# Инструкция агенту: реализация бэкенда по [PLAN.md](../PLAN.md)
|
||
|
||
Документ для ИИ-агента или разработчика, который создаёт **backend** монорепозитория «календарь забегов». Продуктовые цели и модель данных — в корневом **PLAN.md**; здесь — порядок работ, ограничения и **обязательные итоговые артефакты для фронтенда**.
|
||
|
||
---
|
||
|
||
## 0. Ограничение: нет возможности проверить подключение к БД
|
||
|
||
1. **Всё равно реализовать полноценный бэкенд «как для прод»**: миграции SQL, пул подключений `pg`, переменные `DB_*`, `docker-compose.yml` с PostgreSQL в корне репозитория.
|
||
2. **Не блокировать работу отсутствием живой БД у исполнителя:**
|
||
- код миграций и seed должен быть **валидным и согласованным** с PLAN;
|
||
- при старте API при невозможности подключиться к БД — **ясное сообщение в лог** и **корректный HTTP-ответ** на зависящих от БД маршрутах (например 503 с телом `{"error":"database_unavailable",...}`) **или** падение процесса на старте с понятной ошибкой (выбрать одну стратегию и описать её в `docs/backend.md`).
|
||
3. **Не выдумывать обход БД** (in-memory «режим без Postgres»), если это не согласовано отдельно — фронт и план рассчитаны на PostgreSQL.
|
||
4. Автотесты, требующие Docker/Postgres, помечать как **опциональные** или давать инструкцию «как прогнать локально», не считая провал из-за отсутствия БД у агента блокером для merge кода.
|
||
|
||
---
|
||
|
||
## 1. Ветка и расположение в репо
|
||
|
||
- Если репозиторий под git: создать ветку `feature/backend-api` (или аналог по соглашению команды).
|
||
- Каталог **`backend/`** в корне проекта рядом с будущим `frontend/`.
|
||
- Корневой **`docker-compose.yml`** — сервис `postgres` (порт, пользователь, БД, пароль — согласовать с `.env.example`).
|
||
|
||
---
|
||
|
||
## 2. Порядок реализации (обязательный)
|
||
|
||
### Шаг A. Каркас
|
||
|
||
- Node **LTS**, **TypeScript**, **`backend/package.json`**.
|
||
- Фреймворк: **Fastify** или **Express** (выбрать один, не смешивать).
|
||
- Загрузка env: `dotenv` или встроенные средства; **валидация** наличия `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD` при старте (или при первом запросе к БД — но тогда задокументировать).
|
||
- Сервер слушает порт из **`PORT`** или **`API_PORT`** (значение по умолчанию, напр. `3001`, указать в `.env.example`).
|
||
|
||
### Шаг B. CORS
|
||
|
||
- Читать **`CORS_ORIGIN`** (например `http://localhost:5173` для Vite в dev). В prod — origin фронта.
|
||
- Разрешить методы и заголовки, нужные для `GET/POST/PATCH` + `Content-Type: application/json`.
|
||
|
||
### Шаг C. Миграции
|
||
|
||
- Каталог миграций, напр. `backend/migrations/` с нумерованными SQL-файлами **или** один миграционный runner (node-pg-migrate, graphile-migrate, собственный скрипт — на выбор, зафиксировать в `docs/backend.md`).
|
||
- Первая миграция: таблица **`races`** со столбцами, соответствующими PLAN (см. раздел 3 ниже).
|
||
- Команда **`npm run db:migrate`** (или эквивалент в `backend/`) — идемпотентное накатывание на чистую БД.
|
||
|
||
### Шаг D. Доступ к данным
|
||
|
||
- Клиент **`pg`**: `Pool` с параметрами из `DB_*`.
|
||
- Слой репозитория или прямые запросы в обработчиках — на усмотрение, без лишних абстракций сверх задачи.
|
||
|
||
### Шаг E. HTTP API
|
||
|
||
Реализовать минимум:
|
||
|
||
| Метод | Путь | Назначение |
|
||
|--------|------|------------|
|
||
| `GET` | `/health` | Liveness: процесс жив; **не обязан** проверять БД (или опционально — задокументировать). |
|
||
| `GET` | `/ready` (опционально) | Readiness: проверка соединения с БД — полезно для оркестраторов. |
|
||
| `GET` | `/races` | Список забегов; **query**: `year`, `month` (1–12) — фильтрация для экранов календаря; без параметров — все строки или разумный лимит + документация пагинации если добавите позже. |
|
||
| `GET` | `/races/:id` | Одна запись по `id`. |
|
||
| `POST` | `/races` | Создание; тело JSON в **camelCase** как в PLAN. |
|
||
| `PATCH` | `/races/:id` | Частичное обновление; только переданные поля. |
|
||
| `DELETE` | `/races/:id` | Опционально по PLAN; если не нужен фронту — можно не делать, но тогда явно написать в документации «удаление не поддерживается». |
|
||
|
||
**Ошибки:**
|
||
|
||
- 400 — валидация тела/параметров.
|
||
- 404 — нет `id`.
|
||
- 409 — конфликт уникального `id` при POST (если клиент прислал уже существующий).
|
||
- 503 или 500 — недоступна БД (согласовать с разделом 0).
|
||
|
||
Формат ошибки: JSON, единообразно, напр. `{"error":"validation_error","details":[...]}`.
|
||
|
||
### Шаг F. Seed (разовый скрипт)
|
||
|
||
- Команда **`npm run seed`** в `backend/` (или корне монорепо с `workspace` — единообразно).
|
||
- Читает **`import/races_2026_calendar.csv`** (путь от корня репо); парсинг с учётом кавычек в поле названия.
|
||
- Генерирует **`id`** стабильно: например `{date}-{slug-from-title}`; при коллизии — суффикс или upsert по `id`.
|
||
- **`INSERT ... ON CONFLICT (id) DO UPDATE`** (upsert) — удобно для повторного запуска seed.
|
||
- Seed **не** вызывается из HTTP handlers.
|
||
|
||
### Шаг G. Корневой `.env.example`
|
||
|
||
- Все переменные: `DB_*`, `PORT`/`API_PORT`, `CORS_ORIGIN`.
|
||
- **Без** реальных паролей; комментарии к каждой переменной.
|
||
|
||
---
|
||
|
||
## 3. Соответствие полей PLAN ↔ SQL ↔ JSON API
|
||
|
||
**В JSON API (запрос/ответ)** — **camelCase**, как в PLAN:
|
||
|
||
`id`, `date`, `title`, `distanceKm`, `status`, `officialUrl`, `startTime`, `clusterSchedule`, `bibPickup`, `bibNumber`, `finishTime`, `notes`.
|
||
|
||
**В PostgreSQL** — **snake_case**, например:
|
||
|
||
| SQL column | Тип (рекомендация) |
|
||
|------------|---------------------|
|
||
| `id` | `TEXT` PRIMARY KEY |
|
||
| `race_date` | `DATE` |
|
||
| `title` | `TEXT` |
|
||
| `distance_km` | `NUMERIC(6,3)` |
|
||
| `status` | `TEXT` CHECK (опционально) |
|
||
| `official_url` | `TEXT` |
|
||
| `start_time` | `TEXT` |
|
||
| `cluster_schedule` | `TEXT` |
|
||
| `bib_pickup` | `TEXT` |
|
||
| `bib_number` | `TEXT` |
|
||
| `finish_time` | `TEXT` |
|
||
| `notes` | `TEXT` |
|
||
| `created_at` | `TIMESTAMPTZ` DEFAULT now() |
|
||
| `updated_at` | `TIMESTAMPTZ` |
|
||
|
||
Маппинг **строго** в одном модуле (например `backend/src/mappers/race.ts`), чтобы фронт всегда видел camelCase.
|
||
|
||
**Типы `date`:** в API строка `YYYY-MM-DD`. **`distanceKm`:** число. **`finishTime`:** строка времени как в PLAN; бэкенд **не обязан** парсить для бизнес-логики (PR считает фронт), но может валидировать формат по желанию.
|
||
|
||
---
|
||
|
||
## 4. Обязательный итог для упрощения фронтенда
|
||
|
||
После того как код бэкенда готов, агент **обязан** добавить в репозиторий документ:
|
||
|
||
### Файл: `docs/backend-api-for-frontend.md`
|
||
|
||
В нём **кратко и без пробелов в фактах**:
|
||
|
||
1. **Base URL** — что подставлять во фронт (`VITE_API_BASE_URL`), пример для dev.
|
||
2. **CORS** — какой `CORS_ORIGIN` ожидается в dev.
|
||
3. **Таблица эндпоинтов** — метод, путь, query, тело запроса (пример JSON), пример успешного ответа, коды ошибок.
|
||
4. **Модель `Race`** — перечень полей в **camelCase** с типами и обязательностью для POST vs PATCH.
|
||
5. **Фильтр списка** — как именно работают `year` и `month` на `GET /races` (включая границы: пустой месяц, только год и т.д.).
|
||
6. **Идемпотентность seed** — одна фраза: upsert по `id`, откуда берётся CSV.
|
||
7. **Поведение при недоступной БД** — что возвращает API / что в логах (как в реализации).
|
||
|
||
Дополнительно можно дублировать суть в **`docs/backend.md`** (общая эксплуатация: docker, migrate, seed, запуск), но **`backend-api-for-frontend.md`** — главная «шпаргалка» для разработчика SPA.
|
||
|
||
---
|
||
|
||
## 5. Критерии готовности (чеклист агента)
|
||
|
||
- [ ] `docker-compose.yml` поднимает Postgres с параметрами, совместимыми с `.env.example`.
|
||
- [ ] Миграция создаёт `races`; есть команда миграции.
|
||
- [ ] Реализованы `GET /races`, `GET /races/:id`, `POST /races`, `PATCH /races/:id` согласно PLAN.
|
||
- [ ] Реализован seed из `import/races_2026_calendar.csv`.
|
||
- [ ] `GET /health` (и при наличии `/ready` — описано).
|
||
- [ ] Корневой `.env.example` обновлён.
|
||
- [ ] Написан **`docs/backend-api-for-frontend.md`** (раздел 4).
|
||
- [ ] `docs/backend.md` содержит команды: установка зависимостей, migrate, seed, `npm run dev` для API.
|
||
|
||
---
|
||
|
||
## 6. Не входит в объём бэкенда (напоминание)
|
||
|
||
- Авторизация, пользователи, сессии.
|
||
- Парсинг сайтов организаторов.
|
||
- Отдача статики фронта с того же процесса (фронт — отдельно Vite/build).
|
||
|
||
---
|
||
|
||
*Конец инструкции. Источник требований к продукту — всегда [PLAN.md](../PLAN.md).*
|