# Спецификация: `GET /api/v1/workouts` и `GET /api/v1/workouts/{id}` (единицы 4–5) ## `GET /api/v1/workouts` — список с пагинацией Запрос: `?limit=` (1–100, умолчание 20), `?offset=` (≥ 0, умолчание 0); вне диапазона — `400`. Ответ `200`: ```json { "items": [ { "workout_id": "uuid", "started_at": "...", "ended_at": "...", "status": "finished", "session_kind": "normal", "avg_hr": 132, "sets": [ { "set_id": "uuid", "exercise_id": "uuid", "seq": 1, "weight_kg": 60.0, "reps": 10, "rpe": 8, "knee_pain": null } ] } ], "total": 42 } ``` Реализация — `WorkoutRepository.Select` (`workout_select`: карточки + подходы агрегатом); `total` — COUNT по фильтру (без пагинации). Примечание (З-40): пагинация — в памяти (выборка атлета целиком, `limit`/`offset` режут результат) — известное ограничение v1. Тесты: 1) список только этого атлета (🛡 — второй атлет не виден); 2) `limit`/`offset` режут выборку корректно; 3) `limit = 0` / `limit = 101` → 400. ## `GET /api/v1/workouts/{id}` — карточка Ответ `200` — полная карточка (поля карточки + `sets[]` + `command_log[]` с `t_offset_s`, `recognized_text`, `semantics`, `accepted`). | Код | Когда | |---|---| | 404 | тренировка не найдена **или** принадлежит другому атлету (🛡 различие не выдаётся) | | 400 | `{id}` — не UUID | Реализация — `WorkoutRepository.Get` (`workout_get`: карточка + sets + command_log) с проверкой `athlete_id`. Тесты: 1) своя тренировка → 200 с sets и command_log; 2) чужая тренировка → 404; 3) не-UUID id → 400.