Спринт 5: Трекер результатов

- Миграция 005: user_id в test_attempts (дефолт 1 = Гость)
- GET /api/attempts с фильтрами по тесту, дате и пагинацией
- Страница /tracker: таблица попыток, фильтры, пагинация
- Ссылка «Трекер» в шапке приложения

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Aleksey Razorvin
2026-03-21 15:26:40 +05:00
parent 9a0b3ba92c
commit fc684e7c7d
11 changed files with 522 additions and 22 deletions
+118
View File
@@ -0,0 +1,118 @@
# Итоги разработки — 21 марта 2026
## Общая информация
| Параметр | Значение |
|----------|---------|
| Дата | 21 марта 2026 |
| Начало работы | 10:56 |
| Текущее состояние | Спринты 1–5 завершены |
| Затрачено времени | ~5 часов |
| Коммитов | 26 |
---
## Хронология по коммитам
| Время | Этап |
|-------|------|
| 10:5611:41 | Подготовка: структура проекта, ТЗ v1.1, стек, план спринтов, README |
| 12:0512:46 | **Спринт 1** — инфраструктура + создание тестов |
| 12:5313:18 | **Спринт 2** — прохождение теста + результаты + UX |
| 13:2214:08 | **Спринт 3** — редактирование + версионирование |
| 14:0815:11 | **Спринт 4** — AI-помощник (DeepSeek) |
| 15:1116:00 | **Спринт 5** — трекер результатов |
---
## Что реализовано
### Спринт 1 — Инфраструктура + создание тестов (~40 мин)
- Docker Compose: PostgreSQL 16, FastAPI, React + Vite, Nginx
- Alembic: миграция `001_init` (таблицы tests, questions, answers)
- API: `POST /api/tests`, `GET /api/tests`, `GET /api/tests/{id}`
- Фронт: создание теста, список тестов, просмотр теста
- Исправлено 4 бага при тестировании (entrypoint, PYTHONPATH, nginx DNS, FastAPI docs URL)
### Спринт 2 — Прохождение теста + результаты (~25 мин)
- Миграция `002_attempts` (таблицы test_attempts, attempt_answers)
- API: `POST /api/attempts`, `POST /api/attempts/{id}/submit`, `GET /api/attempts/{id}/result`
- Прохождение: случайный порядок вопросов, таймер с автосабмитом, навигация назад
- Страница результатов: балл, зачёт/незачёт, разбор ошибок по каждому вопросу
- UX: разделение вида сотрудника (`/tests/:id`) и автора (`/tests/:id/edit`), выпадающее меню «⋯» в списке тестов
### Спринт 3 — Редактирование + версионирование (~46 мин)
- Миграция `003_test_versioning` (поле `parent_id` в tests)
- API: `PUT /api/tests/{id}`, `GET /api/tests/{id}/versions`, `POST /api/tests/{id}/activate`
- Логика: нет попыток → редактировать на месте; есть попытки → создать новую версию (`version+1`, `parent_id=old.id`)
- Фронт: общий компонент `TestForm`, страница редактирования с историей версий и активацией
- Исправлено 2 бага (FK cascade при bulk DELETE, отображение статуса «Активная»)
### Спринт 4 — AI-помощник (DeepSeek) (~63 мин)
- Миграция `004_settings` (таблица settings, key-value)
- Страница `/settings`: ввод API ключа DeepSeek + кнопка «Проверить подключение»
- 6 AI-эндпоинтов:
- `POST /api/llm/check` — проверка подключения
- `POST /api/llm/generate` — генерация вопросов по теме (= название теста)
- `POST /api/llm/improve` — улучшение формулировки вопроса + ответов
- `POST /api/llm/distractors` — генерация дистракторов
- `POST /api/llm/review` — рецензия всего теста
- `POST /api/llm/improve_all` — улучшение всего теста целиком
- В форме теста: 4 AI-кнопки с модалами и постатейным сравнением (галочки для применения изменений)
- Шапка приложения с навигацией
### Спринт 5 — Трекер результатов (~49 мин)
- Миграция `005_attempt_user` (поле `user_id` в test_attempts, дефолт 1 = «Гость»)
- API: `GET /api/attempts` с фильтрами (test_id, date_from, date_to) и пагинацией
- Страница `/tracker`: таблица всех попыток, фильтр по тесту и диапазону дат, пагинация
- Колонки: Сотрудник / Тест + версия / Начало / Завершение / Результат / Зачёт
---
## Объём кода
| Слой | Файлы |
|------|-------|
| Backend — модели | `test.py`, `attempt.py`, `setting.py` |
| Backend — схемы | `test.py`, `attempt.py`, `setting.py` |
| Backend — API роутеры | `tests.py`, `attempts.py`, `llm.py`, `settings.py` |
| Backend — сервисы | `llm.py` |
| Backend — миграции | `001``005` |
| Frontend — страницы | TestList, TestCreate, TestDetail, TestEdit, TestTake, AttemptResult, Settings, Tracker |
| Frontend — компоненты | `TestForm` (с AI-функциями) |
| Frontend — API клиенты | `tests.ts`, `attempts.ts`, `llm.ts`, `settings.ts`, `client.ts` |
| Документация | ТЗ v1.2, СТЕК, СПРИНТЫ, README, 12 файлов ШАГИ |
| **Итого** | **~46 файлов** |
---
## Текущий статус спринтов
| Спринт | Содержание | Статус |
|--------|-----------|--------|
| 1 | Инфраструктура + создание тестов | ✅ Завершён |
| 2 | Прохождение теста + результаты | ✅ Завершён |
| 3 | Редактирование + версионирование | ✅ Завершён |
| 4 | AI-помощник (DeepSeek) | ✅ Завершён |
| 5 | Трекер результатов | ✅ Завершён |
| 6 | Авторизация, роли, подразделения | ⬜ Следующий |
| 7 | Уведомления в MAX | ⬜ Запланирован |
---
## Технический долг перед Спринтом 6
- `user_id = 1` (Гость) в `test_attempts` — заменить на ID авторизованного пользователя
- `GUEST_USER_NAME = "Гость"` в `api/attempts.py` — заменить на JOIN с таблицей `users`
- Все эндпоинты открыты без авторизации — добавить JWT Middleware
---
## Запуск проекта
```bash
docker compose up --build
```
Приложение: `http://localhost`
API документация: `http://localhost/api/docs`
+11 -6
View File
@@ -140,15 +140,20 @@
---
## Спринт 5 — Трекер результатов
## Спринт 5 — Трекер результатов
**Результат:** Таблица всех попыток прохождения тестов.
**Статус:** Завершён и протестирован вручную в браузере.
- [ ] API: `GET /api/attempts` — все попытки (с фильтрами по тесту, дате)
- [ ] Фронт: страница трекера
- Таблица: тест, версия, дата начала, дата завершения, результат, зачёт
- Фильтрация по тесту и дате
- Пагинация
- [x] Миграция `005`: поле `user_id` в `test_attempts` (дефолт 1 = «Гость»)
- [x] API: `GET /api/attempts` — все попытки (с фильтрами по тесту, дате, пагинацией)
- [x] Фронт: страница `/tracker`
- Таблица: сотрудник, тест + версия, дата начала, дата завершения, результат, зачёт
- Фильтрация по тесту и диапазону дат
- Пагинация (20 записей на страницу)
- [x] Ссылка «Трекер» в шапке приложения
**Примечание:** `user_id = 1` («Гость») — временно до Спринта 6 (авторизация).
---
+72
View File
@@ -0,0 +1,72 @@
# ШАГ 013 — Спринт 5: Трекер результатов
**Дата:** 2026-03-21
**Контекст:** Мастер-класс по разработке системы тестирования сотрудников клиники.
---
## Запрос
> Оставляем текущий спринт. Введём user_id здесь вручную — пусть это будет гость.
---
## Реализовано
Страница трекера всех попыток с фильтрацией и пагинацией. Все попытки пока принадлежат одному пользователю — «Гость» (user_id = 1).
---
## Новые файлы
```
backend/alembic/versions/005_attempt_user.py ← добавляет user_id в test_attempts
frontend/src/pages/Tracker/index.tsx ← страница /tracker
```
## Изменённые файлы
```
backend/app/models/attempt.py ← поле user_id (default=1, server_default='1')
backend/app/schemas/attempt.py ← AttemptListItem, AttemptListResponse
backend/app/api/attempts.py ← GET /api/attempts + GUEST_USER_ID/NAME константы
frontend/src/api/attempts.ts ← AttemptListItem, AttemptListResponse, list()
frontend/src/App.tsx ← роут /tracker, кнопка «Трекер» в шапке
```
---
## API эндпоинты (новые)
| Метод | URL | Параметры | Описание |
|-------|-----|-----------|----------|
| GET | `/api/attempts` | test_id, date_from, date_to, page, page_size | Список завершённых попыток |
---
## Схема БД (изменено)
```
test_attempts
+ user_id INTEGER NOT NULL DEFAULT 1
```
---
## Технический долг (Sprint 6)
- `user_id = 1` → заменить на ID из JWT токена
- `GUEST_USER_NAME` → JOIN с таблицей users
- Все эндпоинты открыты → добавить JWT Middleware
---
## Следующие шаги
- [x] Спринт 1: Инфраструктура + Создание тестов
- [x] Спринт 2: Прохождение теста + результат
- [x] Спринт 3: Редактирование + версионность
- [x] Спринт 4: AI-помощник (DeepSeek)
- [x] Спринт 5: Трекер результатов
- [ ] Спринт 6: Авторизация и роли
- [ ] Спринт 7: Уведомления в MAX