chore: drop agent/plan docs, unify .env for Docker stack
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
- Remove PLAN/agent instruction files; single root .env.example for DB + API - Stack compose uses env_file .env; delete stack env example duplicate - Refresh README, backend docs, API doc; trim gitignore/dockerignore Made-with: Cursor
This commit is contained in:
@@ -1,162 +0,0 @@
|
||||
# Инструкция агенту: реализация бэкенда по [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. **Режим без Postgres для dev/CI** согласован с [PLAN.md](../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 не используется.
|
||||
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` (`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`
|
||||
|
||||
В нём **кратко и без пробелов в фактах**:
|
||||
|
||||
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).*
|
||||
@@ -1,77 +0,0 @@
|
||||
# Инструкция агенту: устранение рассинхронизации backend с планом/контрактом
|
||||
|
||||
Документ описывает, как выполнить план исправлений **только через изменения кода** (без правок существующей документации в `docs/`).
|
||||
|
||||
## 1) Ветка и границы задачи
|
||||
|
||||
- Создать отдельную ветку по best practice, например: `fix/backend-api-validation-and-runtime-sync`.
|
||||
- Не менять существующие файлы документации в `docs/` как способ "починить" замечания.
|
||||
- Исправления вносятся в runtime-код и обязательные артефакты репозитория.
|
||||
|
||||
## 2) Обязательные изменения в коде
|
||||
|
||||
### A. Строгая валидация `GET /races`
|
||||
|
||||
Файл: `backend/src/routes/races.ts`
|
||||
|
||||
- Добавить явную проверку `year`:
|
||||
- целое число;
|
||||
- при невалидном значении вернуть `400`:
|
||||
- `{"error":"validation_error","details":[...]}`
|
||||
- Добавить явную проверку `month`:
|
||||
- целое число в диапазоне `1..12`;
|
||||
- при невалидном значении вернуть `400` в том же формате.
|
||||
- Исключить передачу `NaN`/некорректных значений в SQL-параметры.
|
||||
|
||||
### B. Разделение ошибок валидации и ошибок БД
|
||||
|
||||
Файл: `backend/src/routes/races.ts`
|
||||
|
||||
- `400` использовать только для ошибок входа (query/body/params).
|
||||
- `503 {"error":"database_unavailable"}` использовать только для технической недоступности БД.
|
||||
- Сохранить единый JSON-формат ошибок во всех CRUD-маршрутах.
|
||||
|
||||
### C. Выравнивание конфигурации порта
|
||||
|
||||
Файл: `backend/src/config.ts`
|
||||
|
||||
- Поддержать оба env-подхода:
|
||||
- приоритет `PORT`,
|
||||
- затем `API_PORT`,
|
||||
- затем fallback `3001`.
|
||||
|
||||
### D. Обязательный root-артефакт
|
||||
|
||||
Файл: `README.md` (в корне)
|
||||
|
||||
- Создать базовый `README.md` с:
|
||||
- кратким описанием проекта,
|
||||
- минимальным quick start,
|
||||
- ссылками на текущие документы backend/API.
|
||||
|
||||
## 3) Допустимая реорганизация кода
|
||||
|
||||
- Можно добавить небольшие локальные helper-функции в `backend/src/routes/races.ts`.
|
||||
- При необходимости можно вынести общие mapper/validator-хелперы в `backend/src/mappers/race.ts`, если это уменьшает дублирование.
|
||||
- Не усложнять архитектуру: только то, что нужно для контракта и устойчивого поведения API.
|
||||
|
||||
## 4) Проверка результата
|
||||
|
||||
Минимум выполнить:
|
||||
|
||||
1. `npm run build` в `backend/` (типизация/сборка).
|
||||
2. Проверка диагностики/линтов по измененным backend-файлам.
|
||||
3. Smoke-сценарии API:
|
||||
- `GET /health` -> `200`,
|
||||
- `GET /ready` -> `200` при доступной БД или `503` при недоступной,
|
||||
- `GET /races?year=bad` -> `400`,
|
||||
- `GET /races?month=13` -> `400`,
|
||||
- `GET /races?year=2026&month=5` -> корректный `200` и данные/пустой массив.
|
||||
|
||||
## 5) Критерии готовности (Definition of Done)
|
||||
|
||||
- Контракт валидации `GET /races` соблюден в runtime.
|
||||
- Валидационные ошибки не маскируются под `database_unavailable`.
|
||||
- Конфиг порта поддерживает `PORT` и `API_PORT` с правильным приоритетом.
|
||||
- В репозитории есть корневой `README.md`.
|
||||
- Никакие существующие документы в `docs/` не менялись для "закрытия" замечаний.
|
||||
@@ -8,6 +8,8 @@ VITE_API_BASE_URL=http://localhost:3001
|
||||
|
||||
В коде SPA: `import.meta.env.VITE_API_BASE_URL`.
|
||||
|
||||
В Docker-стеке из репозитория образ фронта собирается с **`VITE_API_BASE_URL=/api`**: запросы идут на тот же origin, nginx проксирует `/api` на backend (см. `docker/nginx.frontend.conf`).
|
||||
|
||||
## 2. CORS
|
||||
|
||||
В dev-режиме бэкенд ожидает переменную:
|
||||
|
||||
@@ -78,6 +78,8 @@ 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`), не через этот файл.
|
||||
|
||||
**Без mock:** при отсутствии любой из `DB_*` процесс падает при старте: `Missing required environment variable: <NAME>`.
|
||||
|
||||
**С `CALENDAR_RUN_MOCK_DB=1`:** переменные `DB_*` не обязательны; реальный пул не поднимается. **Не использовать** mock для `npm run db:migrate` и `npm run seed` — нужен настоящий Postgres и корректные `DB_*`.
|
||||
@@ -111,3 +113,9 @@ backend/
|
||||
├── package.json
|
||||
└── tsconfig.json
|
||||
```
|
||||
|
||||
## Docker: стек backend + frontend
|
||||
|
||||
Файл [`docker-compose.stack.yml`](../docker-compose.stack.yml) поднимает API и nginx со статикой SPA в **внешней** сети Docker (рядом с уже запущенным Postgres). Переменные — в **корневом** `.env` (шаблон [`.env.example`](../.env.example)): как минимум `DB_*`, `CORS_ORIGIN` (для выдачи фронта на порту 3033 задайте `http://localhost:3033`). Перед первым `up` файл `.env` должен существовать.
|
||||
|
||||
Порядок после старта контейнеров: `node dist/migrate.js` и `node dist/seed.js` внутри контейнера `backend` (см. комментарии в compose-файле).
|
||||
|
||||
Reference in New Issue
Block a user