9.8 KiB
Карта задач: Card 1 — история прохождений, документ, авторизация HR
Связь со спринтами: основная масса пунктов V.x — Спринт 1 (версионирование + инфра); D.x — загрузка документа (может пересекаться со Спринтом 2 / AI, если без LLM черновик не делается); A.x — авторизация базой Postgres_TG_Bots (выполнять после/параллельно с V.1, чтобы не плодить дубли пользователей на долгий срок).
Фактический стек репозитория TestingWebApp: Node.js (backend), PostgreSQL, Docker; фронт — SPA в frontend/. План доработок не привязывать к FastAPI, если в коде API на Express/Node.
Часть V — Версионирование (цель: корректная история при правках автора)
Правила (приёмка):
- Пока по цепочке теста (
tests.id) не было ни одной попытки вtest_attempts(через любуюtest_version_idэтой цепочки) — автор редактирует на месте текущую единственную строкуtest_versionsи дочерние вопросы/ответы; полеversionне увеличивается. - Как только появилась хотя бы одна попытка — каждое сохранение с изменениями контента создаёт новую строку
test_versions:version = max+1,parent_id→ id предыдущей версии, прежняя версияis_active = false, новаяis_active = true; старые вопросы/ответы копируются в новую версию. - Все версии одной цепочки — общий
test_id; цепочка линейна поparent_id(и/или по монотонномуversionпри одномtest_id). test_attempts.test_version_idNOT NULL — попытка всегда на снимок версии, разбор старых результатов не «плывёт» при новых правках.- Списки тестов для сотрудников и авторов: только активная версия цепочки (
test_versions.is_activeиtestsне скрыт деактивацией цепочки). - История версий в UI: просмотр, ручной выбор активной версии; при выборе в транзакции: у всех версий данного
test_idis_active = false, у выбраннойis_active = true. Новые старты попыток — по текущей активной версии. - Деактивация теста целиком — флаг на уровне
tests(скрыть цепочку из списков, без удаления строк).
Задачи (детализация):
| ID | Задача | Критерий |
|---|---|---|
| V.1 | Миграция БД: test_versions.parent_id (FK на test_versions.id, ON DELETE NO ACTION/RESTRICT), частичный уникальный индекс: не более одной is_active = true на test_id (если СУБД поддерживает; иначе — уникальный индекс + проверка в сервисе) |
migrate отрабатывает пусто на повтор |
| V.2 | Сервис hasAnyAttemptForTest(testId) + unit-тесты |
Покрыты кейсы: 0 попыток / 1+ по любой версии цепочки |
| V.3 | saveTestDraft(author, testId, payload): ветвление in-place vs forkNewVersion (копия вопросов/опций) |
Соответствие правилам 1–2 |
| V.4 | Старт попытки: в test_attempts писать test_version_id той версии, что была активна в момент старта |
Нет перезаписи version_id позже |
| V.5 | API: GET /tests (роль) — только активные цепочки; GET /tests/:id/versions; POST /tests/:id/versions/:vid/activate |
403/404 по политике |
| V.6 | API: PATCH /tests/:id (деактивация цепочки tests.is_active или отдельное поле) |
Список пустеет, данные на месте |
| V.7 | UI автора: номер/метка версии, предупреждение при «после первой попытки», экран история версий, кнопка сменить активную (с confirm) | Смоук sprint-01-testing.md |
| V.8 | UI списки сотрудника/автора: один ряд на цепочку, без дублей версий | — |
| V.9 | Интеграционные тесты API + регресс «разбор старой попытки» по старым question_id |
— |
| V.10 | Продукт (зафиксировать в коде/доке): при новой версии, что делаем с test_assignments — остаются на старом test_version_id / подтягиваем на новый / оба сценария |
Решение в task.md или ADR one-liner |
Часть D — Загрузка документа → черновик теста
Цель: загрузить файл (PDF, DOCX — перечислить лимиты), извлечь текст, сгенерировать структуру вопросов (логично тянуть LLM из ТЗ §4.2) или дать мастер «вставьте текст».
| ID | Задача | Критерий |
|---|---|---|
| D.1 | Эндпоинт POST /tests/import/document (multipart), валидация размера/типа, сохранение во временное хранилище |
413/400 при нарушении |
| D.2 | Извлечение текста: PDF (библиотека на выбор), DOCX (zip/xml) | Юнит на фикстуре |
| D.3 | Вызов слоя генерации (если есть ключ DeepSeek — → промпт; иначе — заглушка «только вручную») с ответом JSON по схеме вопросов/ответов | Согласовано с §4.2 |
| D.4 | UI: кнопка «Из документа», превью, применение → дальше тот же поток сохранения, что и ручной редактор (в т.ч. V.1–V.3) | — |
| D.5 | Удаление временных файлов после обработки / TTL | — |
Часть A — Авторизация по паролю, БД Postgres_TG_Bots
Контекст: в Postgres_TG_Bots/hr_web_viewer учёт users с полями username, password_hash (Werkzeug pbkdf2:sha256 / scrypt через werkzeug.security — см. hr_web_viewer/models/user_models.py).
| ID | Задача | Критерий |
|---|---|---|
| A.1 | Режим DATABASE_URL (или HR_DATABASE_URL) на ту же БД, что и Postgres_TG_Bots, read-only или отдельный пользователь с SELECT на users (+ при необходимости staff_members для department_id) |
Пример .env в TestingWebApp |
| A.2 | Реализация verifyPassword в Node, совместимой с check_password_hash (использовать пакет, понимающий префиксы pbkdf2:sha256: и scrypt:) |
Тест: тот же хеш, что сгенерировал Werkzeug |
| A.3 | Логин: по username → взять id, password_hash; при успехе — JWT/сессия TestingWebApp с user_id (и маппинг на локальный UUID, если в приложении внутри свои users — документировать стратегию: single source = HR DB или sync) |
Нет дублирования паролей в две таблицы в долгую |
| A.4 | Отключить/не использовать регистрацию с локальным password_hash в прод-режиме, если включён HR_AUTH=1 |
Флаг в .env |
| A.5 | Маппинг ролей: users не содержит hr/manager — связать staff_members.web_login = users.username и взять роль из существующей HR-модели или MVP: одна роль + админ-лист |
Зафиксировать в README Card 1 |
Порядок работ (рекомендация)
- V.1 → V.2 → V.3 (ядро версий).
- A.1–A.3 параллельно или сразу после V.1 (нужен стабильный логин для стенда).
- V.4–V.9 и UI V.7–V.8.
- D.* после появления клиента LLM (или D.1–D.2 + ручной встав текста без LLM).
- V.10 — решение по назначениям до V.5 если назначения уже в проде.
Ссылки
- ТЗ: task.md §4.1, §4.2
- Спринт 1: sprint-01.md
- Проверки и журнал: TESTING_JOURNAL.md
- Старый чек-лист: sprint-01-testing.md
- Анализ таблиц (если ведёте): TEST_TABLES_ANALYSIS.md