Files
qa_test_app/DOC/СПРИНТЫ.md
Aleksey Razorvin fc684e7c7d Спринт 5: Трекер результатов
- Миграция 005: user_id в test_attempts (дефолт 1 = Гость)
- GET /api/attempts с фильтрами по тесту, дате и пагинацией
- Страница /tracker: таблица попыток, фильтры, пагинация
- Ссылка «Трекер» в шапке приложения

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 15:26:40 +05:00

236 lines
16 KiB
Markdown
Raw Permalink 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.
# План спринтов
**Дата:** 2026-03-21
**Статус:** Согласовано
---
## Принцип
Каждый спринт — это готовое работающее приложение (frontend + backend), которое можно запустить локально командой `docker compose up` и протестировать вручную в браузере.
---
## Спринт 1 — Инфраструктура + Создание тестов ✅
**Результат:** Поднят весь стек, можно зайти на страницу и создать тест.
**Статус:** Завершён и протестирован вручную в браузере.
### Инфраструктура
- [x] Структура репозитория: `backend/`, `frontend/`, `nginx/`, `docker-compose.yml`
- [x] `docker-compose.yml`: сервисы `db`, `backend`, `frontend`, `nginx`
- [x] PostgreSQL: контейнер, volume для данных
- [x] FastAPI: контейнер, `GET /api/health``{"status": "ok"}`
- [x] Alembic: инициализирован, первая миграция (`001_init`)
- [x] React + Vite: контейнер, базовая страница открывается в браузере
- [x] Nginx: `/` → React SPA, `/api/` → FastAPI
### Создание тестов (без авторизации)
- [x] Модели БД: `Test`, `Question`, `Answer`
- [x] API: `POST /api/tests` — создать тест с вопросами и ответами
- [x] API: `GET /api/tests` — список тестов
- [x] API: `GET /api/tests/{id}` — детали теста
- [x] Фронт: страница создания теста (название, вопросы, варианты, настройки)
- [x] Фронт: список тестов
- [x] Фронт: страница просмотра теста
**Настройки теста:** порог зачёта (%), таймер (опционально), разрешить возврат к предыдущему вопросу
### Баги, найденные и исправленные при тестировании
- [x] `permission denied` на `entrypoint.sh` — volume mount перекрывал `chmod +x` из Dockerfile → исправлено: `CMD ["bash", "entrypoint.sh"]`
- [x] `No module named 'app'` в Alembic — Python не видел `/app` → исправлено: `ENV PYTHONPATH=/app` в Dockerfile
- [x] `host not found in upstream "backend"` в nginx — nginx резолвил хост при старте, до поднятия backend → исправлено: Docker DNS resolver + `set $backend`
- [x] `http://localhost/api/docs` → 404 — FastAPI отдавал docs по `/docs`, а не `/api/docs` → исправлено: явные `docs_url`, `redoc_url`, `openapi_url` в FastAPI
---
## Спринт 2 — Прохождение теста ✅
**Результат:** Можно выбрать тест из списка и пройти его, увидеть результат и разбор ошибок.
**Статус:** Завершён и протестирован вручную в браузере.
- [x] Модели БД: `TestAttempt`, `AttemptAnswer`
- [x] API: `POST /api/attempts` — начать попытку (фиксируем время начала)
- [x] API: `POST /api/attempts/{id}/submit` — завершить попытку, подсчитать результат
- [x] API: `GET /api/attempts/{id}/result` — результат с разбором ошибок
- [x] Фронт: страница прохождения теста
- Случайный порядок вопросов
- Таймер с обратным отсчётом (если задан) — автосабмит по истечении
- Навигация назад (если разрешена настройкой теста)
- [x] Фронт: страница результата
- Балл и процент
- Сдал / Не сдал (относительно порога)
- Разбор ошибок: вопрос, ответ сотрудника, правильный ответ
- [x] Фронт: кнопка «Пройти тест» прямо в строке таблицы списка тестов
### Доработки после тестирования
- [x] Страница теста разделена на два вида:
- `/tests/:id` — вид сотрудника: вопросы и варианты ответов без отметок правильных
- `/tests/:id/edit` — вид автора: правильные ответы отмечены, жёлтый баннер, кнопка «Редактировать» (задизаблена до Спринта 4)
- [x] Список тестов: три кнопки действий заменены на выпадающее меню «⋯» — колонка с названием стала полноширинной
### Баги, найденные и исправленные при тестировании
- [x] «Не удалось загрузить тест» × 2 при нажатии «Пройти тест» — миграция `002_attempts` не применилась, т.к. `--reload` перезапускает только код приложения, но не `entrypoint.sh` → исправлено: `docker compose restart backend`
---
## Спринт 3 — Редактирование теста + версионность ✅
**Результат:** Тест можно редактировать. Если тест уже проходили — создаётся новая версия, старая сохраняется для истории.
**Статус:** Завершён и протестирован вручную в браузере.
### Backend
- [x] Миграция `003`: добавить поле `parent_id` в таблицу `tests`
- [x] `PUT /api/tests/{id}` — редактировать тест:
- Нет попыток → обновить на месте
- Есть попытки → создать новый тест (`version + 1`, `parent_id = id`), вернуть `{test, is_new_version: true}`
- [x] `GET /api/tests` — показывать только активные версии (`is_active = True`)
- [x] `GET /api/tests/{id}/versions` — цепочка всех версий теста
- [x] `POST /api/tests/{id}/activate` — сделать версию активной (деактивирует остальные в цепочке)
### Frontend
- [x] Страница `/tests/:id/edit` разделена на режим просмотра и режим редактирования
- [x] Форма редактирования с предзаполненными данными (общий компонент `TestForm`)
- [x] При сохранении с новой версией — редирект + уведомление «Создана новая версия v2»
- [x] Кнопка «← К просмотру теста» в форме редактирования
- [x] Секция «История версий»: таблица с версиями, статусом, датой, кнопкой «Сделать активной»
- [x] Активная версия — единственная видимая в списке тестов
### Баги, найденные и исправленные при тестировании
- [x] `ForeignKeyViolationError` при сохранении — bulk `DELETE questions` не каскадирует на `answers` → исправлено: сначала удаляем `answers`, потом `questions`
- [x] Обе версии показывались «Активными» при создании до введения логики деактивации → исправлено: кнопка «Сделать активной» в шапке и в строке таблицы
---
## Спринт 4 — AI-помощник (DeepSeek) ✅
**Результат:** При создании и редактировании теста доступен AI-ассистент на базе DeepSeek. Ключ API настраивается через страницу настроек.
**Статус:** Завершён и протестирован вручную в браузере.
### Страница настроек (`/settings`)
- [x] Модель БД: `Setting` (key-value, ключ `deepseek_api_key`)
- [x] Миграция `004`
- [x] API: `GET /api/settings/{key}`, `PUT /api/settings/{key}`
- [x] API: `POST /api/llm/check` — проверить подключение (тестовый запрос к DeepSeek)
- [x] Фронт: страница `/settings` — поле для ввода ключа + кнопка «Проверить подключение»
### AI-функции в форме создания/редактирования теста
- [x] API: `POST /api/llm/generate` — сгенерировать вопросы и ответы по теме
- [x] API: `POST /api/llm/improve` — улучшить формулировку вопроса
- [x] API: `POST /api/llm/distractors` — добавить варианты-дистракторы к вопросу
- [x] API: `POST /api/llm/review` — проверить качество всего теста
### Интеграция в UI
- [x] Кнопка «Сгенерировать с AI» над списком вопросов — ввод темы → превью → «Применить все вопросы»
- [x] Кнопка «Улучшить» в шапке каждого вопроса — заменяет формулировку AI-версией
- [x] Кнопка «Дистракторы» в шапке каждого вопроса — добавляет 3 новых неправильных варианта
- [x] Кнопка «Проверить тест» — AI анализирует весь тест и выдаёт рекомендации в модале
- [x] Ссылка «Настройки» в шапке приложения (новый Layout с AppHeader)
### Технические детали
- DeepSeek API совместим с форматом OpenAI — используем библиотеку `openai` с `base_url=https://api.deepseek.com`
- Модель: `deepseek-chat`
- Ключ хранится в таблице `settings`, передаётся из бэкенда — фронт ключ не видит
- `response_format={"type": "json_object"}` для generate, distractors, improve, improve_all — гарантирует структурированный ответ
### Доработки после тестирования
- [x] «Сгенерировать с AI»: убран вопрос про тему — используется название теста; кнопка задизаблена пока название не заполнено
- [x] «Улучшить»: открывает модал с постатейным сравнением (вопрос + каждый ответ) и галочками вместо прямой замены
- [x] «Проверить тест»: добавлена кнопка «Предложить вариант» — вызывает `POST /api/llm/improve_all`, показывает сравнение всего теста с галочками
---
## Спринт 5 — Трекер результатов ✅
**Результат:** Таблица всех попыток прохождения тестов.
**Статус:** Завершён и протестирован вручную в браузере.
- [x] Миграция `005`: поле `user_id` в `test_attempts` (дефолт 1 = «Гость»)
- [x] API: `GET /api/attempts` — все попытки (с фильтрами по тесту, дате, пагинацией)
- [x] Фронт: страница `/tracker`
- Таблица: сотрудник, тест + версия, дата начала, дата завершения, результат, зачёт
- Фильтрация по тесту и диапазону дат
- Пагинация (20 записей на страницу)
- [x] Ссылка «Трекер» в шапке приложения
**Примечание:** `user_id = 1` («Гость») — временно до Спринта 6 (авторизация).
---
## Спринт 6 — Авторизация и управление пользователями
**Результат:** Вход по логину/паролю, роли ограничивают доступ. Можно создавать сотрудников и подразделения.
### Авторизация
- [ ] Модели БД: `User`, `Department`
- [ ] API: `POST /api/auth/login` → JWT access token
- [ ] API: `POST /api/auth/logout`
- [ ] API: `GET /api/auth/me`
- [ ] Middleware: проверка JWT на защищённых эндпоинтах
- [ ] Фронт: страница входа
- [ ] Фронт: защищённые роуты (редирект на логин если нет токена)
### Роли и права
| Роль | Тесты | Трекер |
|------|-------|--------|
| HR-менеджер / Директор | Создаёт и редактирует все тесты | Вся клиника |
| Руководитель подразделения | Создаёт и редактирует свои тесты | Только свой отдел |
| Сотрудник | Проходит назначенные тесты | Только свои результаты |
### Управление пользователями
- [ ] API: CRUD подразделений
- [ ] API: CRUD пользователей (создание, редактирование, деактивация)
- [ ] Фронт: страница управления подразделениями (HR)
- [ ] Фронт: страница управления сотрудниками (HR / руководитель)
### Назначение тестов
- [ ] Модели БД: `TestAssignment`
- [ ] API: `POST /api/assignments` — назначить тест (получатели, дедлайн, кол-во попыток)
- [ ] Фронт: форма назначения теста
- [ ] Фронт: дашборд сотрудника — список назначенных тестов со статусами (`Не начат`, `В процессе`, `Завершён`, `Просрочен`)
---
## Спринт 7 — Уведомления в MAX
**Результат:** Сотрудники получают уведомления в мессенджер MAX.
- [ ] Изучить документацию MAX API
- [ ] Реализовать сервис уведомлений в backend
- [ ] Уведомление при назначении теста сотруднику
- [ ] Уведомление за N дней до дедлайна (настраивается)
- [ ] Поле `max_user_id` в профиле пользователя
- [ ] Фронт: в профиле пользователя — поле для MAX ID
---
## Структура репозитория (целевая после Спринта 1)
```
qa_test_app/
├── backend/
│ ├── app/
│ │ ├── api/ ← роутеры FastAPI
│ │ ├── models/ ← SQLAlchemy модели
│ │ ├── schemas/ ← Pydantic схемы
│ │ ├── services/ ← бизнес-логика
│ │ └── main.py
│ ├── alembic/
│ ├── Dockerfile
│ └── requirements.txt
├── frontend/
│ ├── src/
│ │ ├── api/ ← Axios + TanStack Query
│ │ ├── components/ ← переиспользуемые компоненты
│ │ ├── pages/ ← страницы
│ │ └── main.tsx
│ ├── Dockerfile
│ └── package.json
├── nginx/
│ └── nginx.conf
├── docker-compose.yml
└── DOC/
```