Career Quest
Веб-приложение для сотрудника и HR: профиль, покрытие требований карьерной цели, до трёх рекомендаций обучения с объяснением, отметка выполнения с…
О проекте
Команда: Kvaslovers
Кейс HackAlem.ai: Менеджмент — Halyk Bank · кейс 1
Стадия: Рабочий MVP
Задача кейса: «Career Quest»: AI-навигатор, связывающий навыки сотрудника с шагами развития
Суть
Веб-приложение для сотрудника и HR: профиль, покрытие требований карьерной цели, до трёх рекомендаций обучения с объяснением, отметка выполнения с пересчётом, HR-обзор дефицитов навыков и импорт данных.
Как устроено
Чистая функция recommend отбирает доступные события по роли и грейду, prerequisites, будущим сессиям, обязательности и завершениям. Полезный прирост ограничен gain, max_level и оставшимся разрывом. Ранжирование взвешенное: критичность 0.35, разрыв 0.30, эффект 0.20, история 0.15. Покрытие = Σmin(текущий, требуемый) / Σтребуемый. Объяснения строятся из детерминированных шаблонов, опциональный адаптер локального Ollama добавляет пояснение с резервным ответом.
Ключевые решения
- rule-based фильтрация активностей
- взвешенное ранжирование 0.35/0.30/0.20/0.15
- метрика покрытия траектории
- PBKDF2-HMAC-SHA256
- CSRF
- одноразовые приглашения (SHA-256)
Особенности
Прозрачная формула без ML и зависимостей, с раскрываемым пояснением «Как рассчитана оценка». Подготовлены проверочные профили жюри (JURY_A/B/C) с ожидаемым TOP-3. Защита от повторного начисления и регистрация только по одноразовому приглашению.
Стек
Python · http.server · SQLite · HTML/CSS/JS · unittest
Модели
Ollama (локальная модель, опционально)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-edd3c6c3-kvaslovers.
README
README.mdCareer Quest
1. Название проекта
Career Quest — платформа карьерного развития для хакатона HackAlem AI.
2. Краткое описание
Сотруднику бывает трудно выбрать обучение, которое приближает его к нужной роли или грейду. Career Quest сопоставляет профиль, требования карьерной цели и историю участия, чтобы предложить конкретные следующие шаги с объяснением. HR получает обзор дефицитов навыков и участия сотрудников в активностях.
3. Что реализовано
- Вход сотрудника и HR с разграничением доступа на сервере.
- Профиль: роль, грейд, навыки, история и покрытие требований карьерной цели.
- До трёх рекомендаций: компактные блоки цели, разрыва, эффекта и истории; полное объяснение раскрывается отдельно.
- Раскрытие всех навыков и истории, поиск сотрудников в HR-обзоре.
- Отметка выполнения с обновлением навыков, истории и рекомендаций; сохранение в SQLite.
- HR-обзор: дефициты навыков, сотрудники без следующего шага, неактивность и участие.
- Расширенный список HR: рекомендации, последняя активность, основной skill gap и статус развития.
- Импорт
employees.json,events.json,skills.jsonиactivity_history.csvчерез HR-интерфейс. - Регистрация сотрудников по одноразовому персональному приглашению HR для конкретного профиля.
- Получение истории сотрудника через отдельный защищённый API endpoint.
- Автоматические проверки и демонстрационные профили с ожидаемыми результатами.
- Опциональный адаптер локальной LLM для дополнительного объяснения с резервным ответом.
4. Как работает решение
- При первом запуске сервер загружает синтетический kit из
ai/dataв SQLite. HR может добавлять проверочные профили и историю через импорт и создавать одноразовое приглашение, привязанное к конкретному сотруднику. - Сотрудник входит и открывает свой профиль. Движок определяет карьерную цель и восстанавливает уровни навыков с учётом завершённых активностей.
- Движок сравнивает навыки с требованиями цели, отбирает доступные активности и ранжирует их по четырём факторам.
- Интерфейс показывает до трёх шагов: причину выбора, текущий и прогнозируемый уровень навыка, требуемый уровень и историю участия.
- После отметки выполнения сервер сохраняет результат и пересчитывает прогресс. HR видит обновлённую сводку по сотрудникам.
Расчёт рекомендаций
Чистая функция ai.recommendation.recommend выбирает 0–3 доступных события.
Проверяются роль/грейд, prerequisites, будущая сессия, обязательность,
завершения и текущие участия. Полезный прирост ограничен gain, max_level
и оставшимся разрывом. Критичность, разрыв, эффект и история имеют веса
0.35/0.30/0.20/0.15. Это прозрачный алгоритм по правилам, а не обученная модель.
Подробная схема, формула и интерфейс: ai/README.md.
Доля покрытия траектории = сумма min(текущий, требуемый) по целевым навыкам /
сумма требований × 100. Это не вероятность повышения, а покрытие требований.
Прогнозируемый прирост не записывается до добровольной отметки о выполнении.
5. Технологии
| Компонент | Реализация |
|---|---|
| Backend | Python 3.9+, стандартный http.server.ThreadingHTTPServer, JSON API |
| Хранение | SQLite через стандартный модуль sqlite3 |
| Frontend | HTML, CSS, JavaScript, браузерный Fetch API; без сборщика и UI-фреймворка |
| AI-слой | Собственный алгоритм правил и взвешенного ранжирования на Python |
| Объяснения | Детерминированные русскоязычные шаблоны |
| Опциональная LLM | HTTP-адаптер Ollama на localhost; конкретная модель не поставляется |
| Доступ | Cookie-сессии, CSRF, хеширование паролей PBKDF2-HMAC-SHA256 |
| Тестирование | Стандартный unittest |
Для основного сценария внешние библиотеки, облачные API и ключи не нужны. Веса рекомендателя заданы вручную; обученной ML-модели в репозитории нет.
6. Архитектура проекта
Браузер: index.html + app.js + styles.css
→ HTTP / JSON + cookie + CSRF
Backend/main.py: маршруты, сессии, права доступа
→ Backend/store.py: профили, выполнение, импорт, HR-сводка
→ SQLite: сохранённые профили и история
→ ai/profile.py: навыки и карьерная траектория
→ ai/recommendation.py → scoring.py + explain.py
Первоначальные данные: ai/data → Backend/store.py → SQLite
Дополнительное объяснение: /explanations → ai/local_llm.py → локальный Ollama
Интерфейс и API обслуживаются одним сервером с одного адреса.
Рекомендатель получает данные от слоя хранения и возвращает структурированный
результат; сам модуль ai не записывает данные в базу.
ai/ Движок, объяснения, траектория и неизменённый kit
Backend/main.py HTTP, сессии, права, API, локальная раздача frontend
Backend/store.py SQLite, выполнение, импорт, HR-агрегаты
index.html Вход, профиль, рекомендации, HR и импорт
app.js, styles.css Интерфейс команды, подключённый к API
tests/ Интеграционные тесты
.local/ Состояние и доступы конкретного запуска; игнорируется Git
7. Установка и запуск
Шаг 1. Получить код
Нужны Git, доступ к репозиторию команды и Python 3.9+ с SQLite.
Финальная интегрированная версия находится в ветке main; ai содержит ту же сборку.
git clone --branch main https://github.com/BAITC-Hacks/hack-edd3c6c3-kvaslovers.git
cd hack-edd3c6c3-kvaslovers
python3 --version
Если репозиторий уже клонирован, откройте актуальную ветку main в своей рабочей копии.
Шаг 2. Запустить сервер и войти
Нужен Python 3.9+ с SQLite (обычная установка Python). Внешних Python-пакетов, Node.js, сборки frontend и ключей облачных сервисов для основного сценария не нужно.
Из корня клонированного репозитория:
python3 -m Backend.main
Откройте http://127.0.0.1:8000. Не открывайте index.html как файл.
На Windows вместо python3 можно использовать py -3.
При первом запуске создаются локальная база .local/career_quest.sqlite3
и случайные учебные пароли в .local/credentials.json. Откройте этот файл
в VS Code либо выполните в другом терминале:
cat .local/credentials.json
Доступы:
hr: все профили, HR-аналитика, импорт проверочных данных;E0002,E0004,E0151: каждый видит только свой профиль и историю.
Логины не являются паролями. Пароли не прописаны в коде и не отправляются в Git. Исходный dataset не изменяется. Прогресс сохраняется после перезапуска сервера. Сессии истекают через 8 часов и не сохраняются после остановки сервера.
Новая учётная запись сотрудника создаётся только по одноразовому приглашению,
которое HR выдаёт из списка сотрудников. Код привязан к одному employee_id,
истекает через 7 дней, хранится в базе только как SHA-256 и погашается при
регистрации. Публичного списка свободных профилей нет. Для регистрации нового
аккаунта HR задайте переменную CAREER_QUEST_HR_REGISTRATION_CODE до запуска
и используйте её как отдельный код приглашения HR.
CAREER_QUEST_HR_REGISTRATION_CODE=private-invite-code python3 -m Backend.main
Для отдельного чистого прогона без удаления текущего прогресса:
python3 -m Backend.main --port 8001 --db .local/rehearsal/state.db
Это отдельная база и отдельный файл паролей .local/rehearsal/credentials.json.
По умолчанию сервер слушает localhost. Для устройств в одной доверенной сети:
python3 -m Backend.main --host 0.0.0.0 --port 8000
На другом устройстве откройте http://<локальный-IP-сервера>:8000.
Компьютер с сервером должен оставаться включённым; брандмауэр и сеть должны
разрешать соединение. Это общий экземпляр с одной базой. Межустройственная
проверка сети пока не проводилась. Публичный HTTPS deployment не настроен.
8. Как проверить решение
Начните с новой базы без предыдущих выполнений: числовые ожидания ниже относятся к исходным данным. Команда отдельного прогона приведена в разделе запуска.
- Войти как
E0002: Middle → Senior, покрытие требований 62%. - Показать
System Design Fundamentals(EV_005, score 0.6120): два критических навыка, API Design и System Design, 1 → 2, требуется 4. Раскрыть «Как рассчитана оценка»: критичность, разрыв, эффект и история. - Нажать «Отметить выполненной»: покрытие становится 66%, появляется запись истории; новые рекомендации учитывают достигнутые уровни. Обновить страницу — изменения сохраняются. Повторный HTTP-запрос не начисляет прирост повторно.
- Выйти и войти как
hr. Открыть «Обзор команды»: дефициты навыков, сотрудники без шага, отсутствие добровольных завершений за 90 дней, участие по всем 40 активностям и всем статусам. - Загрузить
docs/jury-sample/employees.jsonиdocs/jury-sample/activity_history.csvчерез форму HR. Полный набор также принимаетevents.jsonиskills.json. Можно вставить содержимое в поля. Открыть импортированные профили:JURY_A: три неявки Public Speaking, но критичен System Design; ожидаемый TOP-3: EV_006, EV_005, EV_007;JURY_B: переход Data Analyst → Product Manager; ожидаемый TOP-3: EV_026, EV_021, EV_027;JURY_C: требования закрыты, корректное пустое состояние.
- Проверить приватность: в аккаунте сотрудника нет HR-вкладки и выбора чужих профилей; прямой запрос к чужому ID также возвращает 403. Без персонального приглашения зарегистрироваться на существующий employee_id нельзя; HR может выдать одноразовый код из списка команды.
Ещё три исходных примера: python3 -m ai.demo, сценарий в ai/demo/README.md.
CLI читает исходный kit, веб-приложение — сохранённую SQLite-базу. После
отметок о выполнении веб-результаты закономерно отличаются от исходного CLI.
Автоматические проверки
python3 -m unittest discover -v
python3 -m ai.demo
Проверяются 200 исходных профилей, сложные случаи ранжирования, права, HTTP API, регистрация и защита персонального приглашения, история, загрузка четырёх файлов, транзакции, одновременное выполнение, перезапуск базы, импорт/откат, HR-агрегаты и fallback модели. Тестовые базы создаются во временных папках.
Матрица требований: docs/ACCEPTANCE.md.
9. Данные и интеграции
Источник — предоставленный синтетический Career Quest kit в ai/data:
| Файл | Содержимое |
|---|---|
employees.json | 200 профилей сотрудников |
events.json | 40 активностей, правила gain и max_level, условия участия |
skills.json | 60 навыков и 32 профиля требований ролей/грейдов |
activity_history.csv | 2743 записи истории участия |
Дата среза — 2026-10-01. Исходный kit сохраняется без изменений; пользовательские изменения записываются в локальную SQLite-базу. Описание формата: ai/data/README.ru.md. Дополнительные демонстрационные данные: docs/jury-sample.
Данные синтетические и предназначены для хакатона. Сервер не раздаёт исходный kit, SQLite и файл паролей через статические маршруты. Облачные сервисы для работы приложения не используются; опциональный Ollama вызывается локально.
Импорт жюри
Доступен только HR. Полный набор загружается через POST /api/datasets/upload
и содержит employees.json, events.json, skills.json и
activity_history.csv. JSON передаётся объектами, CSV — текстом. Также
поддерживается частичный импорт профилей и истории через POST /api/import.
UI принимает файлы или вставленный текст, но не оба источника одного типа.
Новые employee_id добавляются, существующие профили обновляются; история объединяется по record_id. Повторная загрузка одинаковых записей безопасна. События и навыки заменяются только при совпадающей дате среза и совместимости с сохранёнными профилями, целями и историей. Каталоги и данные применяются одной SQLite-транзакцией. Список HR содержит наличие рекомендации, дату активности, основной skill gap, статус развития и прогресс. Сводка включает active employees, completion rate, средний прогресс, сотрудников без рекомендации и без активности. Конфликтующий record_id, неизвестная роль/навык/событие, неверный уровень, статус или дата отклоняют весь импорт с 422, без частичных изменений. Дата meta должна совпадать со срезом. Лимит запроса 4 MB, до 1000 профилей и 20000 записей за импорт. Профиль с уже сохранёнными выполнениями нельзя перезаписать другим снимком — используйте новый ID для проверочного профиля. Новые профили доступны HR; импорт не создаёт учётные записи и не даёт права HR.
API приложения
Все данные требуют cookie-сессию; исключения — статические файлы и /health.
| Метод | URL | Назначение |
|---|---|---|
| POST | /api/login | {username, password} → user и csrf; HttpOnly cookie |
| GET | /api/me | Текущая сессия, csrf и дата среза |
| POST | /api/logout | Отзыв сессии |
| GET | /api/employees | HR: расширенный список всех; сотрудник: только свой профиль |
| GET | /api/employees/{id} | Профиль, траектория, история, рекомендации |
| GET | /api/employees/{id}/history | История участия с проверкой доступа к профилю |
| GET | /employees/{id}/recommendations | Совместимый endpoint движка; также с префиксом /api |
| POST | /api/employees/{id}/complete | {event_id} → изменения, прогресс до/после, новый профиль |
| GET | /api/hr/summary | Дефициты, active employees, прогресс, completion rate, отсутствие рекомендаций/активности |
| POST | /api/import | {employees, history}; history — CSV-строка или массив записей |
| POST | /api/datasets/upload | Полный набор {employees, events, skills, activity_history} |
| POST | /api/register | Аккаунт employee по персональному приглашению или HR по invite code |
| POST | /api/employees/{id}/registration-invite | HR создаёт одноразовый код для регистрации профиля |
| POST | /api/employees/{id}/explanations | Опциональная локальная LLM с fallback |
POST требует JSON и X-CSRF-Token из ответа login/me, кроме самого login.
401 — нет сессии; 403 — чужой профиль/HR/CSRF/неверное приглашение; 404 — неизвестный ID;
409 — недоступное выполнение; 422 — ошибка данных. Ошибки имеют {error: ...}.
Для сотрудника неизвестный чужой ID возвращает 403, не раскрывая существование
чужого профиля; HR для неизвестного ID получает 404.
Локальная LLM (опционально)
Факторы и исходные объяснения работают без LLM. Добавлен реальный HTTP-адаптер
к локальному Ollama 127.0.0.1:11434/api/generate, согласно
официальному API. Если Ollama уже
установлена и модель загружена, задайте имя вашей локальной модели:
CAREER_QUEST_OLLAMA_MODEL=your-local-model python3 -m Backend.main
Кнопка «Дополнить объяснение локальной LLM» передаёт только выбранные события, навыки и агрегированную историю, без имени/ID сотрудника. Облачного API нет. На весь запрос отведено до 7 секунд; ошибка/некорректный ответ/тайм-аут оставляют детерминированное объяснение. LLM-текст подписан как дополнительный и не меняет оценки или навыки. Тесты проверяют протокол адаптера и fallback; живой вывод модели на машине без Ollama не проверен. Базовый рекомендатель не выдаётся за работающую LLM. Уточнение необходимости конкретной модели остаётся вопросом трактовки AI-слоя организаторами.
10. Ограничения текущей версии
- Реализован локальный учебный стенд: нет корпоративного SSO и TLS-терминации.
- Геймификация, награды, календарь и прогноз оттока не реализованы.
- Интерфейс и объяснения — на русском; локализации на английский и казахский пока нет.
- Обучения на бизнес-результатах нет; веса ранжирования — эвристика. Покрытие навыков не является вероятностью или гарантией повышения.
- Реальный вывод локальной LLM не проверен: модель не поставляется с проектом. Проверены протокол адаптера и резервное объяснение при ошибке/тайм-ауте.
- Импорт не создаёт учётные записи. Регистрация HR требует кода организации; персональные коды для сотрудников нужно передавать по безопасному каналу.
- Проверены собственные дополнительные профили, а не неизвестный набор жюри.
- Измерения задержки относятся к локальной конфигурации и исходному kit, а не к произвольной нагрузке. Результаты и условия — в docs/ACCEPTANCE.md.
Правила учебного стенда
- Время фиксировано на дате kit 2026-10-01. Кнопка выполнения моделирует результат на эту дату, даже если предложенная сессия позже; это явно подписано.
- Завершения после последней оценки сначала учитываются в фактических уровнях.
При новом выполнении материализуется полный снимок навыков и переносится
граница снимка (
skill_snapshot_date). Дата реальной оценки сохраняется; исторические приросты не учитываются дважды. - Повторный клуб EV_036 разрешён, но один зачёт на дату среза. Прочие добровольные активности после завершения не повторяются.
- Явная карьерная цель имеет приоритет над следующим грейдом своей роли. Для Lead без цели используются требования Lead. Это решения продукта, а не обещания о реальном повышении.
- Для self-paced в исходном CSV нет даты завершения: используется доступная дата записи, что ограничивает точность восстановления старых уровней.
- Пустой список допустим, если подходящих мероприятий нет. HR отдельно видит таких сотрудников. Нерелевантные активности не добавляются ради количества.
11. Deployed-версия
Ссылка на публичную deployed-версию в текущем репозитории не указана. После локального запуска приложение доступно по адресу http://127.0.0.1:8000. Этот адрес работает только на компьютере, где запущен сервер, и не является ссылкой на публичный deployment.
Авторы коммитов
История коммитов
- 2026-09-23 17:57Publish integrated application on main retaining frontendАдилет Досаев
- 2026-09-23 17:56Integrate final Career Quest app with protected registration and verified UIАдилет Досаев
- 2026-09-23 17:34Save early frontend API integration draftAkylbek Daniyal
- 2026-09-23 17:21Merge backend integration into backKaris_Senpai
- 2026-09-23 17:05Merge origin/ai and secure employee registrationKaris_Senpai
- 2026-09-23 16:57Publish final hackathon README on mainАдилет Досаев
- 2026-09-23 16:36Complete backend data import and employee analyticsKaris_Senpai
- 2026-09-23 16:35Polish frontend profile and directory interactionsAkylbek Daniyal
Все коммиты (35)
- 2026-09-23 16:29Document Career Quest against hackathon README requirementsАдилет Досаев
- 2026-09-23 16:27Complete employee and HR frontend flowsAkylbek Daniyal
- 2026-09-23 15:51Complete Career Quest web app integrationKaris_Senpai
- 2026-09-23 15:41Build complete Career Quest app with progress, HR view and protected importsАдилет Досаев
- 2026-09-23 15:22Merge branch 'back' into frontKaris_Senpai
- 2026-09-23 15:21Integrate frontend with backend API routesGaemon
- 2026-09-23 15:16Add backend API integrated with AI recommenderKaris_Senpai
- 2026-09-23 15:14Connect frontend to employee and AI recommendation APIGaemon
- 2026-09-23 15:09Remove frontend file from main: app.jsGaemon
- 2026-09-23 15:09Remove frontend file from main: styles.cssGaemon
- 2026-09-23 15:09Remove frontend file from main: index.htmlGaemon
- 2026-09-23 15:08Add Career Quest frontend: app.jsGaemon
- 2026-09-23 15:08Add Career Quest frontend: styles.cssGaemon
- 2026-09-23 15:08Add Career Quest frontend: index.htmlGaemon
- 2026-09-23 15:07Merge remote-tracking branch 'origin/main' into aiАдилет Досаев
- 2026-09-23 15:04feat : implement appAkylbek Daniyal
- 2026-09-23 15:00Add Career Quest frontend: app.jsGaemon
- 2026-09-23 15:00Add Career Quest frontend: styles.cssGaemon
- 2026-09-23 15:00Add Career Quest frontend: index.htmlGaemon
- 2026-09-23 14:29Complete AI implementation merge and add test fileKaris_Senpai
- 2026-09-23 14:15Add Career Quest recommendation engine and dataset testsАдилет Досаев
- 2026-09-23 14:10finallyKaris_Senpai
- 2026-09-23 14:08testKaris_Senpai
- 2026-09-23 14:07test cleaningKaris_Senpai
- 2026-09-23 14:05Rename directory from src to coreKaris_Senpai
- 2026-09-23 13:59Merge remote changesKaris_Senpai
- 2026-09-23 13:55Fix embedded repository and add all filesKaris_Senpai
Структура репозитория (38 файлов)
.gitignore Backend/.gitignore Backend/README.md Backend/__init__.py Backend/main.py Backend/store.py FRONTEND.md README.md ai/.gitignore ai/README.md ai/__init__.py ai/__main__.py ai/data.py ai/data/README.kz.md ai/data/README.md ai/data/README.ru.md ai/data/activity_history.csv ai/data/employees.json ai/data/events.json ai/data/skills.json ai/demo.py ai/demo/README.md ai/demo/results.json ai/explain.py ai/local_llm.py ai/profile.py ai/recommendation.py ai/scoring.py ai/test_recommendation.py app.js docs/ACCEPTANCE.md docs/TEAM_HANDOFF.md docs/jury-sample/activity_history.csv docs/jury-sample/employees.json index.html styles.css tests/__init__.py tests/test_application.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.