2 changed files with 115 additions and 7 deletions
@ -0,0 +1,98 @@ |
|||||||
|
# ШАГ 010 — Спринт 3: Редактирование теста + версионность |
||||||
|
|
||||||
|
**Дата:** 2026-03-21 |
||||||
|
**Контекст:** Мастер-класс по разработке системы тестирования сотрудников клиники. |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Запрос |
||||||
|
|
||||||
|
> запускаем спринт 3 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Реализовано |
||||||
|
|
||||||
|
Полноценное редактирование тестов с автоматическим версионированием. |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Новые файлы |
||||||
|
|
||||||
|
``` |
||||||
|
backend/alembic/versions/003_test_versioning.py ← добавляет parent_id в tests |
||||||
|
frontend/src/components/TestForm/index.tsx ← переиспользуемая форма теста |
||||||
|
``` |
||||||
|
|
||||||
|
## Изменённые файлы |
||||||
|
|
||||||
|
``` |
||||||
|
backend/app/models/test.py ← добавлено поле parent_id |
||||||
|
backend/app/schemas/test.py ← TestOut.parent_id, TestUpdateResponse |
||||||
|
backend/app/api/tests.py ← PUT + /versions + /activate |
||||||
|
frontend/src/api/tests.ts ← update, versions, activate |
||||||
|
frontend/src/pages/TestCreate/ ← упрощён через TestForm |
||||||
|
frontend/src/pages/TestEdit/ ← полноценный просмотр + редактирование |
||||||
|
``` |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## API эндпоинты (новые) |
||||||
|
|
||||||
|
| Метод | URL | Описание | |
||||||
|
|-------|-----|----------| |
||||||
|
| PUT | `/api/tests/{id}` | Редактировать тест | |
||||||
|
| GET | `/api/tests/{id}/versions` | Цепочка всех версий | |
||||||
|
| POST | `/api/tests/{id}/activate` | Сделать версию активной | |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Схема БД (изменено) |
||||||
|
|
||||||
|
``` |
||||||
|
tests |
||||||
|
+ parent_id → tests.id ← ссылка на предыдущую версию (NULL у первой) |
||||||
|
``` |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Логика версионирования |
||||||
|
|
||||||
|
| Условие при сохранении | Результат | |
||||||
|
|------------------------|-----------| |
||||||
|
| Попыток нет | Редактируем на месте, версия не меняется | |
||||||
|
| Есть хотя бы одна попытка | Новый тест: `version+1`, `parent_id=old.id`, `is_active=True`; старый: `is_active=False` | |
||||||
|
|
||||||
|
**Список тестов** показывает только `is_active=True` версии. |
||||||
|
**История версий** отображается на странице `/tests/:id/edit` — таблица всех версий цепочки. |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## UX редактирования |
||||||
|
|
||||||
|
- Страница `/tests/:id/edit` работает в двух режимах: просмотр автора → нажать «Редактировать» → форма редактирования |
||||||
|
- Кнопка «← К просмотру теста» в шапке формы |
||||||
|
- При создании новой версии: редирект на `/tests/:newId/edit` + уведомление |
||||||
|
- В таблице «История версий»: статус (Активная/Неактивная), кнопка «Сделать активной» для любой версии |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Баги, найденные и исправленные при тестировании |
||||||
|
|
||||||
|
| # | Симптом | Причина | Исправление | |
||||||
|
|---|---------|---------|-------------| |
||||||
|
| 1 | `ForeignKeyViolationError` при сохранении теста | `DELETE FROM questions` bulk-запросом не каскадирует на `answers` — в схеме нет `ON DELETE CASCADE` | Сначала удаляем `answers` по `question_id IN (...)`, затем `questions` | |
||||||
|
| 2 | Обе версии показывались «Активными» | Тест был создан до введения логики деактивации родителя | Добавлена кнопка «Сделать активной» в шапке и в строке таблицы для любой версии | |
||||||
|
|
||||||
|
> **Для джуниора:** `cascade="all, delete-orphan"` в SQLAlchemy работает только при удалении через ORM-объекты (`session.delete(obj)`). При bulk-delete через `db.execute(delete(Model)...)` ORM-каскад не срабатывает — нужно вручную удалять дочерние записи в правильном порядке. |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Следующие шаги |
||||||
|
|
||||||
|
- [x] Спринт 1: Инфраструктура + Создание тестов |
||||||
|
- [x] Спринт 2: Прохождение теста + результат |
||||||
|
- [x] Спринт 3: Редактирование + версионность |
||||||
|
- [ ] Спринт 4: Трекер результатов |
||||||
|
- [ ] Спринт 5: Авторизация и роли |
||||||
|
- [ ] Спринт 6: Уведомления в MAX |
||||||
Loading…
Reference in new issue