Career Quest
Платформа Career Quest: профиль сотрудника с дефицитом навыков и готовностью к следующему грейду, объяснимые рекомендации 1–3 активностей…
О проекте
Команда: Ctrl AI
Кейс HackAlem.ai: Менеджмент — Halyk Bank · кейс 1
Стадия: Рабочий MVP
Задача кейса: «Career Quest»: AI-навигатор, связывающий навыки сотрудника с шагами развития
Суть
Платформа Career Quest: профиль сотрудника с дефицитом навыков и готовностью к следующему грейду, объяснимые рекомендации 1–3 активностей, «Лаборатория выбора» с прогнозом, HR-аналитика и импорт данных.
Как устроено
Датасет (employees/events/skills/activity_history) валидируется по JSON-схемам, движок считает skill gap и взвешенную готовность к грейду, ранжирует активности с учётом грейда, требований и истории пропусков/отказов. Симуляция показывает эффект активности до выполнения; выполнение применяет gain/max_level и пишет историю в SQLite. Опциональный GPT-выбор делает выбор среди допустимых активностей, без ключа работает локальный алгоритм. Фронтенд React работает с mock (MSW) или реальным API по bearer-токену.
Ключевые решения
- skill gap analysis
- weighted readiness
- explainable ranking
- what-if simulation
- atomic JSON/CSV import
- idempotent completion
- MSW mocks
- GitHub Actions container CI
Метрики
87 backend-тестов пройдено; демо: готовность E001 81.73% → 86.54% после EV002
Особенности
Объяснение конфликтующих факторов (низкий навык не определяет выбор, если в истории пропуски и отказы), «Лаборатория выбора» для сравнения вариантов без записи в БД, CI с проверкой сохранения прогресса после перезапуска контейнера.
Стек
Python · FastAPI · Pydantic 2 · SQLite · React · Vite · TypeScript · Tailwind · Docker · Docker Compose · Render
Модели
OpenAI gpt-4o-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-f746c068-ctrl-ai.
README
README.mdCareer Quest — команда Ctrl AI
hack-f746c068-ctrl-ai — командный репозиторий Ctrl AI для кейса Career Quest
хакатона HackAlem AI (трек Halyk Bank). Career Quest помогает сотруднику увидеть
карьерную траекторию и выбрать полезный шаг развития, а HR — понять, какие
компетенции проседают. Репозиторий команды.
Текущее состояние проекта: реализованы загрузка и проверка датасета, расчёт дефицита навыков и готовности к следующему грейду, объяснимый выбор 1–3 активностей, прогноз результата и сравнение вариантов, а также HTTP API с выполнением активностей, сохранением прогресса, HR-аналитикой и импортом. Доступ сотрудника и HR проверяется по локальным демо-токенам. Стек backend: Python 3.11+, Pydantic 2, FastAPI, SQLite. Frontend поддерживает два режима: автономный mock на MSW и подключение к реальному HTTP API по bearer-токену. Маршруты и форматы FastAPI подключены через слой адаптеров. Необязательный GPT-выбор доступен в профиле и через backend API при наличии серверного ключа; без него действует локальный алгоритм. Публичная развёрнутая версия пока не указана.
Источник требований — техническое задание Career Quest, раздел «КЕЙС: CAREER QUEST». Стартовый кит организаторов с официальной схемой данных в проект ещё не добавлен.
Что можно проверить в приложении
| Возможность | Где проверить | Что происходит |
|---|---|---|
| Профиль и карьерная траектория | /employee/E001 | Роль, грейд, навыки, требования следующего уровня и готовность |
| Объяснимые рекомендации | Профиль сотрудника | До 3 шагов с учётом грейда, разрывов, требований и истории участия |
| Выбор с GPT | Кнопка «Подобрать с GPT» в реальном режиме | Модель выбирает допустимую активность; интерфейс показывает источник результата |
| Прогноз и сравнение | «Лаборатория выбора» | Изменения навыков и готовности до выполнения, без записи в базу |
| Выполнение активности | Кнопка выполнения в профиле | Применение gain/max_level, запись истории и пересчёт рекомендаций |
| История | /employee/E001/history | Завершения, пропуски, отказы и другие статусы участия |
| HR-аналитика | /hr с токеном HR | Средняя готовность, дефициты по навыкам и ролям, участие и сотрудники без следующего шага |
| Новые данные жюри | Swagger → POST /dataset/import с токеном HR | Проверка и атомарный импорт профилей и истории JSON/CSV |
Сотрудник имеет доступ к своему профилю и истории. HR может открыть список
сотрудников, любой профиль, аналитику и импорт. Проверка ролей выполняется в API.
В контейнере все API-маршруты имеют префикс /api; Swagger доступен в /api/docs.
Демонстрация для жюри за 3–5 минут
- Запустите приложение по инструкции ниже и войдите значением
tokenиз записи сrole: "employee"вaccess.json. На свежем демонстрационном наборе он относится к E001. - Откройте профиль: Middle Backend Engineer → Senior. Готовность — 81.73%, System Design — 2 из 4. В обычных рекомендациях первый шаг — EV002 / Architecture Mentoring.
- Раскройте объяснение: низкий Public Speaking сам по себе не определяет выбор. Для следующего грейда критичен System Design, а история public speaking содержит два пропуска и отказ. Посмотрите прогноз EV002 без изменения профиля.
- Выполните EV002: System Design станет 3, готовность — 86.54%, в истории появится завершение, первой обычной рекомендацией станет EV006. Обновите страницу и убедитесь, что результат сохранён.
- Выйдите и войдите токеном записи с
role: "hr". Откройте/hr: пересчитаны средняя готовность, разрывы и участие. Для исходного набора число завершений меняется 120 → 121. - Для проверки нового сотрудника откройте
/api/docs, нажмите Authorize, вставьте HR-токен и выполнитеPOST /dataset/import: режимappend, файлemployeesв JSON и при необходимостиactivity_historyв CSV. Используйте новые идентификаторы и существующие роли/навыки/события. Затем откройте новый профиль под HR и проверьте рекомендации. Контракт импорта.
Числа относятся к свежей базе из backend/data/ и обычным рекомендациям.
Повторное выполнение меняет состояние; отдельный GPT-выбор может предложить
другой допустимый шаг. При запуске frontend в mock-режиме набор и проценты другие.
Публикация для жюри и запуск всего приложения
Frontend и API собираются в один Docker-контейнер и работают по одному адресу. Для публикации используйте готовую конфигурацию Render и краткую инструкцию. Конфигурация создаёт платный Web Service с постоянным диском для SQLite и токенов; перед созданием Render показывает стоимость. Сайт опубликован только после успешного развёртывания со статусом Live.
Для этого варианта нужен запущенный Docker с Docker Compose. Python, Node.js и зависимости устанавливаются внутри контейнера. После клонирования репозитория из его корня выполните одну команду:
docker compose up --build -d
Сайт: http://localhost:8000; API: http://localhost:8000/api/docs.
Готовность сервера: http://localhost:8000/api/health возвращает {"status":"ok"}.
Логи запуска: docker compose logs --tail=100 web.
Токены для входа доступны владельцу окружения:
docker compose exec web cat /var/data/access.json
Передайте жюри ссылку и токены сотрудника и HR по закрытому каналу. Не публикуйте токены в репозитории.
Если Render сообщает cannot access the following repo, подключите GitHub App
Render к организации, владеющей приватным репозиторием. Запрос на установку
может требовать одобрения владельца организации; установка только в личный
аккаунт не предоставляет доступ к репозиторию организации. После одобрения
повторите создание Blueprint. Готовый render.yaml сам по себе сайт не публикует.
Для включения GPT задайте OPENAI_API_KEY в окружении Docker Compose или локальном
.env и выполните docker compose up -d --force-recreate. Ключ не обязателен
для запуска. Модель задаётся через CAREER_QUEST_OPENAI_MODEL (по умолчанию
gpt-4o-mini). Настройки ключа на Render и проверка описаны в docs/DEPLOY.md.
Прогресс и токены сохраняются в томе /var/data: пересборка и обычный
docker compose down не удаляют их. docker compose down -v удаляет том вместе
с данными — для обновления приложения эта команда не нужна.
Проверки и текущие ограничения
При проверке кода 4e0cdbe от 23.09.2026 прошли 87 backend-тестов:
python -m unittest discover -s backend/tests -v
Проверка TypeScript (npx tsc -b из frontend/ после установки зависимостей)
на этой версии также прошла.
Проверяются расчёты, конфликтующие факторы рекомендаций, импорт неизвестных профилей и истории, права, выполнение активности, повтор HTTP-запроса, сохранение состояния после перезапуска и обработка ошибок GPT. В тестах ответы внешнего AI-сервиса заменены тестовыми ответами; это не подтверждение настоящего вызова модели с рабочим ключом.
Container verification настроен на backend-тесты, сборку и запуск Docker, проверку HTTP-сценария и сохранения прогресса после перезапуска. Результаты конкретного запуска доступны во вкладке Actions.
- Публичный сайт: подтверждённый URL пока не добавлен. Перед сдачей нужен успешный deploy, проверка входа по внешней ссылке и сама ссылка в материалах жюри.
- Данные: используется собственный синтетический набор; совместимость с официальным стартовым китом ещё нужно проверить по его фактической схеме.
- Вход: API использует демо-токены. При первом запуске создаются HR и один сотрудник; самостоятельной регистрации и входа по паролю в реальном API нет. Импорт нового профиля не создаёт ему учётную запись, но HR видит этот профиль.
- Импорт: доступен через API/Swagger; формы загрузки в HR-интерфейсе пока нет.
Максимум 5 MiB на файл;
appendдополняет набор,replaceтребует все 4 файла. - Пропуски и отказы: учитываются из импортированной истории. Кнопки записи этих действий работают только в mock-режиме; в реальном режиме они скрыты.
- Прогресс: отражает заданный эффект активности, а не результат независимой оценки навыка. Достижение требований не повышает грейд автоматически.
Запуск для разработки
Клонируйте репозиторий и создайте окружение из его корня:
git clone https://github.com/BAITC-Hacks/hack-f746c068-ctrl-ai.git
cd hack-f746c068-ctrl-ai
python -m venv .venv
Активация в PowerShell: .venv\Scripts\Activate.ps1.
В Linux/macOS: source .venv/bin/activate.
python -m pip install -r backend/requirements-dev.txt
python -m backend validate
python -m backend gaps E001
python -m backend readiness E001
python -m backend recommend E001 --limit 3
python -m unittest discover -s backend/tests -v
Запуск HTTP API одной командой после установки зависимостей:
python -m backend.api
Swagger: http://127.0.0.1:8000/docs. При первом запуске создаются рабочая
SQLite-база и локальные демо-токены в backend/runtime/. Для доступа нажмите
Authorize и используйте токен из backend/runtime/access.json.
Подробный контракт, роли, импорт и пример проверки — в docs/API.md.
Для запуска без тестов достаточно зависимостей из backend/requirements.txt.
Инструкция запуска frontend находится в frontend/README.md.
Для автономного демо оставьте VITE_USE_MOCK=true. Для работы с backend укажите
VITE_USE_MOCK=false, настройте VITE_API_URL, разрешите origin frontend через
CAREER_QUEST_CORS_ORIGINS и войдите токеном из backend/runtime/access.json.
Frontend проверит токен через GET /auth/me и добавит его в последующие запросы.
В реальном режиме frontend использует GET /employees/{id} вместо mock-маршрута
/profile, извлекает историю из объединённого ответа, читает HR-сводку через
GET /hr/dashboard и преобразует snake_case-ответы в модели интерфейса адаптерами
из frontend/src/api/adapters.ts. При завершении активности клиент создаёт UUID
для заголовка Idempotency-Key. Backend пока не имеет маршрутов skip/decline:
кнопки пропуска и отказа работают только в mock-режиме, но такие статусы из
загруженной истории отображаются и при работе с FastAPI.
Проверка своего набора и расчёт на нём:
python -m backend --data-dir path/to/dataset validate
python -m backend --data-dir path/to/dataset gaps E001
python -m backend --data-dir path/to/dataset readiness E001
python -m backend --data-dir path/to/dataset recommend E001 --limit 3
Успех возвращает JSON в stdout и exit code 0. Ошибка возвращает JSON в stderr и exit code 1. Загрузка не возвращает частично валидный набор.
Устройство текущей версии
backend/data_loader.py загружает и проверяет все четыре файла как единый набор.
backend/models.py задаёт поля и ограничения, backend/schemas/ содержит
JSON-схемы, backend/engine/skill_gap.py считает разрывы,
backend/engine/grade_progress.py — готовность, а
backend/engine/recommendation.py выбирает активности. backend/__main__.py
предоставляет команды validate, gaps, readiness и recommend. Генератор и
тесты находятся в backend/scripts/ и backend/tests/.
backend/engine/progress.py применяет завершение активности,
backend/engine/simulation.py без записи показывает эффект активности и сравнивает
два варианта по тем же правилам ранжирования,
backend/engine/hr.py собирает HR-показатели, backend/api/ предоставляет HTTP API,
backend/storage.py сохраняет рабочий снимок и ключи повторных запросов в SQLite.
Основной сценарий из ТЗ — профиль → рекомендация с объяснением → выполнение активности → обновлённый прогресс → срез для HR — реализован в API и подключён во frontend. Алгоритм рекомендаций детерминированный по умолчанию; отдельный endpoint может выбрать первый шаг через GPT из допустимых локальных вариантов. CLI считает исходные JSON/CSV, API использует отдельную SQLite-базу: завершённые через HTTP активности не переписывают демо-файлы.
Этап 1: данные и импорт
В backend/data/ находится воспроизводимый демонстрационный набор:
| Файл | Содержание |
|---|---|
employees.json | 48 синтетических профилей; роль, грейд, стаж, текущие навыки |
skills.json | 16 навыков, 4 карьерных трека, порядок грейдов и требования |
events.json | 26 активностей, целевые роли, предполагаемый прирост и предел уровня |
activity_history.csv | 235 записей участия с датой и статусом |
Все профили, названия активностей, история, требования и веса созданы командой для демонстрации. Реальные персональные данные и внешние классификаторы не использованы. Это не официальный датасет организаторов и не подтверждённая HR-матрица. При появлении официальной схемы потребуется адаптер к внутреннему контракту.
Контракт версии 1.0 определён в backend/models.py; машиночитаемые схемы находятся
в backend/schemas/. JSON Schema описывает структуру, а Python-валидатор дополнительно
проверяет уникальность, ссылки и ограничения между файлами. Для CSV схема history
описывает записи после разбора; точный заголовок:
record_id,employee_id,event_id,status,event_date
Правила:
- JSON и CSV читаются как UTF-8; BOM допускается. Даты —
YYYY-MM-DD. - ID уникальны в пределах сущности. Все ссылки на навыки, роли, сотрудников и события должны существовать.
- Уровни — целые числа 0–5; требования, gain и max_level — 1–5.
- Каталог может ограничить отдельный навык меньшим max_level; импорт проверяет это ограничение.
- Роль задаёт собственный упорядоченный список уникальных грейдов.
- У каждого грейда есть непустые требования и хотя бы один обязательный навык.
- Requirement содержит
level,importance(0 < вес <= 1),mandatory. - Неизвестные поля, повторяющиеся JSON-ключи, неверные статусы и даты отклоняются.
- Статусы истории:
invited,enrolled,completed,skipped,declined. - Пустая история и пустой каталог событий допустимы; профили и матрица навыков обязательны.
История описывает отдельные участия, поэтому один event_id может повторяться у сотрудника в разные даты. Архивные события сохраняются для целостности истории. Текущие навыки — готовый снимок: загрузчик не начисляет повторно gain из истории. Gain — условный ожидаемый эффект демо, а не доказательство освоения навыка.
Генератор использует фиксированный seed 42 и не обращается к сети:
python -m backend.scripts.generate_demo_data --output demo-copy
При наличии файлов генератор откажется их перезаписывать. Явное обновление поставляемого набора и схем после изменения моделей:
python -m backend.scripts.generate_demo_data --force --schemas backend/schemas
Этап 2: Skill Gap Engine
calculate_skill_gaps(employee, career_track) — чистая функция.
get_employee_skill_gaps(dataset, employee_id) находит профиль и его трек.
На границе приложения используется только полностью проверенный Dataset.
Следующий грейд берётся из порядка в треке. Для каждого требования этого грейда:
gap = max(required - current, 0)
normalized_gap = gap / required
weighted_gap = normalized_gap * importance
fulfilled = gap == 0
Отсутствующий навык считается уровнем 0 — это явное допущение демонстрационного контракта, а не вывод о способностях реального сотрудника. В реальной системе неизмеренный уровень стоит хранить отдельно и запрашивать оценку.
Результат содержит все целевые навыки, включая выполненные и дополнительные
(mandatory=false), в стабильном порядке skill_id. Навыки сотрудника вне требований
не включаются и не компенсируют дефицит других навыков. Счётчики различают общее
число навыков с gap и число обязательных навыков с gap. Это не рейтинг активностей.
Для E001, Middle Backend Engineer → Senior:
| Навык | Текущий | Требуется | Gap | Вес | Weighted gap |
|---|---|---|---|---|---|
| System Design | 2 | 4 | 2 | 1.0 | 0.5 |
| Python | 3 | 4 | 1 | 1.0 | 0.25 |
| Public Speaking | 1 | 2 | 1 | 0.4 | 0.2 |
| Communication | 3 | 3 | 0 | 0.8 | 0 |
| SQL | 4 | 4 | 0 | 1.0 | 0 |
| Testing | 4 | 4 | 0 | 1.0 | 0 |
Public Speaking здесь дополнительный, остальные навыки обязательные. Всего 6 целевых навыков, 3 выполнены, 3 имеют gap, из них 2 обязательные. История E001 содержит два пропуска и отказ от public speaking; она не влияет на gap, но учитывается в рекомендациях.
Этап 3: рекомендации активностей
get_recommendations(dataset, employee_id, limit=3) возвращает до трёх активных
событий для роли сотрудника. Оно использует текущий грейд, требования следующего
грейда, дефицит и важность навыков, а также историю участия. Подходят только
активности, которые действительно сокращают хотя бы один разрыв с учётом gain
и max_level. Расчёт прогнозирует эффект, но пока не изменяет профиль.
Для каждого затронутого навыка вклад равен
(сокращение разрыва / требуемый уровень) × importance × коэффициент обязательности.
Коэффициент обязательности равен 1.5 для mandatory=true и 1 для дополнительного
навыка. Вклады суммируются. Множитель истории равен
clamp(1 + 0.05 × completed − 0.15 × skipped − 0.25 × declined − 0.10 × same_event_completed, 0.25, 1.25).
История учитывается по событиям, развивающим те же навыки; повтор уже завершённой
активности получает дополнительное снижение. Итоговая оценка — произведение суммы
вкладов и множителя истории. При равной оценке порядок определяется event_id.
Коэффициенты — явная эвристика демо, а не обученная модель или утверждённая HR-политика.
Ответ содержит использованные значения и текстовое объяснение. Для E001 первым
выбирается Architecture Mentoring: System Design 2/4 для перехода Middle → Senior,
после активности прогнозируется 3/4; ранее по навыку было одно завершение.
Public Speaking имеет уровень 1/2, но это дополнительное требование, а история
содержит два пропуска и отказ. Поэтому минимальный навык не определяет выбор.
Статусы без рекомендаций: top_grade, no_skill_gaps, no_matching_activity.
Необязательный GPT-слой
POST /employees/{id}/ai/recommendations (Swagger: /docs) может выбрать первый
шаг среди максимум 12 подходящих активностей. В модель передаются только роль,
грейды, ID вариантов, измеренные разрывы, возможные приросты и агрегированные
счётчики участия — без имени, ID сотрудника, дат и отдельных записей истории.
Backend проверяет возвращённый ID и строит фактическое объяснение из своих
расчётов. Модель не изменяет навыки и состояние. Остальные до двух шагов берутся
из локального ранжирования. Вызов использует store=false и тайм-аут 7 секунд.
Для включения задайте OPENAI_API_KEY в окружении процесса backend (не в
репозитории и не в браузере); при необходимости задайте
CAREER_QUEST_OPENAI_MODEL, по умолчанию gpt-4o-mini. Ключ лучше задать через
защищённые настройки запуска или менеджер секретов. Не вставляйте действующий
ключ в чат, README или исходники. Каждый вызов может
расходовать лимит организации. При отсутствии ключа или ошибке внешнего API
endpoint автоматически возвращает локальный топ-3 с source=rules и причиной
в fallback_reason; обычный GET /recommendations всегда локальный.
В профиле настоящего API есть кнопка Подобрать с GPT: запрос отправляется
только по нажатию, результат показывает источник (GPT или правила), объяснение
и выбранную активность. Можно посмотреть прогноз и выполнить этот шаг.
Альтернативная проверка — Swagger (/api/docs в контейнере).
Подробности ответа и прав доступа — в docs/API.md.
Этап 4: готовность к следующему грейду
calculate_grade_readiness(employee, career_track) использует результат Skill Gap
Engine. Для каждого навыка целевого грейда рассчитывается доля освоения с пределом
100%:
skill_progress = min(current / required, 1)
readiness_percent = 100 × Σ(skill_progress × importance) / Σ(importance)
Общий процент учитывает все требования, включая дополнительные навыки. Отдельный
mandatory_readiness_percent рассчитывается той же формулой только по обязательным
навыкам. meets_mandatory равен true, когда закрыт каждый обязательный навык;
его нельзя определять по округлённому проценту. Оба процента возвращаются без
округления, а интерфейс при необходимости округляет их только для отображения.
Процент не означает автоматического повышения: решение о грейде остаётся за HR.
Для E001 общий взвешенный результат: 100 × 4.25 / 5.2 ≈ 81.73%,
обязательная часть: 100 × 4.05 / 4.8 = 84.375%.
System Design даёт 2/4 = 50%, Python — 3/4 = 75%.
Так как оба навыка обязательны и имеют дефицит, meets_mandatory=false.
У сотрудника на последнем грейде нет следующей цели: статус top_grade,
readiness_percent=null, meets_mandatory=null.
Этап 5: выполнение активности и HR-сводка
Общая функция complete_activity(dataset, employee_id, event_id, record_id, completed_on)
возвращает новый проверенный Dataset и CompletionResult: изменения навыков,
готовность и рекомендации до и после. Прирост ограничен формулой
new = max(old, min(old + gain, max_level)). В историю добавляется completed;
старые завершения не начисляются повторно. Повтор с тем же record_id возвращает
already_completed без прироста; другой сотрудник или событие с этим ID дают
ошибку. Разные ID могут обозначать повторное прохождение. Грейд автоматически
не повышается.
Для E001 выполнение EV002 меняет System Design 2 → 3, готовность
81.73% → 86.54% и первый рекомендуемый шаг с EV002 на EV006. API преобразует
доменный результат в HTTP-контракт через backend/api/presenters.py и сохраняет
его вместе с состоянием в SQLite. Идемпотентность HTTP определяется заголовком
Idempotency-Key, а не передаваемым клиентом ID истории. Frontend генерирует для
новой попытки UUID v4 через crypto.randomUUID() (или безопасный fallback на
crypto.getRandomValues()), передаёт его в этом заголовке и адаптирует ответ
завершения к своей модели прогресса.
get_hr_summary(dataset) возвращает частые дефициты, срез по ролям, сотрудников
без шага с причиной и признаком необходимости действия, а также участие по
событиям и статусам. Считаются записи истории и уникальные сотрудники.
Средняя готовность исключает сотрудников на последнем грейде. Представление
get_hr_dashboard(dataset) в backend/api/presenters.py адаптирует эту сводку
к HTTP-контракту и сохраняет average_readiness_percent и
role_skill_deficits. Доступ к нему разрешён только HR.
Дополнительный блок: прогноз и сравнение вариантов
simulate_activity(dataset, employee_id, event_id) рассчитывает гипотетическое
завершение через тот же complete_activity, что использует настоящий запрос. Оно
возвращает изменения каждого навыка с gain и max_level, разрывы и готовность
до/после, а также рекомендации после предполагаемого завершения. Новый снимок
датасета отбрасывается: история и навыки в SQLite не меняются. Прогноз включает
влияние гипотетической записи completed на последующие рекомендации; грейд
автоматически не меняется.
compare_activities сопоставляет две активные и полезные для следующего грейда
активности одной роли. Используется тот же полный список оценённых кандидатов,
из которого выбираются первые три рекомендации, поэтому сравнить можно и вариант
вне топ-3. Ответ показывает оценку, сокращение взвешенного разрыва, множитель
истории, изменения готовности для каждого варианта и объяснение выбора. При
равенстве оценок действует стабильный порядок event_id. Маршруты доступны
только самому сотруднику или HR: GET /employees/{id}/simulate/{event_id} и
GET /employees/{id}/compare?first_event_id=A&second_event_id=B. Список всех
допустимых альтернатив для выбора даёт GET /employees/{id}/comparison-options.
Это отдельный необязательный блок принятия решения, а не автоматическое начисление навыков. Лаборатория выбора работает как с mock-обработчиками, так и с реальными маршрутами backend; численные оценки разных режимов могут отличаться, поскольку mock использует локальный демонстрационный расчёт.
Проверочные профили
| ID | Сценарий |
|---|---|
| E001 | Точные разрывы и выбор с учётом истории |
| E002 | Нет измеренных навыков и истории; все целевые навыки считаются нулевыми |
| E003 | Требования превышены; gap остаётся нулевым, повышения автоматически нет |
| E004 | Последний грейд; status=top_grade, target_grade=null, gaps={} |
| E005 | Единственный gap — Testing; подходящей активности в демо-каталоге нет |
Последний грейд отличается от выполненных требований: он не означает готовность
100%. Неизвестный сотрудник даёт employee_not_found; невалидная роль или грейд
отклоняются при импорте. Пустые требования — ошибка данных.
Тесты проверяют импорт и связи, воспроизводимость, ошибки файлов, точные расчёты,
пропущенные и избыточные навыки, изменение процента готовности после роста навыка,
конфликтующие факторы рекомендаций, новый профиль и его историю, ограничения
активности по роли, статусу и max_level, отсутствие подходящих шагов, последний
грейд, отсутствие мутации входа и инварианты всех 48 профилей.
API-тесты дополнительно проверяют права доступа, выполнение и пересчёт, идемпотентность запросов, сохранение после перезапуска, конкурентные изменения, добавление нового профиля с историей и откат невалидного импорта. HR-показатели считают записи участия; последний грейд и закрытые требования помечаются отдельными причинами отсутствия рекомендаций, а не признаками низкой вовлечённости.
Авторы коммитов
История коммитов
- 2026-09-23 17:59docs: add jury walkthrough and verified project statusvwgit
- 2026-09-23 17:50feat: package GPT-enabled app for deployment and verify container in CIgostevandrey9-bit
- 2026-09-23 17:47merge: integrate shared container deployment and frontend APIgostevandrey9-bit
- 2026-09-23 17:46feat: add optional GPT recommendations with safe fallbackgostevandrey9-bit
- 2026-09-23 17:41Add single-service Render deployment for Career Questvwgit
- 2026-09-23 17:27feat(frontend): integrate authenticated backend API and idempotent completionKavkaz228
- 2026-09-23 16:35Expose HR readiness and role deficitsvwgit
- 2026-09-23 16:22feat: add career activity decision labgostevandrey9-bit
Все коммиты (26)
- 2026-09-23 16:08feat(frontend): вход и регистрация, роли HR/сотрудник, зелёно-золотая палитраKavkaz228
- 2026-09-23 15:47feat(frontend): фронтенд Career Quest на моковом API Сделан фронтенд Career Quest (React + Vite + TypeScript + Tailwind). Добавлено: Список сотрудников по разделам (44 человека в 5 разделах) с поискоKavkaz228
- 2026-09-23 15:47feat(frontend): дизайн, смягчение цветовKavkaz228
- 2026-09-23 15:38Merge team progress and frontend changes with API integrationgostevandrey9-bit
- 2026-09-23 15:35Add authenticated API with transactional progress and dataset importgostevandrey9-bit
- 2026-09-23 15:16Test imported profile activity progressvwgit
- 2026-09-23 15:14Add activity progress and HR summariesvwgit
- 2026-09-23 15:04CommitKavkaz228
- 2026-09-23 15:00Add Career Quest frontendKavkaz228
- 2026-09-23 14:38Add explainable activity recommendationsvwgit
- 2026-09-23 14:30Add weighted next-grade readiness calculationgostevandrey9-bit
- 2026-09-23 14:12Merge repository requirements and Career Quest implementationgostevandrey9-bit
- 2026-09-23 14:10Combine local and repository README contentgostevandrey9-bit
- 2026-09-23 13:59docs: add Career Quest agent instructionsvwgit
- 2026-09-23 13:57Document dataset validation and skill gap enginegostevandrey9-bit
- 2026-09-23 13:32Merge pull request #1 from BAITC-Hacks/caseVadim
- 2026-09-23 13:30Добавил файл с кейсомVadim
- 2026-09-23 13:18docs: add Russian project READMEvwgit
Структура репозитория (118 файлов)
.dockerignore .env.example .github/workflows/container.yml .gitignore AGENTS.md Dockerfile HackAlem AI_ Career Quest - платформа геймификации жизненного цикла сотрудника..md README.md backend/__init__.py backend/__main__.py backend/api/__init__.py backend/api/__main__.py backend/api/ai.py backend/api/app.py backend/api/auth.py backend/api/imports.py backend/api/presenters.py backend/data/activity_history.csv backend/data/employees.json backend/data/events.json backend/data/skills.json backend/data_loader.py backend/engine/__init__.py backend/engine/grade_progress.py backend/engine/hr.py backend/engine/progress.py backend/engine/recommendation.py backend/engine/simulation.py backend/engine/skill_gap.py backend/models.py backend/requirements-dev.txt backend/requirements.txt backend/schemas/dataset.schema.json backend/schemas/employees.schema.json backend/schemas/events.schema.json backend/schemas/history.schema.json backend/schemas/skills.schema.json backend/scripts/__init__.py backend/scripts/generate_demo_data.py backend/scripts/smoke_container.py backend/storage.py backend/tests/__init__.py backend/tests/test_ai_recommendations.py backend/tests/test_api.py backend/tests/test_cli.py backend/tests/test_dataset.py backend/tests/test_grade_progress.py backend/tests/test_hr.py backend/tests/test_hr_dashboard.py backend/tests/test_progress.py backend/tests/test_progress_response.py backend/tests/test_recommendation.py backend/tests/test_simulation.py backend/tests/test_skill_gap.py backend/tests/test_storage.py backend/tests/test_web.py backend/web.py compose.yaml docs/API.md docs/DEPLOY.md frontend/.env.development frontend/.env.production frontend/.gitignore frontend/.oxlintrc.json frontend/README.md frontend/index.html frontend/package-lock.json frontend/package.json frontend/postcss.config.js frontend/public/favicon.svg frontend/public/icons.svg frontend/public/mockServiceWorker.js frontend/src/api/adapters.ts frontend/src/api/auth.ts frontend/src/api/client.ts frontend/src/api/endpoints.ts frontend/src/api/mock/auth.ts frontend/src/api/mock/browser.ts frontend/src/api/mock/data/employees.ts frontend/src/api/mock/data/events.ts frontend/src/api/mock/data/skills.ts frontend/src/api/mock/engine.ts frontend/src/api/mock/handlers.ts frontend/src/auth/AuthContext.tsx frontend/src/auth/guards.tsx frontend/src/auth/session.ts frontend/src/components/hr/ActivityParticipationTable.tsx frontend/src/components/hr/GapHeatmap.tsx frontend/src/components/hr/StatusFunnel.tsx frontend/src/components/hr/TopGapsChart.tsx frontend/src/components/hr/UncoveredTable.tsx frontend/src/components/labels.ts frontend/src/components/layout/AppLayout.tsx frontend/src/components/profile/GapList.tsx frontend/src/components/profile/ProfileHeader.tsx frontend/src/components/profile/SkillGapChart.tsx frontend/src/components/progress/CompleteModal.tsx frontend/src/components/recommendations/AiRecommendation.tsx frontend/src/components/recommendations/DecisionLab.tsx frontend/src/components/recommendations/RecommendationCard.tsx frontend/src/components/recommendations/ScoreBreakdown.tsx frontend/src/components/ui/index.tsx frontend/src/hooks/queries.ts frontend/src/index.css frontend/src/main.tsx frontend/src/pages/AuthPage.tsx frontend/src/pages/EmployeesPage.tsx frontend/src/pages/HistoryPage.tsx frontend/src/pages/HrPage.tsx frontend/src/pages/ProfilePage.tsx frontend/src/router.tsx frontend/src/types/index.ts frontend/tailwind.config.js frontend/tsconfig.app.json frontend/tsconfig.json frontend/tsconfig.node.json frontend/vite.config.ts render.yaml
Ветки (2)
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.