feat: Sprint 2 — test taking + results
Backend:
- Models: TestAttempt, AttemptAnswer (migration 002)
- POST /api/attempts: start attempt, shuffle questions/answers,
hide is_correct, expose is_multiple for UI hints
- POST /api/attempts/{id}/submit: save answers, calculate score,
strict matching (selected == correct), return full result
- GET /api/attempts/{id}/result: fetch saved result
- Register attempts router in main.py
Frontend:
- api/attempts.ts: types + API functions
- TestTake page: one question at a time, progress bar, timer
with auto-submit, back navigation controlled by test setting,
radio/checkbox based on is_multiple
- AttemptResult page: score, pass/fail, per-question breakdown
with correct/selected/missed answer highlighting
- App.tsx: add /tests/:testId/take and /attempts/:id/result routes
- TestDetail: add "Пройти тест" button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
# ШАГ 007 — Спринт 2: Прохождение теста + результат
|
||||
|
||||
**Дата:** 2026-03-21
|
||||
**Контекст:** Мастер-класс по разработке системы тестирования сотрудников клиники.
|
||||
|
||||
---
|
||||
|
||||
## Запрос
|
||||
|
||||
> запускай реализацию спринта 2
|
||||
|
||||
---
|
||||
|
||||
## Ответ
|
||||
|
||||
Реализован Спринт 2: прохождение теста с таймером и навигацией, результат с разбором ошибок.
|
||||
|
||||
---
|
||||
|
||||
## Новые файлы
|
||||
|
||||
```
|
||||
backend/app/models/attempt.py ← TestAttempt, AttemptAnswer
|
||||
backend/app/schemas/attempt.py ← схемы для старта, сдачи и результата
|
||||
backend/app/api/attempts.py ← 3 эндпоинта
|
||||
backend/alembic/versions/002_attempts.py ← миграция
|
||||
|
||||
frontend/src/api/attempts.ts ← типы и запросы
|
||||
frontend/src/pages/TestTake/ ← страница прохождения теста
|
||||
frontend/src/pages/AttemptResult/ ← страница результата
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API эндпоинты (новые)
|
||||
|
||||
| Метод | URL | Описание |
|
||||
|-------|-----|----------|
|
||||
| POST | `/api/attempts` | Начать попытку → возвращает вопросы перемешанные, без правильных ответов |
|
||||
| POST | `/api/attempts/{id}/submit` | Сдать тест → подсчитать и вернуть результат |
|
||||
| GET | `/api/attempts/{id}/result` | Получить результат сохранённой попытки |
|
||||
|
||||
---
|
||||
|
||||
## Схема БД (добавлено)
|
||||
|
||||
```
|
||||
test_attempts
|
||||
id, test_id → tests.id, started_at, finished_at,
|
||||
score, passed, correct_count, total_count, status
|
||||
|
||||
attempt_answers
|
||||
id, attempt_id → test_attempts.id,
|
||||
question_id → questions.id, answer_id → answers.id
|
||||
```
|
||||
|
||||
Одна строка `attempt_answers` = один выбранный вариант ответа.
|
||||
Для вопросов с несколькими правильными ответами — несколько строк.
|
||||
|
||||
---
|
||||
|
||||
## Логика прохождения теста
|
||||
|
||||
**Старт попытки:**
|
||||
- Создаётся запись `TestAttempt` со статусом `in_progress`
|
||||
- Вопросы и ответы внутри каждого вопроса перемешиваются случайно
|
||||
- Поле `is_correct` **не передаётся** на фронт — нельзя смошенничать через DevTools
|
||||
- Поле `is_multiple: bool` говорит фронту: показывать радио-кнопки или чекбоксы
|
||||
|
||||
**Сдача теста:**
|
||||
- Фронт отправляет `[{ question_id, answer_ids[] }]` для каждого вопроса
|
||||
- Вопрос засчитывается правильным только если `selected_ids == correct_ids` (точное совпадение)
|
||||
- Балл = (правильных / всего) × 100
|
||||
- Зачёт: балл ≥ порогу из теста
|
||||
|
||||
**Разбор ошибок:**
|
||||
- Для каждого вопроса: `is_answered_correctly`
|
||||
- Для каждого варианта: `is_correct` + `is_selected` → фронт показывает что выбрал и что было правильно
|
||||
|
||||
---
|
||||
|
||||
## UX прохождения теста
|
||||
|
||||
- Вопросы по одному, прогресс-бар сверху
|
||||
- Таймер: если задан — обратный отсчёт, при `< 60 сек` — предупреждение, при `0` — автосабмит
|
||||
- Кнопка «Назад» заблокирована если `allow_navigation_back = false`
|
||||
- Чекбоксы для `is_multiple`, радио-кнопки для одиночного ответа
|
||||
|
||||
---
|
||||
|
||||
## Следующие шаги
|
||||
|
||||
- [x] Спринт 1: Инфраструктура + Создание тестов
|
||||
- [x] Спринт 2: Прохождение теста + результат
|
||||
- [ ] Спринт 3: Трекер результатов
|
||||
- [ ] Спринт 4: Авторизация и роли
|
||||
- [ ] Спринт 5: Уведомления в MAX
|
||||
Reference in New Issue
Block a user