Files
runners-calendar/docs/agent-backend-instruction.md
2026-04-01 13:42:37 +03:00

162 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Инструкция агенту: реализация бэкенда по [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` (112) — фильтрация для экранов календаря; без параметров — все строки или разумный лимит + документация пагинации если добавите позже. |
| `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).*