# Модуль m02-rest-api — план разработки > План по алгоритму d-dev (`std1\_rules\d\d-dev.md`), адаптация к > REST-модулю: вместо psql-функций — эндпоинты и обработчики; статусная > модель шагов та же (`⬜ → 🔄 → ✅`), шлюзы «**Пользователь!**» — > d-dev-4. Требования — [module_reqs.md](module_reqs.md). | Шаг d-dev | Состав | Статус | |---|---|---| | 0. Персистентная подготовка | module_reqs.md, readme.md, SKILL.md | ✅ | | 1. Список единиц к реализации | эндпоинты + компоненты (middleware, sync-обработчик, DTO) со статусами в разд. «Список единиц» ниже | ✅ | | 1.3. Утверждение списка | — | **Пользователь!** ✅ (2026-10-17) | | 2. Спецификации единиц | `api_specs\` модуля — контракт каждой единицы (запрос/ответ/ошибки/тесты) — 6 файлов (DTO; конфиг; middleware; sync; чтение workouts; programs/active) | ✅ | | 2.4. Утверждение спецификаций | — | **Пользователь!** ✅ (2026-10-17) | | 3. Код и тесты | `3-app\2-cli\Server.WatchBody.Web` + `Server.WatchBody.Web.Tests` (интеграционные, docker `watchbody-pg`): тесты 25/25 PASS (Core 55/55 на момент закрытия модуля; после З-35 — 56/56, после З-41 — Web 81/81), сборка 0 ошибок | ✅ | | 3.4. Утверждение реализации | — | **Пользователь!** ✅ (2026-10-18, с переводом маршрутов на fluent Kit.Helpers.Routes) | | 4. Завершение | сборка и тесты зелёные; критерии приёмки module_reqs разд. 7 проверены | ✅ (2026-10-18: сборка 0 ошибок, тесты Web 25/25 + Core 55/55 PASS; после З-35 — Core 56/56) | **Модуль завершён** (2026-10-18). Следующий по плану этапа 7 — m03-program-store. ## Список единиц (шаг 1) | # | Единица | Тип | Статус | |---|---|---|---| | 1 | Конфигурация и стартовая валидация (`Api.*`, `Db.*` — tech-req 4.2) + сопоставление атлетов конфига с `src.athlete` (upsert по хэшу) | компонент | REQ | | 2 | Middleware `X-Api-Key` → `athlete_id` (401 при отсутствии/чужом/заблокированном ключе) | компонент | REQ | | 3 | `POST /api/v1/sync` — обработчик пакета (атомарность, идемпотентность, маппинг 7 сущностей, 409/400) | эндпоинт | REQ | | 4 | `GET /api/v1/workouts` — список с пагинацией | эндпоинт | REQ | | 5 | `GET /api/v1/workouts/{id}` — карточка | эндпоинт | REQ | | 6 | `GET /api/v1/programs/active` — активная версия программы | эндпоинт | REQ | | 7 | DTO пакета sync и ответов (конверт, `accepted`, ошибки) | компонент | REQ | Примечания: - Доступ к БД — только репозитории m01 (`Server.WatchBody.Core`); прямой SQL в Web-проекте запрещён (module_reqs разд. 1). - Прогон интеграционных тестов — PostgreSQL 17 в docker `watchbody-pg` (порт 5433, БД `watchbody`), как в m01. - Регистрация маршрутов — fluent `Kit.Helpers.Routes` (`Config\RouteConfig.cs`, MVC-контроллеры в `Controllers\`, `UseMvc` с `EnableEndpointRouting = false`; решение владельца 2026-10-18, паттерн — Kit.Task.WebAp\Task.WebApp). Admin REST API (`/api/admin/*`) для консоли — в границах m08 (UI — отдельное Flutter Web-приложение, решение владельца 2026-10-17). - Атомарность пакета sync — `TransactionScope` (Npgsql подключает соединения Kit.Helpers к ambient-транзакции); все чтения — до открытия транзакции (select-функции Kit открывают собственную). Вскрытая errata m01: jsonb-параметры функций приняты как `text` (каста в теле); `program_version_insert` дополнен идемпотентностью по `p_id` (🛡) — подробнее в readme m01. - Интеграционные тесты запускают приложение in-process (`WebAppStartup.Build`, Kestrel на `127.0.0.1:0`) против docker `watchbody-pg`; данные — фиксированные uuid/ключи (идемпотентность повторных прогонов), атлеты тестов создаются bootstrap'ом конфига. ## Errata (после закрытия модуля) - **З-41(а)** (2026-10-18, ревью этапа 7 волна 2): sync терял `is_active` у `exercise` — `exercise_insert`/`exercise_update` параметр не принимают (дизайн m01, З-34), Delete из sync не вызывался: серверный контур Ф-4.2 был недостижим (фильтр ограничений m05 строится на флаге). Исправлено: `SyncService` при `is_active=false` вызывает `exercises.Delete` (идемпотентно, GUID — в `accepted`); интеграционный тест `Sync_ExerciseInactive_LogicalDelete` (Web.Tests 81/81). Семантика — module_reqs / spec 06 / tech-req 2.2.