docs folder with steps
This commit is contained in:
Vendored
BIN
Binary file not shown.
+163
@@ -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
|
||||||
Reference in New Issue
Block a user