docs: mark Sprint 2 complete, document migration restart bug
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+12
-7
@@ -44,22 +44,27 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Спринт 2 — Прохождение теста
|
## Спринт 2 — Прохождение теста ✅
|
||||||
|
|
||||||
**Результат:** Можно выбрать тест из списка и пройти его, увидеть результат и разбор ошибок.
|
**Результат:** Можно выбрать тест из списка и пройти его, увидеть результат и разбор ошибок.
|
||||||
|
**Статус:** Завершён и протестирован вручную в браузере.
|
||||||
|
|
||||||
- [ ] Модели БД: `TestAttempt`, `AttemptAnswer`
|
- [x] Модели БД: `TestAttempt`, `AttemptAnswer`
|
||||||
- [ ] API: `POST /api/attempts` — начать попытку (фиксируем время начала)
|
- [x] API: `POST /api/attempts` — начать попытку (фиксируем время начала)
|
||||||
- [ ] API: `POST /api/attempts/{id}/submit` — завершить попытку, подсчитать результат
|
- [x] API: `POST /api/attempts/{id}/submit` — завершить попытку, подсчитать результат
|
||||||
- [ ] API: `GET /api/attempts/{id}/result` — результат с разбором ошибок
|
- [x] API: `GET /api/attempts/{id}/result` — результат с разбором ошибок
|
||||||
- [ ] Фронт: страница прохождения теста
|
- [x] Фронт: страница прохождения теста
|
||||||
- Случайный порядок вопросов
|
- Случайный порядок вопросов
|
||||||
- Таймер с обратным отсчётом (если задан) — автосабмит по истечении
|
- Таймер с обратным отсчётом (если задан) — автосабмит по истечении
|
||||||
- Навигация назад (если разрешена настройкой теста)
|
- Навигация назад (если разрешена настройкой теста)
|
||||||
- [ ] Фронт: страница результата
|
- [x] Фронт: страница результата
|
||||||
- Балл и процент
|
- Балл и процент
|
||||||
- Сдал / Не сдал (относительно порога)
|
- Сдал / Не сдал (относительно порога)
|
||||||
- Разбор ошибок: вопрос, ответ сотрудника, правильный ответ
|
- Разбор ошибок: вопрос, ответ сотрудника, правильный ответ
|
||||||
|
- [x] Фронт: кнопка «Пройти тест» прямо в строке таблицы списка тестов
|
||||||
|
|
||||||
|
### Баги, найденные и исправленные при тестировании
|
||||||
|
- [x] «Не удалось загрузить тест» × 2 при нажатии «Пройти тест» — миграция `002_attempts` не применилась, т.к. `--reload` перезапускает только код приложения, но не `entrypoint.sh` → исправлено: `docker compose restart backend`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
# ШАГ 008 — Спринт 2: Баг «Не удалось загрузить тест»
|
||||||
|
|
||||||
|
**Дата:** 2026-03-21
|
||||||
|
**Контекст:** Мастер-класс по разработке системы тестирования сотрудников клиники.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Запрос
|
||||||
|
|
||||||
|
> вот такой баг при нажатии кнопки «Пройти тест» — «Не удалось загрузить тест» × 2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Симптом
|
||||||
|
|
||||||
|
При нажатии кнопки «Пройти тест» фронт выполняет `POST /api/attempts` и получает ошибку.
|
||||||
|
В консоли backend:
|
||||||
|
|
||||||
|
```
|
||||||
|
sqlalchemy.exc.ProgrammingError: (asyncpg.exceptions.UndefinedTableError)
|
||||||
|
relation "test_attempts" does not exist
|
||||||
|
```
|
||||||
|
|
||||||
|
Ошибка появляется дважды — из-за React StrictMode, который в dev-режиме намеренно монтирует компоненты дважды.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Причина
|
||||||
|
|
||||||
|
`uvicorn --reload` следит только за изменениями Python-файлов и перезапускает **процесс приложения**, но **не перезапускает контейнер целиком** и не выполняет `entrypoint.sh` повторно.
|
||||||
|
|
||||||
|
Миграция `002_attempts` (создаёт таблицы `test_attempts` и `attempt_answers`) была добавлена уже после первого запуска стека — поэтому она ни разу не применялась.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Исправление
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose restart backend
|
||||||
|
```
|
||||||
|
|
||||||
|
При перезапуске контейнер выполняет `entrypoint.sh` заново:
|
||||||
|
|
||||||
|
```
|
||||||
|
Running migrations...
|
||||||
|
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
|
||||||
|
INFO [alembic.runtime.migration] Will assume transactional DDL.
|
||||||
|
INFO [alembic.runtime.migration] Running upgrade 001 -> 002, attempts
|
||||||
|
Starting server...
|
||||||
|
INFO: Application startup complete.
|
||||||
|
```
|
||||||
|
|
||||||
|
Таблицы созданы — баг исчезает.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Правило для джуниора
|
||||||
|
|
||||||
|
> `uvicorn --reload` ≠ перезапуск контейнера.
|
||||||
|
>
|
||||||
|
> Если ты добавил новую миграцию Alembic и стек уже работает — выполни `docker compose restart backend`, чтобы миграция применилась.
|
||||||
|
>
|
||||||
|
> `docker compose up` запускает контейнер только если он не запущен. `restart` — принудительно пересоздаёт его.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Следующие шаги
|
||||||
|
|
||||||
|
- [x] Спринт 1: Инфраструктура + Создание тестов
|
||||||
|
- [x] Спринт 2: Прохождение теста + результат
|
||||||
|
- [ ] Спринт 3: Трекер результатов
|
||||||
|
- [ ] Спринт 4: Авторизация и роли
|
||||||
|
- [ ] Спринт 5: Уведомления в MAX
|
||||||
Reference in New Issue
Block a user