Compare commits
2 Commits
6f9a80be16
...
4eeb3fbc62
| Author | SHA1 | Date | |
|---|---|---|---|
| 4eeb3fbc62 | |||
| 93dcfcf4ff |
@@ -0,0 +1,14 @@
|
||||
-- Version chain: parent link + at most one active version per test chain
|
||||
-- Aligns with docs/revision_task/card1.md (V.1)
|
||||
|
||||
ALTER TABLE test_versions
|
||||
ADD COLUMN IF NOT EXISTS parent_id UUID REFERENCES test_versions(id) ON DELETE RESTRICT;
|
||||
|
||||
COMMENT ON COLUMN test_versions.parent_id IS 'Previous version in chain; NULL for first version';
|
||||
|
||||
-- Only one active version per tests.id (chain)
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_test_versions_one_active_per_test
|
||||
ON test_versions (test_id)
|
||||
WHERE is_active = true;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_test_versions_parent_id ON test_versions (parent_id);
|
||||
@@ -0,0 +1,88 @@
|
||||
# Декомпозиция доработки (по ТЗ [revision_task/task.md](task.md))
|
||||
|
||||
**Стек (репозиторий [TestingWebApp](../..)):** **Node.js** (backend), **PostgreSQL**, **Docker**; фронт — desktop-first SPA. Экосистема клиники: см. [HR_TG_Bot README](../../../HR_TG_Bot/README.md); перенос на Python/FastAPI **не** считается обязательным для этого репо — **контракт** данных и [card1.md](revision_task/card1.md) важнее.
|
||||
|
||||
**Карта больших кусков работ:** [card1.md](card1.md) (версии **V**, документ **D**, авторизация **HR A**).
|
||||
|
||||
**Этап 1 (ТЗ §4)** — пять фич: 4.1–4.5 (части можно параллелить).
|
||||
**Этап 2 (ТЗ §5)** — дашборды.
|
||||
**Этапы 3–5** — интеграция в общий HR, MAX, уведомления.
|
||||
|
||||
**Первые спринты:** [sprint-01.md](sprint-01.md), [sprint-02.md](sprint-02.md) (и при наличии `sprint-02-testing`).
|
||||
|
||||
---
|
||||
|
||||
## A. Подготовка и база (фундамент)
|
||||
|
||||
| ID | Подзадача |
|
||||
| --- | --- |
|
||||
| A.1 | Репозиторий, Docker Compose (PostgreSQL), .env, health |
|
||||
| A.2 | Схема БД, миграции: пользователи, подразделения, тесты, версии, попытки (см. [card1 V.1](card1.md)) |
|
||||
| A.3 | Аутентификация: **локальная** **или** **через** [Postgres_TG_Bots](card1.md#часть-a--авторизация-по-паролю-бд-postgres_tg_bots) ([card1 A.x](card1.md)) |
|
||||
| A.4 | CRUD тест/назначение/прохождение (база шагов `docs/шаги/`) + затем **B** |
|
||||
|
||||
*Если A.1–A.4 частично сданы — добить по [sprint-01](sprint-01.md) и [card1](card1.md).*
|
||||
|
||||
---
|
||||
|
||||
## B. Фича 4.1 — Версионирование тестов
|
||||
|
||||
См. полностью [card1.md — Часть V](card1.md#часть-v--версионирование-цель-корректная-история-при-правках-автора) (V.1–V.10).
|
||||
|
||||
---
|
||||
|
||||
## C. Фича 4.2 — AI-помощник (DeepSeek)
|
||||
|
||||
| ID | Подзадача |
|
||||
| --- | --- |
|
||||
| C.1 | Ключ в БД; `/settings`; «Проверить»; ключ не на фронт |
|
||||
| C.2 | OpenAI-совместимый клиент, `json_object` |
|
||||
| C.3 | Сгенерировать/проверить/улучшить тест; модалки, было→стало |
|
||||
| C.4 | Вопрос: улучшить, дистракторы, подсказка (с 4.4) |
|
||||
|
||||
*Импорт из документа ([card1 D](card1.md)) тянет C.1–C.3.*
|
||||
|
||||
---
|
||||
|
||||
## D. Импорт из документа
|
||||
|
||||
См. [card1 D.1–D.5](card1.md#часть-d--загрузка-документа--черновик-теста).
|
||||
|
||||
---
|
||||
|
||||
## E–F. Подсказки и режимы (§4.4–4.5)
|
||||
|
||||
| ID | Кратко |
|
||||
| --- | --- |
|
||||
| E.x | Подсказка в вопросе, показ по режиму |
|
||||
| F.x | Таймер, мгновенная оценка, итог в конце |
|
||||
|
||||
---
|
||||
|
||||
## G. Этап 2 — Дашборды (§5)
|
||||
|
||||
| ID | Подзадача |
|
||||
| --- | --- |
|
||||
| G.1 | Дашборд сотрудника |
|
||||
| G.2 | Руководитель подразделения |
|
||||
| G.3 | Директор / вся клиника |
|
||||
|
||||
---
|
||||
|
||||
## H. Спринт 1 — сопоставление
|
||||
|
||||
| Спринт | Охват |
|
||||
| --- | --- |
|
||||
| **Спринт 1** | A (дозакрытие) + **B** = [card1 V](card1.md) + при согласовании [A](card1.md) (Postgres_TG_Bots) |
|
||||
| **Спринт 2** | **C** + начало D при наличии LLM; иначе D без генерации = только текст/ручной ввод |
|
||||
| Далее | E, F, G, интеграция MAX, уведомления |
|
||||
|
||||
---
|
||||
|
||||
## Сопоставление с файлами
|
||||
|
||||
| Документ | Содержание |
|
||||
| --- | --- |
|
||||
| [card1.md](card1.md) | Задачи Card 1: версии, документ, auth HR |
|
||||
| [sprint-01.md](sprint-01.md) | Спринт 1, кратко |
|
||||
| [task.md](task.md) | ТЗ 1.0 |
|
||||
@@ -0,0 +1,81 @@
|
||||
# Карта задач: Card 1 — история прохождений, документ, авторизация HR
|
||||
|
||||
**Связь со спринтами:** основная масса пунктов **V.x** — **Спринт 1** (версионирование + инфра); **D.x** — загрузка документа (может пересекаться со **Спринтом 2** / AI, если без LLM черновик не делается); **A.x** — авторизация **базой** `Postgres_TG_Bots` (выполнять после/параллельно с V.1, чтобы не плодить дубли пользователей на долгий срок).
|
||||
|
||||
**Фактический стек репозитория [TestingWebApp](../../README.md):** Node.js (backend), PostgreSQL, Docker; фронт — SPA в `frontend/`. План доработок **не** привязывать к FastAPI, если в коде API на Express/Node.
|
||||
|
||||
---
|
||||
|
||||
## Часть 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)
|
||||
|
||||
**Контекст:** в `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 |
|
||||
|
||||
---
|
||||
|
||||
## Порядок работ (рекомендация)
|
||||
|
||||
1. **V.1** → **V.2** → **V.3** (ядро версий).
|
||||
2. **A.1**–**A.3** параллельно или сразу после **V.1** (нужен стабильный логин для стенда).
|
||||
3. **V.4**–**V.9** и UI **V.7**–**V.8**.
|
||||
4. **D.*** после появления клиента LLM (или D.1–D.2 + ручной встав текста без LLM).
|
||||
5. **V.10** — решение по назначениям до **V.5** если назначения уже в проде.
|
||||
|
||||
---
|
||||
|
||||
## Ссылки
|
||||
|
||||
- ТЗ: [task.md](task.md) §4.1, §4.2
|
||||
- Спринт 1: [sprint-01.md](sprint-01.md)
|
||||
- Тестирование: [sprint-01-testing.md](sprint-01-testing.md)
|
||||
- Анализ таблиц (если ведёте): [TEST_TABLES_ANALYSIS.md](../TEST_TABLES_ANALYSIS.md)
|
||||
@@ -0,0 +1,55 @@
|
||||
# Спринт 1 — Редактор тестов: версионирование (desktop web)
|
||||
|
||||
**Формат:** отдельное веб desktop-приложение (согласно ТЗ `task.md`, этап 1; приёмка руководителями подразделений).
|
||||
**Граница спринта:** **до** готовой цепочки **версий** теста, **привязки попыток** к версии, **UI** списков/истории/смены активной версии и **деактивации** цепочки.
|
||||
**Детальная нарезка и правила приёмки:** [card1.md](card1.md) (части **V.x**, **A.x** по мере готовности).
|
||||
|
||||
**Дизайн:** не отходить от визуального языка внутренних веб-экранов клиники (типографика, отступы, таблицы, модалки).
|
||||
|
||||
**Стек (факт по репозиторию [TestingWebApp](../../README.md)):** **Node.js** (API в `backend/`), **PostgreSQL**, **Docker**; фронтенд **desktop-first** SPA. Интеграция с [HR_TG_Bot](../../../HR_TG_Bot/README.md) / экосистемой — по готовности API-контрактов, **не** обязана совпадать с FastAPI, если в этом репо бэкенд на Node. При переносе на Python — пересмотреть только слой API, **смысл** [card1.md](card1.md) не меняется.
|
||||
|
||||
---
|
||||
|
||||
## Цель спринта
|
||||
|
||||
Реализовать **§4.1 ТЗ** (версионирование) end-to-end: модель данных, бизнес-правила, API, UI автора, поведение для сотрудника и разбора **старых** результатов.
|
||||
|
||||
---
|
||||
|
||||
## Функциональные критерии готовности (из ТЗ 4.1)
|
||||
|
||||
1. Пока по тесту **не было попыток** — автор редактирует **на месте**, номер версии **не** инкрементируется.
|
||||
2. После **первой** попытки каждое сохранение изменений создаёт **новую** версию (`version + 1`, связь `parent_id`), предыдущая версия **неактивна**, данные **сохраняются**.
|
||||
3. Попытки привязаны к **конкретной** версии; разбор старых попыток **валиден** после правок.
|
||||
4. В списках — **только одна** активная версия цепочки.
|
||||
5. **История версий** + **ручная** смена активной версии; остальные — неактивны.
|
||||
6. Тест можно **деактивировать** целиком (скрыть из списков, **без** удаления данных).
|
||||
|
||||
---
|
||||
|
||||
## Технические подзадачи (этапы внутри спринта)
|
||||
|
||||
| # | Задача | См. в card1 |
|
||||
| --- | --- | --- |
|
||||
| 1 | Миграция: `parent_id`, инвариант «одна активная версия на `test_id`», флаг цепочки (деактивация) | V.1, V.6 |
|
||||
| 2 | Сервис: «0 попыток — in-place; иначе — fork + копия вопросов» | V.2, V.3 |
|
||||
| 3 | Попытка: `test_version_id` фиксируется **на старте**; не перезаписывается | V.4 |
|
||||
| 4 | API: CRUD с версиями; переключение активной; деактивация; списки без дублей | V.5, V.6, V.10 |
|
||||
| 5 | UI: версия, история, смена активной, списки | V.7, V.8 |
|
||||
| 6 | Тесты: unit + integration, регресс разбора | V.9 |
|
||||
|
||||
**Авторизация на БД [Postgres_TG_Bots](../../../Postgres_TG_Bots):** [card1.md](card1.md) **A.1**–**A.5** — **в рамке спринта 1**, если согласовано (иначе — отдельной задачей сразу после V.1).
|
||||
|
||||
**Загрузка документа → тест:** [card1.md](card1.md) **D.1**–**D.5** — **вне** замыкания **только** на версии; может пойти **после** V.3 или параллельно, зависит от **LLM** (§4.2).
|
||||
|
||||
---
|
||||
|
||||
## Вне спринта 1 (как в ТЗ)
|
||||
|
||||
- Полный **AI-**модуль (§4.2) сверх **импорта** из карточки, **медиа** (§4.3), **подсказки** (§4.4), **режимы** (§4.5), **дашборды** (этап 2).
|
||||
|
||||
---
|
||||
|
||||
## Документ тестирования
|
||||
|
||||
Чек-лист: [sprint-01-testing.md](sprint-01-testing.md).
|
||||
@@ -0,0 +1,252 @@
|
||||
# Техническое задание на доработку
|
||||
|
||||
**Система тестирования сотрудников клиники**
|
||||
|
||||
| Поле | Значение |
|
||||
| --- | --- |
|
||||
| Версия | 1.0 |
|
||||
| Дата | 2026-04-23 |
|
||||
| Статус | Черновик |
|
||||
| Адресат | Константин Л. (разработчик) |
|
||||
| Базовый репозиторий | https://git.pirogov.ai/l_konstantin/TestingWebApp |
|
||||
|
||||
## 1. Контекст и зачем это делается
|
||||
|
||||
### Зачем клинике система тестирования
|
||||
|
||||
Система нужна, чтобы сделать проверку знаний сотрудников управляемым процессом, а не бумажной рутиной. Сегодня проверка знаний по регламентам, стандартам работы с пациентами, новым протоколам и внутренним правилам проходит устно или на бумаге — это тяжело воспроизводить, невозможно сравнивать результаты между людьми и отделами, а руководитель не видит целостной картины по своему подразделению.
|
||||
|
||||
### Что система даёт каждой роли
|
||||
|
||||
- **Руководителю подразделения** — единое место, где видно, кто из сотрудников прошёл обязательные тесты, кто не справился, у кого приближается дедлайн. Вместо рассылки регламентов «в чат и на почту» — проверяемая практика: назначил тест → увидел результат → понял, где у отдела пробелы. AI-помощник снимает главный барьер: придумать и сформулировать хороший тест — это отдельная работа, которой у руководителя обычно нет времени. С помощником создание теста занимает минуты, а не часы.
|
||||
|
||||
- **Сотруднику** — понятный личный кабинет: какие тесты назначены, когда сдать, какой результат был в прошлый раз, какие ошибки стоит разобрать. Разбор ошибок после теста превращает проверку в короткий обучающий цикл. Если автор составит задорный тест — с живыми формулировками, неочевидными вариантами ответов, лёгким юмором, — прохождение перестаёт восприниматься как рутинная формальность и приобретает элементы фана и геймификации. Это снижает сопротивление и делает регулярные тесты нормальной частью рабочего дня.
|
||||
|
||||
- **Директору и его помощнику** — объективная картина по всей клинике: какие подразделения сильнее, какие отстают, где нужно вмешательство. Это инструмент управленческих решений по обучению и кадрам, а не просто отчётность.
|
||||
|
||||
- **HR** — структурированная история знаний каждого сотрудника, которая в будущем ляжет в общий HR-контур (онбординг, индивидуальные планы развития, кадровые решения).
|
||||
|
||||
### Стратегическая роль: точка входа в HR-приложение в MAX
|
||||
|
||||
У модуля тестирования есть ещё одна важная роль — он становится одной из первых регулярно используемых частей общего HR-приложения в боте MAX. Тесты назначаются регулярно и требуют обязательного прохождения, а значит, сотрудник будет заходить в HR-приложение не время от времени, а стабильно. Это формирует привычку: открыть HR в MAX — привычное действие. Следом подтянутся и другие HR-сервисы (справочная информация, заявки, графики, отпуска, обратная связь), которые без точки притяжения могли бы оставаться «пустым модулем». Таким образом, система тестирования популяризует само HR-приложение внутри MAX и помогает ему стать ежедневным рабочим инструментом, а не редко открываемым разделом.
|
||||
|
||||
Отдельно важен формат взаимодействия. Внутри бота MAX система тестирования открывается как полноценное веб-приложение (мини-приложение) — с нормальной вёрсткой форм, навигацией, медиа в вопросах, удобными таблицами результатов. Это принципиально лучший пользовательский опыт, чем предыдущая реализация в Telegram, где интерфейс был ограничен форматом бота (сообщения, кнопки, линейные диалоги) и не давал ни удобного ввода, ни нормального отображения сложного контента. Перевод в веб-формат внутри MAX — это не просто смена канала, а качественный скачок в удобстве работы с тестами для всех ролей.
|
||||
|
||||
### Текущее состояние
|
||||
|
||||
Уже реализовано: авторизация по логину/паролю, создание тестов автором, назначение теста сотрудникам из списка, прохождение теста сотрудником в браузере.
|
||||
|
||||
Доработка расширяет эту реализацию новыми возможностями и готовит её к встраиванию в общую HR-систему клиники. В HR-системе уже есть собственная авторизация и собственная система разграничения прав (кто какие разделы и данные видит), поэтому на более поздних этапах собственная авторизация модуля тестирования будет отключена в пользу HR-авторизации. До этого момента текущая авторизация используется как есть.
|
||||
|
||||
## 2. Ключевые дополнительные возможности
|
||||
|
||||
Помимо базового функционала (создание тестов, назначение, прохождение), который уже реализован, в этой доработке добавляются пять возможностей, радикально расширяющих ценность системы. Они перечислены в порядке значимости для пользователя.
|
||||
|
||||
### 2.1. AI-помощники при создании тестов — ключевая возможность
|
||||
|
||||
Это главный выигрыш всей доработки. Создание теста с нуля — это отдельная работа: нужно придумать вопросы, сформулировать варианты ответов, подобрать неочевидные неправильные ответы (дистракторы), проверить качество формулировок. У руководителя подразделения этого времени обычно нет. Без AI-помощника сама задача «писать тесты регулярно» фактически невыполнима — она превращается в проект.
|
||||
|
||||
AI-помощник меняет это кардинально:
|
||||
|
||||
- **Сокращение времени в разы.** Вместо нескольких часов ручной работы — несколько минут на редактирование черновика, который сгенерировал AI.
|
||||
- **Более удобный формат работы.** Автор не пишет с пустого листа, а работает в режиме редактора: получает готовое, правит, подтверждает. Отдельные кнопки позволяют улучшить конкретный вопрос, добавить дистракторы, сгенерировать подсказку, проверить весь тест на качество.
|
||||
- **Выше качество формулировок.** AI предлагает варианты, о которых автор мог не подумать — правдоподобные дистракторы, более чёткие формулировки, корректную подсказку.
|
||||
|
||||
Без этой возможности регулярное создание тестов останется узким местом и система не заработает в полную силу. С ней — создание теста становится быстрой повседневной операцией, которую может делать любой руководитель.
|
||||
|
||||
### 2.2. Версионирование тестов
|
||||
|
||||
Руководитель может править тест после первых прохождений, не теряя корректность старых результатов. Старые попытки по-прежнему корректно разбираются по той версии теста, которая была на момент их прохождения.
|
||||
|
||||
### 2.3. Медиа в вопросах
|
||||
|
||||
К вопросу можно прикрепить изображение или видео: фото инструмента, рентгеновский снимок, ролик с правильной техникой манипуляции. Тесты перестают быть «только про текст» — это особенно важно в медицинской тематике.
|
||||
|
||||
### 2.4. Подсказки и режимы прохождения (таймер, мгновенная оценка)
|
||||
|
||||
Один и тот же тест можно проводить как строгую проверку (с таймером, без подсказок, итог в конце) или как мягкий обучающий тренажёр (с подсказками, без таймера, мгновенная обратная связь по каждому вопросу). Набор режимов — независимые настройки, автор комбинирует их под задачу.
|
||||
|
||||
### 2.5. Дашборды для всех ролей
|
||||
|
||||
Замена ручного сбора статистики на один экран с нужным срезом: сотрудник видит свои тесты и историю, руководитель — своё подразделение, директор — всю клинику с возможностью посмотреть любое подразделение и любого сотрудника.
|
||||
|
||||
## 3. Этапы
|
||||
|
||||
| № | Этап | Формат | Кто принимает |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | Доработка редактора тестов | Web desktop | Руководители подразделений |
|
||||
| 2 | Дашборды (сотрудника / руководителя / директора) | Web desktop | Руководители подразделений + директор |
|
||||
| 3 | Интеграция с HR-системой | Backend-интеграция + изменения авторизации | Совместно с командой HR |
|
||||
| 4 | Адаптация под мини-приложение в боте MAX | Mini-app | Совместно с командой HR |
|
||||
| 5 | Уведомления | В рамках общей системы HR | Совместно с командой HR |
|
||||
|
||||
Этапы 1 и 2 реализуются как отдельные desktop-приложения и принимаются независимо друг от друга. Этапы 3–5 выполняются позже, совместно с командой большой HR-системы — в этом ТЗ описаны верхнеуровнево.
|
||||
|
||||
## 4. Этап 1 — Доработка редактора тестов
|
||||
|
||||
Этап расширяет существующий редактор пятью возможностями. Все пять — независимые фичи, могут реализовываться в любом порядке и приниматься отдельно.
|
||||
|
||||
### 4.1. Версионирование тестов
|
||||
|
||||
**Цель:** сохранить корректность истории прохождений, когда автор правит тест после первых попыток.
|
||||
|
||||
**Правила:**
|
||||
|
||||
- Пока по тесту не было ни одной попытки — автор редактирует тест на месте, номер версии не меняется.
|
||||
- Как только появилась хотя бы одна попытка — любое сохранение изменений создаёт новую версию теста (`version + 1`, связь со старой версией через `parent_id`). Старая версия становится неактивной, но сохраняется в базе.
|
||||
- Все версии теста связаны в цепочку. Каждая попытка прохождения привязана к конкретной версии, по которой сотрудник проходил тест, — разбор ошибок по старым результатам остаётся корректным даже после того, как автор изменил тест.
|
||||
- В списке тестов для сотрудников и авторов показывается только одна активная версия каждой цепочки.
|
||||
- Автор может открыть историю версий теста и вручную переключить активную версию на любую другую из цепочки — остальные при этом автоматически становятся неактивными.
|
||||
- Тест можно деактивировать целиком (скрыть всю цепочку из списка, данные не удаляются).
|
||||
|
||||
### 4.2. AI-помощник при создании и редактировании тестов
|
||||
|
||||
**Цель:** ускорить и повысить качество создания тестов силами LLM.
|
||||
|
||||
**Интеграция:**
|
||||
|
||||
- Используется DeepSeek API (совместим с форматом OpenAI — подключается через библиотеку `openai` с `base_url=https://api.deepseek.com`, модель `deepseek-chat`).
|
||||
- Для структурированных ответов использовать `response_format={"type": "json_object"}`.
|
||||
- API-ключ DeepSeek вводится на отдельной странице настроек (`/settings`) и хранится в БД. На фронтенд ключ не передаётся.
|
||||
- На странице настроек — кнопка «Проверить подключение», которая выполняет тестовый запрос к API.
|
||||
- Все AI-функции требуют настроенного ключа; при его отсутствии возвращается понятная ошибка со ссылкой на «Настройки».
|
||||
|
||||
**Функции уровня всего теста:**
|
||||
|
||||
| Функция | Описание |
|
||||
| --- | --- |
|
||||
| Сгенерировать тест | По названию теста AI генерирует набор вопросов с вариантами ответов. Кнопка доступна только когда название заполнено. Результат показывается в превью, автор применяет его целиком. |
|
||||
| Проверить тест | AI анализирует весь тест и выдаёт рекомендации по улучшению (чёткость формулировок, качество дистракторов, охват темы). Показывается в модальном окне. |
|
||||
| Предложить улучшение всего теста | AI предлагает улучшенные формулировки всех вопросов и ответов. Результат отображается как постатейное сравнение (было → стало) с чекбоксами — автор выбирает, какие изменения применить. |
|
||||
|
||||
**Функции уровня одного вопроса:**
|
||||
|
||||
| Функция | Описание |
|
||||
| --- | --- |
|
||||
| Улучшить вопрос | AI переформулирует выбранный вопрос и его варианты ответов. Результат показывается в модальном окне с постатейным сравнением и чекбоксами (вопрос + каждый вариант отдельно). Прямая замена без подтверждения не допускается. |
|
||||
| Дистракторы | AI генерирует 3 новых правдоподобных неправильных варианта ответа. Они добавляются к существующим, а не заменяют их. |
|
||||
| Сгенерировать подсказку | AI пишет подсказку к вопросу (см. раздел 4.4). Автор может отредактировать или переписать полученный текст. |
|
||||
|
||||
### 4.3. Медиа в вопросах
|
||||
|
||||
**Цель:** к вопросу можно прикрепить изображение или видео, которое сотрудник увидит при прохождении.
|
||||
|
||||
**Требования:**
|
||||
|
||||
- К одному вопросу может быть прикреплён один медиа-файл (изображение или видео).
|
||||
- **Поддерживаемые форматы:** изображения: JPG, PNG, WebP; видео: MP4, WebM.
|
||||
- **Ограничения по размеру:** изображение — до 5 МБ; видео — до 50 МБ.
|
||||
- Файлы хранятся локально на сервере (например, в папке `uploads/`). Внешние хранилища (S3/MinIO) не используются.
|
||||
- В редакторе вопроса — отдельное поле «Медиа» с загрузкой файла и превью, кнопкой удаления.
|
||||
- При прохождении теста медиа отображается над текстом вопроса. Видео — с нативным плеером браузера.
|
||||
- Имена файлов на диске должны быть непредсказуемыми (например, UUID), чтобы исключить угадывание ссылок.
|
||||
|
||||
### 4.4. Подсказки к вопросам
|
||||
|
||||
**Цель:** при прохождении теста в режиме с подсказками сотрудник может запросить подсказку к вопросу.
|
||||
|
||||
**Требования:**
|
||||
|
||||
- Каждый вопрос имеет одно необязательное текстовое поле «Подсказка».
|
||||
- Заполнение подсказки — на усмотрение автора. Три способа:
|
||||
1. Автор пишет подсказку вручную.
|
||||
2. Автор нажимает «Сгенерировать подсказку» — AI генерирует текст подсказки; автор может сохранить как есть, отредактировать или удалить.
|
||||
3. Оставить поле пустым — подсказки по этому вопросу не будет даже в режиме с подсказками.
|
||||
- Подсказка показывается сотруднику только если тест запущен в режиме с подсказками (см. 4.5) и автор её заполнил.
|
||||
|
||||
### 4.5. Режимы прохождения теста
|
||||
|
||||
**Цель:** автор при создании теста выбирает, как именно сотрудник будет его проходить.
|
||||
|
||||
Три независимых настройки теста (устанавливаются при создании, сохраняются в версии теста):
|
||||
|
||||
| Настройка | Варианты | Поведение при прохождении |
|
||||
| --- | --- | --- |
|
||||
| Подсказки | Включены / выключены | Если включены и у вопроса заполнена подсказка — сотруднику доступна кнопка «Показать подсказку» под вопросом. Факт использования подсказки фиксируется в попытке (в будущем может влиять на балл). |
|
||||
| Таймер | Выключен / N минут | Если задан — отображается обратный отсчёт. По истечении — тест автоматически завершается, попытка считается сданной с тем, что ответил сотрудник. |
|
||||
| Мгновенная оценка | Включена / выключена | Если включена — после ответа на каждый вопрос сразу показывается правильный ответ и комментарий (разбор по этому вопросу), затем переход к следующему. Если выключена — разбор и итог только после завершения всего теста. |
|
||||
|
||||
Настройки отображаются на странице прохождения так, чтобы сотрудник заранее понимал условия (есть ли таймер, будет ли сразу виден правильный ответ и т. д.).
|
||||
|
||||
## 5. Этап 2 — Дашборды
|
||||
|
||||
**Цель:** предоставить каждой роли индивидуальный экран с релевантной для неё информацией. Этап реализуется отдельным desktop-приложением (или отдельным разделом того же приложения — на усмотрение разработчика).
|
||||
|
||||
### 5.1. Дашборд сотрудника
|
||||
|
||||
Что видит сотрудник на своей главной странице:
|
||||
|
||||
- **Назначенные тесты** — таблица или карточки со статусом (Не начат, В процессе, Завершён, Просрочен) и датой дедлайна.
|
||||
- **График дедлайнов** — визуализация (таймлайн или календарь) по ближайшим срокам сдачи.
|
||||
- **История попыток** — все попытки сотрудника: тест, версия, дата начала/завершения, результат, зачёт/незачёт.
|
||||
- Из строки истории — переход на разбор ошибок конкретной попытки.
|
||||
|
||||
### 5.2. Дашборд руководителя подразделения
|
||||
|
||||
Что видит руководитель подразделения — только по своему подразделению:
|
||||
|
||||
- **Сводка по сотрудникам:** список сотрудников с колонками — назначено тестов / сдано / просрочено / средний балл. По клику на сотрудника — его история попыток и назначенных тестов.
|
||||
- **Сводка по назначенным тестам:** по каждому тесту, назначенному подразделению — процент сдавших, список сдавших и несдавших.
|
||||
- **Фильтры:** по диапазону дат, по конкретному тесту.
|
||||
|
||||
### 5.3. Дашборд директора и помощника директора
|
||||
|
||||
Что видят директор и его помощник — по всей клинике:
|
||||
|
||||
- **Общая сводка:** число активных тестов, число сотрудников, общий процент сдачи, средний балл.
|
||||
- **Сравнение подразделений:** таблица подразделений с колонками — число сотрудников, процент сдачи, средний балл. Сортировка по любой колонке. По клику на подразделение открывается вид как у руководителя этого подразделения (см. 5.2).
|
||||
- По клику на сотрудника (из любого уровня) — его история попыток.
|
||||
|
||||
## 6. Этап 3 — Интеграция с HR-системой
|
||||
|
||||
**Цель:** модуль тестирования становится частью большой HR-системы клиники.
|
||||
|
||||
**Ключевые изменения:**
|
||||
|
||||
- Собственная авторизация модуля тестирования отключается. Вход выполняется через HR (SSO, JWT или другой механизм, который будет определён командой HR).
|
||||
- Пользователи, подразделения и роли приходят из HR — не хранятся в локальной БД модуля тестирования (или хранятся как кэш, синхронизируемый с HR).
|
||||
- Разграничение прав доступа (кто что видит и что может делать) выполняется по ролям, приходящим из HR. Соответствие ролей HR-системы и возможностей модуля тестирования определяется отдельно в начале этапа.
|
||||
- Назначение тестов остаётся внутри модуля тестирования (а не в HR). Это отдельный пользовательский сценарий, который удобнее оставить рядом с редактором и трекером.
|
||||
- Дашборды используют ФИО, подразделения и иерархию из HR.
|
||||
|
||||
Детальные контракты (API HR, формат токена, справочники) будут описаны отдельным документом совместно с командой HR перед стартом этапа.
|
||||
|
||||
## 7. Этап 4 — Мини-приложение для бота MAX
|
||||
|
||||
**Цель:** сотрудник может проходить назначенные тесты прямо из бота MAX, без перехода в браузер.
|
||||
|
||||
**Верхнеуровневые требования:**
|
||||
|
||||
- Desktop-интерфейс сотрудника адаптируется под размер мини-приложения MAX (адаптивная вёрстка, упрощённая навигация, без многоуровневого меню).
|
||||
- Внутри мини-приложения доступны: список назначенных тестов, прохождение теста, результат и разбор ошибок.
|
||||
- Функции авторов тестов и руководителей в mini-app не выносятся — для них остаётся полноценный desktop-интерфейс.
|
||||
- Авторизация в mini-app — через MAX → HR (конкретная схема определяется на старте этапа).
|
||||
|
||||
## 8. Этап 5 — Уведомления
|
||||
|
||||
Реализуются в рамках общей системы уведомлений большой HR-системы, а не как отдельный модуль системы тестирования.
|
||||
|
||||
**События**, которые должна знать система тестирования и передавать в общую систему уведомлений:
|
||||
|
||||
- Сотруднику назначен новый тест.
|
||||
- Приближается дедлайн сдачи теста (за N дней, N — настраивается).
|
||||
- Дедлайн теста просрочен без сдачи.
|
||||
|
||||
Канал (MAX / e-mail / другое) и формат сообщений определяются общей системой HR.
|
||||
|
||||
## 9. Вне scope
|
||||
|
||||
В рамках этой доработки не реализуются:
|
||||
|
||||
- Экспорт отчётов в Excel / PDF.
|
||||
- Собственная система уведомлений внутри модуля тестирования — уведомления будут реализованы в общей HR-системе.
|
||||
|
||||
## 10. Порядок приёмки
|
||||
|
||||
Общий принцип: каждый этап принимается отдельно. Следующий этап не начинается, пока предыдущий не принят.
|
||||
|
||||
1. **Этап 1** — по мере готовности каждой из пяти функций (4.1–4.5) руководители подразделений вручную проходят по ней сценарии использования, заводят замечания, разработчик их исправляет. Этап принят, когда все пять функций прошли приёмку.
|
||||
2. **Этап 2** — дашборды тестируются по ролям: сотрудник → руководитель подразделения → директор. Проверяется, что каждая роль видит только разрешённые данные и что переходы между уровнями (клиника → подразделение → сотрудник) работают корректно.
|
||||
3. **Этапы 3–5** — приёмка проводится совместно с командой большой HR-системы, критерии и сценарии определяются в начале каждого этапа.
|
||||
|
||||
Подробные чек-листы тестирования для каждой функции готовятся перед стартом соответствующего этапа и ведутся в отдельных документах в папке DOC/.
|
||||
Reference in New Issue
Block a user