You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

13 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.

Хранение, связь с сотрудниками, RBAC (зафиксировано)

  • Один кластер PostgreSQL (как в Postgres_TG_Bots): отдельные базыclinic_tests (тесты, назначения, попытки, миграции модуля) и hr_bot_test (штат, справочники, уже реализованный RBAC). Таблицы модуля тестов не вешаем в hr_bot_test, чтобы не конфликтовать по именам (users, departments и т.д. уже заняты смыслами HR).
  • Сотрудник в бизнес-процессах модуля тестирования идентифицируется по staff_members.id (БД hr_bot_test / экосистема hr_web_viewer). В clinic_tests храним суррогатные ссылки на сотрудника (например staff_id / UUID той же сущности), без дублирования ФИО и кадровых данных в долгую.
  • telegram_id в данных сотрудника — только справка (в т.ч. для исторических выгрузок, отображения). Ни назначения, ни проверок прав, ни выбор сотрудника в сценариях модуля от telegram_id не зависят и не должны зависеть.
  • RBAC: единая цель — опираться на уже существующую в клинике модель (роли, привязки к сотруднику, permissions). Проверка «можно ли действие» в конечном варианте — через HR API / общий auth-контур и/или согласованное чтение RBAC-таблиц; в clinic_tests не строим параллельную полную матрицу ролей. На переходных этапах допустимы упрощения (MVP-флаги), пока в контракте не зафиксировано иное.

Часть V — Версионирование (цель: корректная история при правках автора)

Правила (приёмка):

  1. Пока по цепочке теста (tests.id) не было ни одной попытки в test_attempts (через любую test_version_id этой цепочки) — автор редактирует на месте текущую единственную строку test_versions и дочерние вопросы/ответы; поле version не увеличивается.
  2. Как только появилась хотя бы одна попытка — каждое сохранение с изменениями контента создаёт новую строку test_versions: version = max+1, parent_id → id предыдущей версии, прежняя версия is_active = false, новая is_active = true; старые вопросы/ответы копируются в новую версию.
  3. Все версии одной цепочки — общий test_id; цепочка линейна по parent_id (и/или по монотонному version при одном test_id).
  4. test_attempts.test_version_id NOT NULL — попытка всегда на снимок версии, разбор старых результатов не «плывёт» при новых правках.
  5. Списки тестов для сотрудников и авторов: только активная версия цепочки (test_versions.is_active и tests не скрыт деактивацией цепочки).
  6. История версий в UI: просмотр, ручной выбор активной версии; при выборе в транзакции: у всех версий данного test_id is_active = false, у выбранной is_active = true. Новые старты попыток — по текущей активной версии.
  7. Деактивация теста целиком — флаг на уровне 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). Идентичность сотрудника для сценариев тестов — по staff_members.id (см. блок «Хранение…» выше); telegram_id не используем в логике входа, назначений и прав.

ID Задача Критерий
A.1 Вторичное соединение: HR_DATABASE_URL (или DSN) к hr_bot_test, read-only или отдельный пользователь с SELECT на users и staff_members (для связки логин → staff_id, подразделение и т.д.) отдельно от DATABASE_URL в clinic_tests Пример .env в TestingWebApp
A.2 Реализация verifyPassword в Node, совместимой с check_password_hash (использовать пакет, понимающий префиксы pbkdf2:sha256: и scrypt:) Тест: тот же хеш, что сгенерировал Werkzeug
A.3 Логин: по usernameusers в hr_bot_test; при успехе — токен TestingWebApp с привязкой к staff_members.id (и при необходимости к локальному users в clinic_tests только как технический mirror без отдельного жизненного цикла пароля). Пароли только в HR-таблице users Нет дублирования паролей в долгую
A.4 Отключить/не использовать регистрацию с локальным password_hash в прод-режиме, если включён HR_AUTH=1 Флаг в .env
A.5 Маппинг ролей: взять из существующей RBAC-модели HR (см. staff_role_assignments / roles & permissions) или согласованный вызов HR API; MVP — ограниченный набор, без опоры на telegram_id README — данные и интеграция

Порядок работ (рекомендация)

  1. V.1V.2V.3 (ядро версий).
  2. A.1A.3 параллельно или сразу после V.1 (нужен стабильный логин для стенда).
  3. V.4V.9 и UI V.7V.8.
  4. D.* после появления клиента LLM (или D.1–D.2 + ручной встав текста без LLM).
  5. V.10 — решение по назначениям до V.5 если назначения уже в проде.

Ссылки