- Add PLAN.md and sync backend docs, .env.example, API doc (404 details) - Document mock DB and PORT/API_PORT in docs/backend.md; README monorepo + frontend/.env.example - Migration 002: finish_place column, status registered; mapper and mock DB updated - Frontend: registered status, finishPlace, calendar year/month filters, pace sparkline - Extract createApp for tests; supertest + tsx; GitHub Actions CI Made-with: Cursor
12 KiB
Инструкция агенту: реализация бэкенда по PLAN.md
Документ для ИИ-агента или разработчика, который создаёт backend монорепозитория «календарь забегов». Продуктовые цели и модель данных — в корневом PLAN.md; здесь — порядок работ, ограничения и обязательные итоговые артефакты для фронтенда.
0. Ограничение: нет возможности проверить подключение к БД
- Всё равно реализовать полноценный бэкенд «как для прод»: миграции SQL, пул подключений
pg, переменныеDB_*,docker-compose.ymlс PostgreSQL в корне репозитория. - Не блокировать работу отсутствием живой БД у исполнителя:
- код миграций и seed должен быть валидным и согласованным с PLAN;
- при старте API при невозможности подключиться к БД — ясное сообщение в лог и корректный HTTP-ответ на зависящих от БД маршрутах (например 503 с телом
{"error":"database_unavailable",...}) или падение процесса на старте с понятной ошибкой (выбрать одну стратегию и описать её вdocs/backend.md).
- Режим без Postgres для dev/CI согласован с PLAN.md и
docs/backend.md: переменнаяCALENDAR_RUN_MOCK_DB=1(илиtrue) включает in-memory заглушку пула только для HTTP-слоя. Дляnpm run db:migrateиnpm run seedнужен реальный PostgreSQL иDB_*; mock для миграций/seed не используется. - Автотесты, требующие 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 (planned | registered | completed), officialUrl, startTime, clusterSchedule, bibPickup, bibNumber, finishTime, finishPlace, 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 |
finish_place |
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
В нём кратко и без пробелов в фактах:
- Base URL — что подставлять во фронт (
VITE_API_BASE_URL), пример для dev. - CORS — какой
CORS_ORIGINожидается в dev. - Таблица эндпоинтов — метод, путь, query, тело запроса (пример JSON), пример успешного ответа, коды ошибок.
- Модель
Race— перечень полей в camelCase с типами и обязательностью для POST vs PATCH. - Фильтр списка — как именно работают
yearиmonthнаGET /races(включая границы: пустой месяц, только год и т.д.). - Идемпотентность seed — одна фраза: upsert по
id, откуда берётся CSV. - Поведение при недоступной БД — что возвращает 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.