Спринт 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:
@@ -0,0 +1,118 @@
|
||||
# Итоги разработки — 21 марта 2026
|
||||
|
||||
## Общая информация
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|---------|
|
||||
| Дата | 21 марта 2026 |
|
||||
| Начало работы | 10:56 |
|
||||
| Текущее состояние | Спринты 1–5 завершены |
|
||||
| Затрачено времени | ~5 часов |
|
||||
| Коммитов | 26 |
|
||||
|
||||
---
|
||||
|
||||
## Хронология по коммитам
|
||||
|
||||
| Время | Этап |
|
||||
|-------|------|
|
||||
| 10:56–11:41 | Подготовка: структура проекта, ТЗ v1.1, стек, план спринтов, README |
|
||||
| 12:05–12:46 | **Спринт 1** — инфраструктура + создание тестов |
|
||||
| 12:53–13:18 | **Спринт 2** — прохождение теста + результаты + UX |
|
||||
| 13:22–14:08 | **Спринт 3** — редактирование + версионирование |
|
||||
| 14:08–15:11 | **Спринт 4** — AI-помощник (DeepSeek) |
|
||||
| 15:11–16: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
@@ -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 (авторизация).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user