commit
b42a3c3d55
14 changed files with 910 additions and 0 deletions
Binary file not shown.
Binary file not shown.
@ -0,0 +1,163 @@
|
||||
# Техническое задание |
||||
## Система тестирования сотрудников клиники |
||||
|
||||
**Версия:** 1.2 |
||||
**Дата:** 2026-03-21 |
||||
**Статус:** Согласовано |
||||
|
||||
--- |
||||
|
||||
## 1. Назначение системы |
||||
|
||||
Веб-приложение для проведения внутреннего тестирования сотрудников клиники. Руководители подразделений и HR-менеджер создают тесты и назначают их сотрудникам. Сотрудники проходят тесты в браузере. Система фиксирует все попытки и результаты. |
||||
|
||||
--- |
||||
|
||||
## 2. Роли и права доступа |
||||
|
||||
| Роль | Кто | Создаёт тесты | Назначает тесты | Видит результаты | |
||||
|------|-----|:---:|:---:|:---:| |
||||
| **HR-менеджер** | Руководитель службы HR, Директор клиники | ✅ | Всем сотрудникам клиники | Всех сотрудников | |
||||
| **Руководитель подразделения** | Главный врач, рук. службы администраторов и др. | ✅ | Только своему подразделению | Только своего подразделения | |
||||
| **Сотрудник** | Все остальные работники | ❌ | ❌ | Только свои | |
||||
|
||||
--- |
||||
|
||||
## 3. Авторизация |
||||
|
||||
- Вход по логину и паролю |
||||
- Учётные записи создаются администратором системы вручную |
||||
- Сессия хранится на сервере (cookie-based или JWT — определить при выборе стека) |
||||
- Пароль хранится в зашифрованном виде (bcrypt или аналог) |
||||
|
||||
--- |
||||
|
||||
## 4. Функциональные требования |
||||
|
||||
### 4.1. Управление пользователями и подразделениями |
||||
|
||||
- Создание/редактирование/деактивация учётных записей сотрудников |
||||
- Каждый сотрудник принадлежит одному подразделению |
||||
- Создание/редактирование справочника подразделений |
||||
- Назначение роли сотруднику: HR-менеджер / Руководитель подразделения / Сотрудник |
||||
|
||||
### 4.2. Создание и редактирование тестов |
||||
|
||||
**Тест содержит:** |
||||
- Название теста |
||||
- Описание (опционально) |
||||
- Список вопросов (минимум 7) |
||||
- Порог зачёта — минимальный % правильных ответов (задаётся автором) |
||||
- Таймер прохождения — лимит в минутах (опционально) |
||||
|
||||
**Вопрос содержит:** |
||||
- Текст вопроса |
||||
- Минимум 3 варианта ответа |
||||
- Один или несколько правильных ответов (чекбокс или радио-кнопка в зависимости от типа) |
||||
|
||||
**Настройки теста (задаются автором при создании):** |
||||
- Разрешить возврат к предыдущему вопросу: да / нет |
||||
|
||||
**Правила работы с тестом:** |
||||
- Автор может редактировать тест пока никто его не проходил |
||||
- Если тест уже проходили — создаётся новая версия (`version + 1`), старая сохраняется |
||||
- Все версии теста хранятся; результаты привязаны к конкретной версии |
||||
- Активная версия — та, которую видят сотрудники; автор может вручную переключить активную версию |
||||
- Тест можно деактивировать (скрыть из списка, не удалять) |
||||
|
||||
### 4.3. Назначение теста |
||||
|
||||
При назначении задаются: |
||||
- Список получателей (отдел или конкретные сотрудники) |
||||
- Срок сдачи — дата дедлайна (задаётся в днях от даты назначения или конкретной датой) |
||||
- Допустимое количество попыток (1 или более — задаётся при назначении) |
||||
|
||||
HR-менеджер может назначить тест сотрудникам любых подразделений. |
||||
Руководитель подразделения — только сотрудникам своего подразделения. |
||||
|
||||
### 4.4. Прохождение теста (интерфейс сотрудника) |
||||
|
||||
- На главной странице сотрудник видит список назначенных ему тестов со статусами: |
||||
- `Не начат` — ещё не открывал |
||||
- `В процессе` — начал, не завершил (если таймер — отсчёт продолжается) |
||||
- `Завершён` — сдал/не сдал |
||||
- `Просрочен` — дедлайн прошёл, не сдан |
||||
- Если задан таймер — отображается обратный отсчёт, по истечении тест завершается автоматически |
||||
- Порядок вопросов **случайный** при каждом прохождении |
||||
- Возможность вернуться к предыдущему вопросу — определяется настройкой теста |
||||
|
||||
### 4.5. Результаты после завершения теста |
||||
|
||||
Сотрудник сразу после сдачи видит: |
||||
- Итоговый балл и процент правильных ответов |
||||
- Факт зачёта: **сдал / не сдал** (относительно порога) |
||||
- Разбор ошибок: по каждому вопросу — его ответ и правильный ответ |
||||
|
||||
### 4.6. Трекер попыток |
||||
|
||||
Система фиксирует каждую попытку прохождения теста: |
||||
|
||||
| Поле | Описание | |
||||
|------|----------| |
||||
| Сотрудник | ФИО, подразделение | |
||||
| Тест | Название | |
||||
| Попытка № | Порядковый номер попытки | |
||||
| Начало | Дата и время начала | |
||||
| Завершение | Дата и время окончания | |
||||
| Результат | Количество правильных ответов / всего, % | |
||||
| Зачёт | Да / Нет (преодолён ли порог) | |
||||
|
||||
Руководитель видит трекер по своему подразделению. |
||||
HR-менеджер видит трекер по всей клинике. |
||||
Сотрудник видит только свои попытки. |
||||
|
||||
### 4.7. AI-помощник при создании и редактировании тестов |
||||
|
||||
Интеграция с LLM (DeepSeek) доступна авторам тестов в форме создания и редактирования. |
||||
|
||||
**Функции AI-помощника:** |
||||
|
||||
| Функция | Описание | |
||||
|---------|----------| |
||||
| Генерация теста | Автор вводит тему — AI генерирует готовый набор вопросов с вариантами ответов | |
||||
| Улучшение формулировки | AI переформулирует выбранный вопрос более чётко и однозначно | |
||||
| Добавление дистракторов | AI генерирует правдоподобные неправильные варианты ответов к вопросу | |
||||
| Проверка качества | AI анализирует весь тест и выдаёт рекомендации по улучшению | |
||||
|
||||
**Настройки:** |
||||
- API-ключ DeepSeek вводится на странице `/settings` и хранится в базе данных |
||||
- Страница настроек содержит кнопку «Проверить подключение» — выполняет тестовый запрос к API |
||||
- Ключ хранится только на бэкенде и не передаётся на фронтенд |
||||
|
||||
--- |
||||
|
||||
## 5. Нефункциональные требования |
||||
|
||||
| Параметр | Требование | |
||||
|----------|-----------| |
||||
| Количество пользователей | 50–200 человек | |
||||
| Платформа | Веб-приложение, браузер (desktop-first) | |
||||
| Доступность | Внутренняя сеть клиники | |
||||
| Язык интерфейса | Русский | |
||||
| Время отклика | < 2 секунды для основных операций | |
||||
|
||||
--- |
||||
|
||||
## 6. Уведомления |
||||
|
||||
Уведомления реализуются в одном из последних спринтов. |
||||
|
||||
- Канал: мессенджер **MAX** |
||||
- События для уведомления: |
||||
- Сотруднику назначен новый тест |
||||
- Приближается дедлайн сдачи теста |
||||
- Интеграция с MAX API — отдельная задача спринта |
||||
|
||||
--- |
||||
|
||||
## 7. Вне scope (не реализуем в данной версии) |
||||
|
||||
- Интеграция с AD/LDAP |
||||
- Мобильное приложение |
||||
- Вопросы с вложениями (изображения, видео) |
||||
- Экспорт отчётов в Excel / PDF |
||||
@ -0,0 +1,44 @@
|
||||
# Шаг 1: Проект и инфраструктура |
||||
|
||||
## Цель |
||||
|
||||
Создать базовую структуру проекта, настроить окружение разработки и выбрать технологический стек. |
||||
|
||||
--- |
||||
|
||||
## Задачи |
||||
|
||||
### 1.1. Выбор технологического стека |
||||
|
||||
| Компонент | Выбор | |
||||
|-----------|-------| |
||||
| Backend | Node.js + Express или Python + FastAPI | |
||||
| Frontend | React / Vue.js (SPA) | |
||||
| Database | PostgreSQL | |
||||
| Session | JWT (токен в cookie) | |
||||
| Password | bcrypt | |
||||
|
||||
### 1.2. Инициализация проекта |
||||
|
||||
- Создать репозиторий |
||||
- Настроить структуру папок (backend / frontend) |
||||
- Настроить Git workflow |
||||
|
||||
### 1.3. Настройка окружения |
||||
|
||||
- Docker Compose для PostgreSQL |
||||
- Переменные окружения (.env) |
||||
- Настройка линтеров и форматтеров |
||||
|
||||
### 1.4. Базовая структура API |
||||
|
||||
- Настроить Express/FastAPI сервер |
||||
- Подключить базу данных |
||||
- Создать базовые роуты health check |
||||
|
||||
--- |
||||
|
||||
## Результат |
||||
|
||||
- Работающий сервер с подключением к БД |
||||
- Структура проекта готова для разработки |
||||
@ -0,0 +1,139 @@
|
||||
# Шаг 2: Проектирование базы данных |
||||
|
||||
## Цель |
||||
|
||||
Спроектировать и создать структуру базы данных для хранения всех сущностей системы. |
||||
|
||||
--- |
||||
|
||||
## Задачи |
||||
|
||||
### 2.1. Сущности базы данных |
||||
|
||||
#### Таблица: `departments` (Подразделения) |
||||
|
||||
| Поле | Тип | Описание | |
||||
|------|-----|----------| |
||||
| id | UUID | PK | |
||||
| name | VARCHAR(255) | Название подразделения | |
||||
| created_at | TIMESTAMP | Дата создания | |
||||
| updated_at | TIMESTAMP | Дата обновления | |
||||
|
||||
#### Таблица: `users` (Пользователи) |
||||
|
||||
| Поле | Тип | Описание | |
||||
|------|-----|----------| |
||||
| id | UUID | PK | |
||||
| login | VARCHAR(100) | Уникальный логин | |
||||
| password_hash | VARCHAR(255) | Хеш пароля | |
||||
| full_name | VARCHAR(255) | ФИО | |
||||
| role | ENUM | 'hr', 'manager', 'employee' | |
||||
| department_id | UUID | FK -> departments | |
||||
| is_active | BOOLEAN | Активна ли учётная запись | |
||||
| created_at | TIMESTAMP | Дата создания | |
||||
| updated_at | TIMESTAMP | Дата обновления | |
||||
|
||||
#### Таблица: `tests` (Тесты) |
||||
|
||||
| Поле | Тип | Описание | |
||||
|------|-----|----------| |
||||
| id | UUID | PK | |
||||
| title | VARCHAR(255) | Название теста | |
||||
| description | TEXT | Описание (опционально) | |
||||
| passing_threshold | INTEGER | Порог зачёта (%) | |
||||
| time_limit | INTEGER | Таймер в минутах (nullable) | |
||||
| allow_back | BOOLEAN | Возврат к предыдущему | |
||||
| is_active | BOOLEAN | Активен | |
||||
| is_versioned | BOOLEAN | Есть версии | |
||||
| created_by | UUID | FK -> users | |
||||
| created_at | TIMESTAMP | Дата создания | |
||||
| updated_at | TIMESTAMP | Дата обновления | |
||||
|
||||
#### Таблица: `test_versions` (Версии тестов) |
||||
|
||||
| Поле | Тип | Описание | |
||||
|------|-----|----------| |
||||
| id | UUID | PK | |
||||
| test_id | UUID | FK -> tests | |
||||
| version | INTEGER | Номер версии | |
||||
| is_active | BOOLEAN | Активная версия | |
||||
| created_at | TIMESTAMP | Дата создания | |
||||
|
||||
#### Таблица: `questions` (Вопросы) |
||||
|
||||
| Поле | Тип | Описание | |
||||
|------|-----|----------| |
||||
| id | UUID | PK | |
||||
| test_version_id | UUID | FK -> test_versions | |
||||
| text | TEXT | Текст вопроса | |
||||
| question_order | INTEGER | Порядок вопроса | |
||||
| has_multiple_answers | BOOLEAN | Несколько правильных | |
||||
|
||||
#### Таблица: `answer_options` (Варианты ответов) |
||||
|
||||
| Поле | Тип | Описание | |
||||
|------|-----|----------| |
||||
| id | UUID | PK | |
||||
| question_id | UUID | FK -> questions | |
||||
| text | TEXT | Текст варианта | |
||||
| is_correct | BOOLEAN | Правильный ответ | |
||||
| option_order | INTEGER | Порядок варианта | |
||||
|
||||
#### Таблица: `test_assignments` (Назначения тестов) |
||||
|
||||
| Поле | Тип | Описание | |
||||
|------|-----|----------| |
||||
| id | UUID | PK | |
||||
| test_version_id | UUID | FK -> test_versions | |
||||
| assigned_by | UUID | FK -> users | |
||||
| deadline | DATE | Срок сдачи | |
||||
| max_attempts | INTEGER | Допустимое число попыток | |
||||
| created_at | TIMESTAMP | Дата назначения | |
||||
|
||||
#### Таблица: `test_assignment_targets` (Получатели назначений) |
||||
|
||||
| Поле | Тип | Описание | |
||||
|------|-----|----------| |
||||
| id | UUID | PK | |
||||
| assignment_id | UUID | FK -> test_assignments | |
||||
| target_type | ENUM | 'department', 'user' | |
||||
| target_id | UUID | FK (department или user) | |
||||
|
||||
#### Таблица: `test_attempts` (Попытки прохождения) |
||||
|
||||
| Поле | Тип | Описание | |
||||
|------|-----|----------| |
||||
| id | UUID | PK | |
||||
| test_version_id | UUID | FK -> test_versions | |
||||
| user_id | UUID | FK -> users | |
||||
| attempt_number | INTEGER | Номер попытки | |
||||
| status | ENUM | 'in_progress', 'completed', 'expired' | |
||||
| started_at | TIMESTAMP | Начало | |
||||
| completed_at | TIMESTAMP | Завершение | |
||||
| correct_count | INTEGER | Правильных ответов | |
||||
| total_questions | INTEGER | Всего вопросов | |
||||
| passed | BOOLEAN | Зачёт | |
||||
|
||||
#### Таблица: `user_answers` (Ответы пользователя) |
||||
|
||||
| Поле | Тип | Описание | |
||||
|------|-----|----------| |
||||
| id | UUID | PK | |
||||
| attempt_id | UUID | FK -> test_attempts | |
||||
| question_id | UUID | FK -> questions | |
||||
| selected_options | UUID[] | Выбранные варианты | |
||||
|
||||
#### Таблица: `settings` (Настройки) |
||||
|
||||
| Поле | Тип | Описание | |
||||
|------|-----|----------| |
||||
| key | VARCHAR(100) | PK | |
||||
| value | TEXT | Значение | |
||||
|
||||
--- |
||||
|
||||
## Результат |
||||
|
||||
- Созданы все таблицы с связями |
||||
- Накатанные миграции |
||||
- Схема БД готова |
||||
@ -0,0 +1,56 @@
|
||||
# Шаг 3: Аутентификация и авторизация |
||||
|
||||
## Цель |
||||
|
||||
Реализовать систему входа в систему и разграничения прав доступа. |
||||
|
||||
--- |
||||
|
||||
## Задачи |
||||
|
||||
### 3.1. Аутентификация |
||||
|
||||
- **Эндпоинт:** `POST /api/auth/login` |
||||
- Принимает: `{ login, password }` |
||||
- Возвращает: JWT токен в httpOnly cookie |
||||
- Проверка пароля через bcrypt |
||||
|
||||
### 3.2. Выход |
||||
|
||||
- **Эндпоинт:** `POST /api/auth/logout` |
||||
- Очищает cookie с токеном |
||||
|
||||
### 3.3. Защита роутов (Middleware) |
||||
|
||||
- Проверка валидности JWT |
||||
- Извлечение user_id и роли из токена |
||||
|
||||
### 3.4. Права доступа (RBAC) |
||||
|
||||
| Роль | Доступ | |
||||
|------|--------| |
||||
| HR | Все операции | |
||||
| Manager | Своё подразделение | |
||||
| Employee | Только свои данные | |
||||
|
||||
### 3.5. Middleware авторизации |
||||
|
||||
```javascript |
||||
// Проверка роли |
||||
function requireRole(roles: string[]) { |
||||
// Проверяет, что user.role входит в массив roles |
||||
} |
||||
|
||||
// Проверка подразделения (для manager) |
||||
function requireDepartment(departmentId: string) { |
||||
// Проверяет, что user.department_id === departmentId |
||||
} |
||||
``` |
||||
|
||||
--- |
||||
|
||||
## Результат |
||||
|
||||
- Работающий вход по логину/паролю |
||||
- Защищённые API роуты |
||||
- Разграничение прав по ролям |
||||
@ -0,0 +1,49 @@
|
||||
# Шаг 4: Управление пользователями и подразделениями |
||||
|
||||
## Цель |
||||
|
||||
Реализовать CRUD операции для сотрудников и справочника подразделений. |
||||
|
||||
--- |
||||
|
||||
## Задачи |
||||
|
||||
### 4.1. Управление подразделениями |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/departments` | GET | Список подразделений | |
||||
| `/api/departments` | POST | Создать подразделение | |
||||
| `/api/departments/:id` | PUT | Редактировать | |
||||
| `/api/departments/:id` | DELETE | Деактивировать | |
||||
|
||||
### 4.2. Управление пользователями |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/users` | GET | Список сотрудников | |
||||
| `/api/users` | POST | Создать сотрудника | |
||||
| `/api/users/:id` | GET | Карточка сотрудника | |
||||
| `/api/users/:id` | PUT | Редактировать | |
||||
| `/api/users/:id` | DELETE | Деактивировать | |
||||
|
||||
### 4.3. Фильтрация |
||||
|
||||
- GET `/api/users` поддерживает фильтры: |
||||
- `department_id` — по подразделению |
||||
- `role` — по роли |
||||
- `is_active` — по статусу |
||||
|
||||
### 4.4. Права доступа |
||||
|
||||
- **HR:** полный доступ ко всем пользователям |
||||
- **Manager:** только своё подразделение |
||||
- Создание пользователей — только администратор (ручной ввод) |
||||
|
||||
--- |
||||
|
||||
## Результат |
||||
|
||||
- Админка для управления сотрудниками |
||||
- Справочник подразделений |
||||
- Назначение ролей сотрудникам |
||||
@ -0,0 +1,54 @@
|
||||
# Шаг 5: Управление тестами (админка) |
||||
|
||||
## Цель |
||||
|
||||
Реализовать создание и редактирование тестов с вопросами и версионированием. |
||||
|
||||
--- |
||||
|
||||
## Задачи |
||||
|
||||
### 5.1. CRUD тестов |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/tests` | GET | Список тестов | |
||||
| `/api/tests` | POST | Создать тест | |
||||
| `/api/tests/:id` | GET | Тест с вопросами | |
||||
| `/api/tests/:id` | PUT | Редактировать | |
||||
| `/api/tests/:id` | DELETE | Деактивировать | |
||||
|
||||
### 5.2. Управление вопросами |
||||
|
||||
- Добавление/редактирование вопросов к версии теста |
||||
- Минимум 3 варианта ответа на вопрос |
||||
- Указание одного или нескольких правильных ответов |
||||
- Перетаскивание для изменения порядка (drag & drop) |
||||
|
||||
### 5.3. Версионирование |
||||
|
||||
- При создании теста — версия 1, помечается как активная |
||||
- При редактировании: |
||||
- Если никто не проходил — изменяется текущая версия |
||||
- Если уже были попытки — создаётся новая версия (version + 1) |
||||
- Переключение активной версии вручную |
||||
- Просмотр истории версий |
||||
|
||||
### 5.4. Настройки теста |
||||
|
||||
- `passing_threshold` — порог зачёта (%) |
||||
- `time_limit` — таймер в минутах (опционально) |
||||
- `allow_back` — разрешить возврат к предыдущему вопросу |
||||
|
||||
### 5.5. Права доступа |
||||
|
||||
- **HR, Manager:** могут создавать и редактировать тесты |
||||
- **Employee:** только прохождение |
||||
|
||||
--- |
||||
|
||||
## Результат |
||||
|
||||
- Полноценный конструктор тестов |
||||
- Версионирование с сохранением истории |
||||
- Управление вопросами и ответами |
||||
@ -0,0 +1,50 @@
|
||||
# Шаг 6: Назначение тестов |
||||
|
||||
## Цель |
||||
|
||||
Реализовать функционал назначения тестов сотрудникам и подразделениям. |
||||
|
||||
--- |
||||
|
||||
## Задачи |
||||
|
||||
### 6.1. Назначение теста |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/assignments` | GET | Список назначений | |
||||
| `/api/assignments` | POST | Назначить тест | |
||||
| `/api/assignments/:id` | GET | Детали назначения | |
||||
| `/api/assignments/:id` | PUT | Редактировать | |
||||
| `/api/assignments/:id` | DELETE | Удалить | |
||||
|
||||
### 6.2. Параметры назначения |
||||
|
||||
- `test_version_id` — активная версия теста |
||||
- `deadline` — срок сдачи (дата) |
||||
- `max_attempts` — допустимое количество попыток |
||||
- `targets` — получатели: |
||||
- Тип: `department` или `user` |
||||
- Список ID подразделений/сотрудников |
||||
|
||||
### 6.3. Ограничения |
||||
|
||||
- **HR:** может назначить любому сотруднику любого подразделения |
||||
- **Manager:** может назначить только сотрудникам своего подразделения |
||||
|
||||
### 6.4. API для сотрудника |
||||
|
||||
- **GET** `/api/my-assignments` — список назначенных тестов для текущего пользователя |
||||
- Статусы: |
||||
- `not_started` — не начат |
||||
- `in_progress` — в процессе |
||||
- `completed` — завершён |
||||
- `expired` — просрочен |
||||
|
||||
--- |
||||
|
||||
## Результат |
||||
|
||||
- Назначение тестов подразделениям или сотрудникам |
||||
- Ограничение по дедлайну и попыткам |
||||
- Список назначений для сотрудника |
||||
@ -0,0 +1,72 @@
|
||||
# Шаг 7: Интерфейс прохождения теста |
||||
|
||||
## Цель |
||||
|
||||
Реализовать интерфейс для сотрудника, позволяющий проходить назначенные тесты. |
||||
|
||||
--- |
||||
|
||||
## Задачи |
||||
|
||||
### 7.1. Начало прохождения |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/attempts/start` | POST | Начать попытку | |
||||
| `/api/attempts/:id` | GET | Получить вопросы | |
||||
|
||||
**Логика:** |
||||
- Проверить лимит попыток |
||||
- Создать запись попытки со статусом `in_progress` |
||||
- Перемешать вопросы в случайном порядке |
||||
- Запустить таймер (если задан) |
||||
|
||||
### 7.2. Ответ на вопрос |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/attempts/:id/answers` | POST | Отправить ответ | |
||||
| `/api/attempts/:id/answers` | GET | Получить текущий прогресс | |
||||
|
||||
**Параметры:** |
||||
- `question_id` — ID вопроса |
||||
- `selected_options` — массив ID выбранных вариантов |
||||
|
||||
### 7.3. Навигация |
||||
|
||||
- Переход к следующему вопросу |
||||
- Возврат к предыдущему (если `allow_back = true`) |
||||
- Переход к конкретному вопросу по номеру |
||||
|
||||
### 7.4. Завершение теста |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/attempts/:id/complete` | POST | Завершить тест | |
||||
|
||||
**Логика:** |
||||
- Проверить ответы на все вопросы |
||||
- Подсчитать правильные ответы |
||||
- Вычислить процент |
||||
- Сравнить с порогом зачёта |
||||
- Обновить статус попытки на `completed` |
||||
|
||||
### 7.5. Таймер |
||||
|
||||
- Обратный отсчёт на фронтенде |
||||
- При истечении — автоматическое завершение |
||||
- Проверка на бэкенде при отправке ответа |
||||
|
||||
### 7.6. Обработка просрочки |
||||
|
||||
- При запросе списка назначений проверить дедлайн |
||||
- Если дедлайн прошёл и попытка не завершена — пометить как `expired` |
||||
|
||||
--- |
||||
|
||||
## Результат |
||||
|
||||
- Прохождение теста со случайным порядком вопросов |
||||
- Таймер с автозавершением |
||||
- Сохранение прогресса |
||||
- Навигация по вопросам |
||||
@ -0,0 +1,78 @@
|
||||
# Шаг 8: Результаты и разбор ошибок |
||||
|
||||
## Цель |
||||
|
||||
Реализовать отображение результатов теста и разбора ответов сотруднику. |
||||
|
||||
--- |
||||
|
||||
## Задачи |
||||
|
||||
### 8.1. Просмотр результатов |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/attempts/:id/result` | GET | Получить результат | |
||||
|
||||
**Ответ:** |
||||
```json |
||||
{ |
||||
"test_title": "Название теста", |
||||
"version": 1, |
||||
"correct_count": 8, |
||||
"total_questions": 10, |
||||
"percentage": 80, |
||||
"passed": true, |
||||
"passing_threshold": 75, |
||||
"completed_at": "2026-03-21T10:30:00Z" |
||||
} |
||||
``` |
||||
|
||||
### 8.2. Разбор ошибок |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/attempts/:id/review` | GET | Получить разбор | |
||||
|
||||
**Ответ:** |
||||
```json |
||||
{ |
||||
"questions": [ |
||||
{ |
||||
"id": "uuid", |
||||
"text": "Текст вопроса", |
||||
"user_selected": ["option_id_1", "option_id_2"], |
||||
"correct_options": ["option_id_1", "option_id_3"], |
||||
"is_correct": false, |
||||
"options": [ |
||||
{ "id": "option_id_1", "text": "Вариант А", "is_correct": true }, |
||||
{ "id": "option_id_2", "text": "Вариант Б", "is_correct": false }, |
||||
{ "id": "option_id_3", "text": "Вариант В", "is_correct": true } |
||||
] |
||||
} |
||||
] |
||||
} |
||||
``` |
||||
|
||||
### 8.3. Логика отображения |
||||
|
||||
- Сразу после завершения — перенаправление на страницу результатов |
||||
- Показывать балл, процент, зачёт/не зачёт |
||||
- Для каждого вопроса: |
||||
- Выбранные ответы сотрудника |
||||
- Правильные ответы |
||||
- Индикатор правильно/неправильно |
||||
- Все варианты ответов с подсветкой |
||||
|
||||
### 8.4. Доступ |
||||
|
||||
- Сотрудник видит только свои результаты |
||||
- Результаты доступны после завершения попытки |
||||
|
||||
--- |
||||
|
||||
## Результат |
||||
|
||||
- Итоговый балл и процент |
||||
- Статус зачёта |
||||
- Полный разбор по каждому вопросу |
||||
@ -0,0 +1,53 @@
|
||||
# Шаг 9: Трекер попыток |
||||
|
||||
## Цель |
||||
|
||||
Реализовать единый интерфейс просмотра всех попыток прохождения тестов. |
||||
|
||||
--- |
||||
|
||||
## Задачи |
||||
|
||||
### 9.1. API трекера |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/tracker` | GET | Список всех попыток | |
||||
|
||||
**Параметры фильтрации:** |
||||
- `department_id` — по подразделению |
||||
- `user_id` — по сотруднику |
||||
- `test_id` — по тесту |
||||
- `status` — по статусу (in_progress, completed, expired) |
||||
- `passed` — по результату (true, false) |
||||
|
||||
### 9.2. Поля в трекере |
||||
|
||||
| Поле | Источник | |
||||
|------|----------| |
||||
| Сотрудник | users.full_name, departments.name | |
||||
| Тест | tests.title | |
||||
| Попытка № | test_attempts.attempt_number | |
||||
| Начало | test_attempts.started_at | |
||||
| Завершение | test_attempts.completed_at | |
||||
| Результат | correct_count / total_questions, % | |
||||
| Зачёт | passed (true/false) | |
||||
|
||||
### 9.3. Права доступа |
||||
|
||||
- **HR:** видит все попытки по всей клинике |
||||
- **Manager:** видит попытки только своего подразделения |
||||
- **Employee:** видит только свои попытки |
||||
|
||||
### 9.4. Пагинация и сортировка |
||||
|
||||
- Пагинация по 20/50/100 записей |
||||
- Сортировка по дате начала (убывание) |
||||
|
||||
--- |
||||
|
||||
## Результат |
||||
|
||||
- Таблица попыток с фильтрами |
||||
- Ограничение данных по роли |
||||
- Полная история прохождений |
||||
@ -0,0 +1,89 @@
|
||||
# Шаг 10: AI-помощник (DeepSeek) |
||||
|
||||
## Цель |
||||
|
||||
Интегрировать LLM DeepSeek для помощи при создании тестов. |
||||
|
||||
--- |
||||
|
||||
## Задачи |
||||
|
||||
### 10.1. Настройка API |
||||
|
||||
- Сохранить API ключ DeepSeek в таблице `settings` |
||||
- Ключ хранится только на бэкенде, не передаётся на фронтенд |
||||
|
||||
### 10.2. Функции AI-помощника |
||||
|
||||
#### Генерация теста |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/ai/generate-test` | POST | Сгенерировать тест | |
||||
|
||||
**Запрос:** |
||||
```json |
||||
{ |
||||
"topic": "Оказание первой помощи", |
||||
"question_count": 10 |
||||
} |
||||
``` |
||||
|
||||
**Ответ:** готовый тест с вопросами и вариантами ответов |
||||
|
||||
#### Улучшение формулировки |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/ai/improve-question` | POST | Улучшить вопрос | |
||||
|
||||
**Запрос:** |
||||
```json |
||||
{ |
||||
"question": "Что делать при переломе?" |
||||
} |
||||
``` |
||||
|
||||
#### Добавление дистракторов |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/ai/add-distractors` | POST | Добавить неправильные варианты | |
||||
|
||||
**Запрос:** |
||||
```json |
||||
{ |
||||
"question": "Признаки инфаркта:", |
||||
"correct_answer": "Боль в груди", |
||||
"count": 3 |
||||
} |
||||
``` |
||||
|
||||
#### Проверка качества |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/ai/check-quality` | POST | Проверить качество теста | |
||||
|
||||
**Запрос:** |
||||
```json |
||||
{ |
||||
"test": { ... } |
||||
} |
||||
``` |
||||
|
||||
**Ответ:** рекомендации по улучшению |
||||
|
||||
### 10.3. Обработка ошибок |
||||
|
||||
- Timeout при длительном ответе API |
||||
- Логирование ошибок |
||||
- Fallback при недоступности DeepSeek |
||||
|
||||
--- |
||||
|
||||
## Результат |
||||
|
||||
- AI-генерация вопросов |
||||
- Улучшение формулировок |
||||
- Рекомендации по качеству |
||||
@ -0,0 +1,63 @@
|
||||
# Шаг 11: Страница настроек |
||||
|
||||
## Цель |
||||
|
||||
Реализовать страницу настроек для управления API ключами и системными параметрами. |
||||
|
||||
--- |
||||
|
||||
## Задачи |
||||
|
||||
### 11.1. Страница настроек |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/settings` | GET | Получить настройки | |
||||
| `/api/settings` | PUT | Обновить настройки | |
||||
|
||||
### 11.2. Поля настроек |
||||
|
||||
| Поле | Описание | |
||||
|------|----------| |
||||
| deepseek_api_key | API ключ DeepSeek (скрыт на фронтенде) | |
||||
|
||||
### 11.3. Проверка подключения |
||||
|
||||
| Эндпоинт | Метод | Описание | |
||||
|----------|-------|----------| |
||||
| `/api/settings/test-connection` | POST | Проверить подключение к DeepSeek | |
||||
|
||||
**Ответ:** |
||||
```json |
||||
{ |
||||
"success": true, |
||||
"message": "Подключение успешно" |
||||
} |
||||
``` |
||||
|
||||
или |
||||
|
||||
```json |
||||
{ |
||||
"success": false, |
||||
"message": "Ошибка: неверный API ключ" |
||||
} |
||||
``` |
||||
|
||||
### 11.4. Безопасность |
||||
|
||||
- API ключ никогда не передаётся в ответах GET `/api/settings` |
||||
- При GET возвращается `***hidden***` вместо ключа |
||||
- PUT принимает новый ключ и сохраняет в БД |
||||
|
||||
### 11.5. Права доступа |
||||
|
||||
- Только HR может изменять настройки |
||||
|
||||
--- |
||||
|
||||
## Результат |
||||
|
||||
- Страница `/settings` |
||||
- Ввод и сохранение API ключа |
||||
- Проверка подключения к DeepSeek |
||||
Loading…
Reference in new issue