Halyk Career Quest
Карьерный навигатор для Halyk Bank: траектория до следующего грейда, skill gaps, 1–3 объяснимые рекомендации, демо-курс с quiz и пересчётом навыка и…
О проекте
Команда: A&B Systems
Кейс HackAlem.ai: Менеджмент — Halyk Bank · кейс 1
Стадия: Доведённый продукт
Задача кейса: «Career Quest»: AI-навигатор, связывающий навыки сотрудника с шагами развития
Суть
Карьерный навигатор для Halyk Bank: траектория до следующего грейда, skill gaps, 1–3 объяснимые рекомендации, демо-курс с quiz и пересчётом навыка и готовности, HR-аналитика и импорт данных. Дополнительно корпоративные чаты с AI-сводками для руководителя и HR.
Как устроено
Express 5 API на TypeScript детерминированно вычисляет skill gaps, правила допуска к мероприятиям, gain/max_level, готовность и RBAC, данные (200 сотрудников, 40 событий, 60 навыков, 32 профиля ролей) хранятся в PostgreSQL 16. В OpenAI Responses API (gpt-4.1-mini) уходит только shortlist допустимых мероприятий для ранжирования или ограниченное окно сообщений чата для сводки; без ключа рекомендации работают по правилу. Фронтенд на React 19 + Vite, серверные сессии с scrypt, аудит-журнал, деплой через Docker Compose и Nginx.
Ключевые решения
- skill gap analysis
- rule-based eligibility
- LLM ranking of shortlist
- chat summarization
- RBAC
- scrypt sessions
Особенности
Шесть ролей (включая менеджера, оператора и супервизора контакт-центра) с матрицей прав на сервере, журнал аудита и демо-курс с quiz, который реально пересчитывает навык. В LLM передаётся только проверенный shortlist, а не весь датасет.
Стек
TypeScript · Node.js · Express · React · Vite · PostgreSQL · Docker Compose · Nginx
Модели
gpt-4.1-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-f02d3fd7-a-b-systems.
README
README.mdHalyk Career Quest
Сотрудники часто получают разрозненные уведомления об обучении и не видят, как конкретная активность помогает перейти к следующему грейду. Halyk Career Quest превращает требования роли, skill gaps и историю участия в понятную карьерную траекторию и 1–3 объяснимых следующих шага. Сотрудник может пройти короткое обучение, сдать тест и увидеть рост навыка и готовности. HR и руководитель видят прогресс команды; рабочие чаты получают краткие AI-сводки.
Это демонстрационный продукт команды A&B Systems для кейса Halyk Bank на HackAlem AI. Исходные HR-данные синтетические. OpenAI помогает ранжировать допустимые карьерные мероприятия и составлять сводки доступных пользователю сообщений; правила допуска, пересчёт навыков и проверка прав выполняются на backend.
Employee → Skill Gap Analysis → AI Recommendation → Learning Activity → Quiz
→ Achievement → Skill Progress → Career Readiness → HR / Manager Analytics
Corporate Chat → OpenAI AI Summary → Manager / HR / Supervisor
Что умеет продукт
- Карьерная траектория до следующего грейда, critical skills и skill gaps.
- 1–3 объяснимых рекомендации с учётом грейда, prerequisites, развиваемых навыков и истории участия; mandatory/compliance исключаются.
- Демо-курс из четырёх уроков и пяти вопросов, пересчёт навыка, готовности и достижение после успешного quiz.
- HR Analytics, импорт проверочных
employees.jsonиactivity_history.csv. - ADMIN/HR/EMPLOYEE и бизнес-роли с проверкой RBAC в API; панель администратора.
- Личный профиль, аватар, история входов, кадровое редактирование и журнал аудита.
- Личные и групповые корпоративные чаты, read/unread, OpenAI-сводки для уполномоченных ролей.
- Адаптивный интерфейс для desktop, tablet и смартфона шириной от 360px.
Technology Stack
| Слой | Реальная технология |
|---|---|
| Frontend | React 19, Vite 7, TypeScript, CSS, Lucide icons |
| Backend / API | Node.js 22, Express 5, TypeScript |
| Database | PostgreSQL 16 (pg), возможен Supabase PostgreSQL |
| AI | OpenAI Responses API (gpt-4.1-mini по умолчанию) |
| Auth | Серверные сессии в PostgreSQL, HttpOnly cookie, salted scrypt |
| Обновление чатов | Polling каждые 5 секунд |
| Infrastructure | Multi-stage Dockerfile, Docker Compose, Nginx reverse proxy на VPS |
Architecture
flowchart LR
Browser[Browser / React SPA] -->|Same-origin /api + HttpOnly cookie| API[Express API / RBAC]
API -->|SQL: users, events, progress, chats, audit| DB[(PostgreSQL persistent volume)]
API -->|Допустимый shortlist и краткий контекст| AI[OpenAI Responses API]
API -->|Статические файлы React| Browser
Proxy[Nginx / HTTPS] -->|127.0.0.1:3000| API
Backend детерминированно вычисляет skill gaps, правила допуска к мероприятиям, gain/max_level, готовность и все ограничения RBAC. В OpenAI уходит только shortlist подходящих мероприятий либо ограниченное окно сообщений после проверки доступа. Весь датасет модели не передаётся. Без ключа карьерные рекомендации продолжают работать по правилу ранжирования; AI-сводки показывают явную ошибку настройки вместо выдуманного результата.
Брендинг Halyk
Логотипы и favicon сохранены без изменения из HTML и assets официального сайта Halyk: основной логотип, белый логотип, SVG favicon и ICO favicon. Локальные копии находятся в public/brand/, чтобы интерфейс и вкладка браузера работали после clone без обращения к сайту банка. Товарные знаки и бренд-материалы Halyk принадлежат их правообладателю и используются в рамках hackathon demo.
QUICK START — запуск после clone
Нужны Docker Desktop либо Docker Engine с Compose и свободный локальный порт 3000. Docker сам поднимет PostgreSQL с постоянным volume; Node.js на машине не нужен.
git clone https://github.com/BAITC-Hacks/hack-f02d3fd7-a-b-systems.git
cd hack-f02d3fd7-a-b-systems
cp .env.example .env
docker compose up --build -d
docker compose ps
curl http://localhost:3000/api/health
В PowerShell используйте Copy-Item .env.example .env, а для проверки curl.exe http://localhost:3000/api/health. Откройте http://localhost:3000. Ответ health должен содержать "ok":true,"database":"ready". Для локального показа шаблонный пароль БД работает сразу; на VPS замените его до запуска. .env исключён из Git. docker compose down сохраняет данные; docker compose down -v удаляет volume и все внесённые изменения.
При старте сервер применяет server/schema.sql и, если БД пуста, импортирует 200 сотрудников, 40 событий, 60 навыков, 32 профиля ролей и 2743 записи участия. Учетные записи и пять демонстрационных чатов создаются при первом запуске даже при обновлении ранее созданной БД. Повторный запуск сохраняет профили, пользователей, сообщения, аудит и историю.
Проверка за 5 минут
- Employee /
learning: войдите с паролем из таблицы ниже. Откройте обзор, skill gaps, траекторию и рекомендованное обучение. Пройдите четыре урока и quiz (4 из 5 верных ответов). Проверьте Digital Starter, рост Technical Troubleshooting2 → 3и готовности69% → 71%на чистой БД. - Manager /
manager: откройте «Команда» и «Чаты» → «Команда Backend Development». Нажмите «Сделать AI-сводку» и проверьте темы, задачи и открытые вопросы. ТребуетсяOPENAI_API_KEY; сохранённая сводка появляется снова после входа. - HR /
hr: откройте HR Analytics, частые разрывы, сотрудников без следующего шага и результаты обученияE0021. В «Команда» проверьте кадровые поля. - ADMIN /
admin: откройте «Администрирование», список и роли пользователей, затем «Журнал аудита». Попробуйте поиск и фильтры.
После прохождения курса учётная запись learning останется в статусе completed: прогресс хранится в PostgreSQL. Для повторения с исходного состояния используйте новую БД или отдельный Docker Compose project.
DEMO ACCOUNTS
Это публичные демонстрационные пароли для проверочного стенда. Введите логин или email и пароль на странице входа. Они не являются данными доступа к VPS или production-инфраструктуре.
| System / business role | Login | Password | Что проверить |
|---|---|---|---|
| ADMIN / COMPANY_EMPLOYEE | admin | DemoAdmin!2026 | Пользователи, роли, полный аудит, HR Analytics |
| HR / HR_SPECIALIST | hr | DemoHR!2026 | HR Analytics, импорт, кадровые изменения, результаты обучения |
| EMPLOYEE / COMPANY_EMPLOYEE | employee | DemoEmployee!2026 | Собственный профиль E0028, рекомендации, траектория, чат |
| EMPLOYEE / COMPANY_EMPLOYEE | learning | DemoLearning!2026 | Курс E0021, quiz, skill progress, achievement |
| EMPLOYEE / DEPARTMENT_MANAGER | manager | DemoManager!2026 | Подчинённые, рабочий чат, AI-сводка |
| EMPLOYEE / CONTACT_OPERATOR | operator | DemoOperator!2026 | Диалог с клиентом и супервизором |
| EMPLOYEE / CONTACT_SUPERVISOR | supervisor | DemoSupervisor!2026 | Диалоги команды и общая AI-сводка обращений |
| EMPLOYEE / CONTACT_CLIENT | client | DemoClient!2026 | Только собственные чаты с оператором и профиль |
Пароли хранятся в PostgreSQL как salted scrypt-хеши; исходный текст в БД не сохраняется. Администратор может изменить пароль через панель. Демо-пароли нужно заменить перед доступом с других машин.
Роли, вход и проверка доступа
- ADMIN: полный доступ к Career Quest и разделу «Администрирование». Может создавать и редактировать пользователей, менять роли, статус, пароль и связь с employee. Может завершать активности для демонстрации.
- HR: видит сотрудников, их развитие и HR-аналитику, загружает проверочные файлы. Не может управлять пользователями или завершать активность от имени сотрудника.
- EMPLOYEE: видит только привязанный HR-профиль. Переключатель сотрудников и разделы HR/ADMIN отсутствуют; прямые вызовы чужого API возвращают
403.
После успешного входа браузер получает серверную сессию в HttpOnly, SameSite=Strict cookie. Сессия действует 7 дней и сохраняется при перезагрузке. «Выйти» внизу меню удаляет сессию на сервере. Деактивация, изменение роли/связи и смена пароля также завершают текущие сессии пользователя. У неавторизованных запросов к приватному API ответ 401; для недостаточной роли — 403. React скрывает недоступные разделы, но права проверяет сам Express для каждого запроса. Сессии хранятся в PostgreSQL, cookie содержит случайный токен, в БД хранится только SHA-256 токена. Для HTTPS cookie получает флаг Secure; запросы с чужим Origin на изменение данных отклоняются.
Учетная запись в users и HR-профиль в employees — разные сущности. Поле users.employee_id может быть пустым у ADMIN, HR и внешнего клиента контакт-центра. Для остальных EMPLOYEE связь обязательна и уникальна. Два пользователя не могут ссылаться на один employee. Импорт сотрудника сам по себе не создает учетную запись.
Roles & Security — матрица прав
| Feature | Employee | Manager | HR | Operator | Supervisor | Admin |
|---|---|---|---|---|---|---|
| Собственный профиль и активность | ✓ | ✓ | Профиль | ✓ | ✓ | ✓ |
| Карьерные данные других | — | Прямые подчинённые | Все | — | Прямые подчинённые | Все |
| HR Analytics и импорт | — | — | ✓ | — | — | ✓ |
| Кадровое редактирование | — | — | ✓ | — | — | ✓ |
| Личные/групповые чаты | ✓ | ✓ | ✓ | ✓ | ✓ | Клиенты только с операторами |
| AI-сводка доступного чата | — | ✓ | ✓ | — | ✓ | ✓ |
| Журнал аудита | Свои безопасные поля | Свои безопасные поля | Кадровые поля | Свои безопасные поля | Свои безопасные поля | Все события |
| Управление пользователями и ролями | — | — | — | — | — | ✓ |
Роль проверяется на сервере для каждого запроса к профилю, сотруднику, чату, AI-сводке и административному действию; скрытие кнопки в React не считается защитой. Пароли хранятся как salted scrypt, сессии — в PostgreSQL, cookie HttpOnly/SameSite=Strict и Secure за корректно настроенным HTTPS proxy. Запросы на запись с чужим Origin отклоняются. Секреты берутся из локального .env и не передаются React; .env исключён из Git и Docker build context.
Проверка под каждой ролью
- ADMIN: войдите как
admin, откройте «Администрирование». Проверьте список, поиск по имени/email/ID, фильтры роли/статуса, редактирование и создание. Откройте HR-аналитику и любой профиль. - HR: выйдите и войдите как
hr. Проверьте все профили, рекомендации, HR-дашборд и импорт. Раздела администрирования нет. ПрямойGET /api/admin/usersвозвращает403;POST /api/employees/:id/completeтакже403. - EMPLOYEE: войдите как
employee. Доступен толькоE0028(Akmaral Ismailova), ее навыки, история и рекомендации. HR и администрирование скрыты.GET /api/employees/E0001иGET /api/hr/dashboardвозвращают403. - Выйдите.
GET /api/bootstrap,/api/auth/meи приватные маршруты теперь возвращают401.
Создание и привязка пользователя
Войдите как ADMIN → Администрирование → Добавить. Введите имя, логин (3–40 латинских букв/цифр/._-), email, системную и бизнес-роль, первоначальный пароль (10–200 символов). Для обычного EMPLOYEE выберите существующий профиль в списке; ADMIN, HR и внешний клиент могут оставить связь пустой. Сохраните и войдите под новой учетной записью. В действиях строки доступны Изменить, Пароль, Отключить/Активировать, а также исправление даты рождения с записью в аудит. Последнего активного ADMIN отключить или понизить нельзя. Уникальность логина, email и связи с employee проверяется базой.
Личный профиль, кадровые права и аудит
Откройте «Мой профиль» из меню. Здесь отображаются имя учетной записи, email/логин, системная и бизнес-роль, кадровые данные, последние посещение и входы (успешные и неуспешные), а также разрешённая пользователю история изменений. Можно загрузить PNG/JPEG/WebP аватар до 2 МБ, изменить телефон, текст «О себе», предпочитаемый язык и пароль. Аватар хранится в PostgreSQL; пароль заменяется salted scrypt-хешем, другие сессии отзываются. Дату рождения пользователь может самостоятельно заполнить один раз; последующие исправления делают HR или ADMIN с записью старого и нового значения в аудит. Предпочитаемый язык сохраняется в профиле; перевод всего интерфейса пока не реализован.
Сотрудник не может самостоятельно изменить ФИО, логин/email, должность, подразделение, руководителя, грейд, дату приёма, формат работы, системную или бизнес-роль. Попытка прямого PATCH /api/me/profile с любым из этих полей получает 403. HR и ADMIN редактируют кадровые поля в разделе «Команда»; ADMIN отдельно управляет учетными данными и ролями в «Администрирование». Руководитель и супервизор могут видеть своих прямых подчинённых, но не редактировать кадровые поля. Изменения ФИО сотрудника через HR синхронизируются со связанной учетной записью.
audit_logs — отдельный журнал действий backend: кто, когда и чьё поле изменил, старое/новое значение и источник запроса. Изменение профиля, кадровых полей, учетных данных, даты рождения, аватара и пароля регистрируется при записи. Значения паролей, хешей, токенов и секретов в журнал не попадают. ADMIN видит полный журнал с фильтрами по периоду, цели, инициатору, действию, типу объекта и поиском. HR видит только разрешённые кадровые изменения. Сотрудник видит в «Мой профиль» только безопасную историю собственных данных. login_history хранит время, успех/ошибку, IP и user agent входа отдельно от журнала полей. audit_logs защищён SQL-триггером от UPDATE/DELETE, а API не предоставляет операцию удаления.
Корпоративные чаты и бизнес-роли
Системные роли ADMIN / HR / EMPLOYEE отвечают за доступ к API. Отдельная бизнес-роль задаёт контекст общения: COMPANY_EMPLOYEE, HR_SPECIALIST, DEPARTMENT_MANAGER, CONTACT_OPERATOR, CONTACT_SUPERVISOR, CONTACT_CLIENT. Она назначается ADMIN и проверяется сервером при поиске собеседников, создании чата, чтении, отправке сообщений и AI-сводках.
| Бизнес-роль | Возможности в чатах |
|---|---|
| COMPANY_EMPLOYEE | Личные диалоги с сотрудниками, чат своей команды |
| DEPARTMENT_MANAGER | Рабочая группа подчинённых, сводка обсуждения, просмотр команды |
| HR_SPECIALIST | Чаты с сотрудниками и руководителями, HR-права по системной роли |
| CONTACT_OPERATOR | Диалог с клиентом и своим супервизором, рабочий чат контакт-центра |
| CONTACT_SUPERVISOR | Чаты команды, просмотр рабочих диалогов операторов без права писать от их имени, общая сводка обращений |
| CONTACT_CLIENT | Только собственные чаты с операторами и личный профиль; HR и карьерные данные недоступны |
В «Чаты» можно начать личный диалог или группу, искать разрешённых участников, отправлять сообщения, видеть число непрочитанных и отмечать прочитанным. Сообщения сохраняются в PostgreSQL; интерфейс обновляет их каждые 5 секунд. Демо-чаты с готовой перепиской появляются при первом запуске. Прямой API-запрос к чужому чату возвращает 403. Для супервизора просмотр диалога оператора с клиентом доступен только если оператор является его прямым подчинённым; отправка сообщения в этот диалог запрещена.
AI-сводки используют реальный OpenAI Responses API и требуют OPENAI_API_KEY в .env. Руководитель может свести рабочее обсуждение команды, HR — доступный групповой чат, супервизор — отдельный рабочий диалог или обращения команды. Доступны последние 20/50 сообщений, сообщения за сегодня и непрочитанные; «непрочитанные» в общей сводке супервизора означают сообщения после последней общей сводки. Результат структурирован: темы, решения, задачи и открытые вопросы. Система просит модель брать факты только из переписки, не придумывать сроки или оценки людей. Сообщения с признаками секретов скрываются перед отправкой в OpenAI; запрос выполняется только на backend с store:false. Результат и охваченный период сохраняются в PostgreSQL. Без ключа endpoint возвращает 503 и объяснение, выдуманная сводка не показывается.
Сценарии для жюри: профиль, чат, сводка и аудит
- Войдите как
employee. Откройте «Мой профиль», измените «О себе» и телефон, при желании добавьте аватар. Обновите страницу: изменения останутся. Попробуйте изменить дату рождения один раз; после сохранения поле заблокировано. Кадровые поля доступны только для просмотра. - Откройте «Чаты» → «Команда Backend Development», прочитайте переписку, отправьте сообщение, отметьте прочитанным. Войдите как
manager, откройте этот чат и создайте AI-сводку: проверьте реальные темы/поручения, отсутствие выдуманного срока встречи и сохранённую сводку после повторного входа. Подemployeeкнопки сводки нет, а прямой API-запрос вернёт403. - Войдите как
clientи откройте диалог сoperator; внешний клиент не видит карьерное меню. Подoperatorответьте клиенту. Подsupervisorоткройте «Контакт-центр»: прочитайте обращение оператора в режиме просмотра и создайте «Сводка диалогов команды». Система показывает темы, задачи и открытые вопросы без рейтингов сотрудников. - Войдите как
hr, откройте «Команда», исправьте тестовое кадровое поле и верните исходное значение. В «Журнал аудита» найдите обе записи. Подadminпроверьте полный аудит и назначение бизнес-роли в «Администрирование». Подemployeeсобственные безопасные изменения видны в «Мой профиль», но журнал всей компании недоступен.
Короткий сквозной показ: learning → «Мой профиль» (аватар/«О себе») → «Обучение» → quiz и Digital Starter → employee пишет manager через «Чаты» → manager открывает «Команда Backend Development» и нажимает «Сделать AI-сводку» → hr смотрит обучение и карьерный прогресс в HR-аналитике. Для шага со сводкой добавьте OPENAI_API_KEY в локальный .env; остальные шаги доступны сразу после запуска.
Как проверить Career Quest
Для повторяемой демонстрации используется дата среза датасета 2026-10-01, даже если дата ОС другая.
- Войдите как EMPLOYEE. На «Обзоре» открыт
E0028, Backend Engineer, Middle. Без явной цели система строит путь к Senior. - Посмотрите «Ваши следующие шаги»: 1–3 мероприятия с объяснением, приростом навыков, форматом и ближайшей сессией. Вкладка «Моя траектория» показывает текущие/требуемые уровни и критичные разрывы; «История» показывает
completed,no_show,declined,droppedи другие статусы. - Нажмите «Отметить выполненной» на доступной активности. После ответа API появляются запись
completed, новые уровни с учетомgain/max_levelи обновленный процент готовности. Повторная отметка недопустимой активности отклоняется. - Войдите как HR. Откройте «HR аналитика»: частые gaps, сотрудники без подходящего шага, таблица участия по активностям. Загрузите новые
employees.jsonи/илиactivity_history.csvчерез форму внизу. - Войдите как ADMIN. Создайте нового EMPLOYEE и привяжите к только что импортированному employee ID; проверьте его персональные рекомендации.
Demo Learning Scenario
Это самостоятельный демонстрационный курс «Компьютерная грамотность: периферийные устройства»: четыре коротких урока, пять вопросов и проходной результат 80%. Он хранится в data/demo_learning.json и собственных таблицах learning_*, quiz_questions, achievements, employee_achievements. Исходные events.json и skills.json не изменяются. Курс связан с существующим навыком Technical Troubleshooting: базовая диагностика периферии — часть этого навыка. Карточка обучения предлагается по разрыву до целевого грейда; OpenAI ранжирует исходные мероприятия отдельно и не подменяет учебный контент.
Для жюри используйте learning / DemoLearning!2026 (или [email скрыт]). Это отдельный EMPLOYEE, привязанный к E0021 — Botagoz Zhumabekova, Customer Support Specialist, Middle. Исходно Technical Troubleshooting имеет уровень 2, цель Senior требует 3; курс дает +1 с пределом 3. На чистой БД готовность до прохождения — 69%, после — 71%.
- Откройте
http://localhost:3000, войдите какlearning. На «Обзоре» найдите карточку «Рекомендованное демо-обучение»: она объясняет skill gap и ожидаемый прирост. Нажмите «Открыть обучение». Курс также доступен через пункт меню «Обучение». - Нажмите «Начать обучение». Последовательно прочитайте четыре карточки: периферия и ввод, ввод/вывод на практике, внешние накопители и USB, безопасная работа. Кнопка «Следующий урок» сохраняет прогресс в PostgreSQL; после четвертой карточки откроется тест.
- Ответьте на пять вопросов. При результате 4/5 или 5/5 курс получает
completed. При меньшем результате попытка сохраняется, уроки остаются пройденными и quiz можно повторить. - После успешного теста появится анимированное окно Digital Starter с оценкой, изменением навыка
2 → 3и готовности. В профиле на «Обзоре» откройте «Достижения»; при первом завершении возможен также First Step. - Перейдите в «Моя траектория» и проверьте новый уровень Technical Troubleshooting и процент готовности. Перезагрузите страницу, снова откройте «Обучение» и «Достижения»:
completed, результат и badge не исчезают. - Выйдите, войдите как
hr/DemoHR!2026. Откройте «HR аналитика» → «Обучение и достижения»: сотрудник E0021 отображается с прогрессом, оценкой и badges. Под ADMIN в «Администрирование» доступен обзор модуля и каталога достижений.
Проверка на отдельном тестовом профиле, которая не завершает курс для жюри:
node scripts/learning-smoke.mjs
Скрипт создает временного сотрудника и учетную запись, проходит уроки, сначала проваливает quiz, затем получает 100%, проверяет рост навыка и готовности, badge, запреты RBAC и сохранение результата при новом GET. Чтобы вернуть демо-аккаунт learning к исходному состоянию после ручного показа, используйте новую БД/Compose volume; удаление Docker volume стирает и другие локальные данные.
Рекомендация исключает mandatory/compliance, неподходящие текущему грейду/роли события, неудовлетворенные prerequisites, прошедшие сессии, in_progress и уже завершенные активности (кроме повторяемого клуба). Разрывы считаются от требований следующего грейда с приоритетом critical skills. История completed, no_show, declined, dropped влияет на оценку. Навык после завершения: max(current, min(5, max_level, current + gain)). Завершения после последней оценки применяются по хронологии, старые не считаются дважды. Готовность — round(100 × (1 − сумма оставшихся разрывов / сумма требуемых уровней)); грейд автоматически не присваивается.
При наличии OPENAI_API_KEY backend отправляет только допустимый shortlist в OpenAI Responses API. Ответ модели сверяется с допустимыми ID. Без ключа или при ошибке OpenAI используется прозрачное правило ранжирования; UI показывает «Умный подбор» вместо «OpenAI recommendation». Объяснение строится из проверенных данных. OpenAI-ключ никогда не передается frontend.
AI Architecture
| Функция | Что считает backend | Что получает OpenAI | Поведение без ключа |
|---|---|---|---|
| AI Career Recommendation | Следующий грейд, skill gaps, critical skills, история, prerequisites и допустимые события | Короткий список уже допустимых event ID для ранжирования; результат проверяется по whitelist | Backend возвращает 1–3 шага по воспроизводимому правилу |
| AI Chat Summary | RBAC на чат и сообщения, период/лимит до 50 сообщений, удаление возможных секретов | Только разрешённый краткий контекст; JSON с темами, решениями, задачами и вопросами | Endpoint отвечает 503; фиктивная сводка не создаётся |
Исходные 200 employee-профилей, каталог навыков и полная история чатов не отправляются в LLM. Ключ OPENAI_API_KEY читается только сервером. Для сводок используется store:false, результаты и охваченный период записываются в PostgreSQL. AI-вывод следует сверять с исходными сообщениями; оценок сотрудников и рейтингов система не формирует.
Структура проекта
React + Vite + TypeScript (5173 в dev, :3000 в Docker)
│ /api + HttpOnly cookie
▼
Express + TypeScript (:3001)
├─ auth, бизнес-роли и серверный RBAC
├─ рекомендации/траектории и импорт
├─ отдельные demo learning и achievements
├─ личные профили, кадровое редактирование и аудит
├─ корпоративные чаты и AI-сводки
├─ OpenAI Responses API (опционально для рекомендаций, обязательно для сводок)
└─ PostgreSQL 16 / Supabase PostgreSQL
| Путь | Назначение |
|---|---|
src/App.tsx, src/styles.css | Существующие экраны Career Quest и адаптивная компоновка |
src/LoginPage.tsx, src/AdminPanel.tsx, src/auth.css | Вход, управление пользователями, мобильные стили |
src/api.ts | Клиент API и реакция на истекшую сессию |
server/index.ts | REST API и серверная проверка прав |
server/auth.ts, server/admin.ts | Пароли, сессии, RBAC и CRUD пользователей |
server/profile.ts, server/audit.ts | Личный кабинет, кадровые поля, история входов и журнал изменений |
server/chats.ts, server/aiChat.ts | Участники, сообщения, правила доступа и OpenAI-сводки |
src/ProfilePage.tsx, src/TeamPage.tsx, src/AuditPage.tsx | Личный кабинет, команда и журнал аудита |
src/ChatsPage.tsx, src/social.css | Корпоративные чаты и адаптивные экраны |
server/domain.ts, server/ai.ts | Расчет навыков/допуска и OpenAI-ранжирование |
server/learning.ts, data/demo_learning.json | Уроки, quiz, попытки, прогресс и достижения |
src/LearningPage.tsx, src/HRLearningPanel.tsx, src/learning.css | Учебный поток, HR-отчет и адаптивный интерфейс |
server/db.ts, server/schema.sql | PostgreSQL, схема и первоначальный импорт |
server/import.ts | Проверка и транзакционный импорт JSON/CSV |
data/ | Датасет и README.md/README.ru.md/README.kz.md с форматом полей |
scripts/smoke.mjs | Сквозная проверка ролей и карьерного сценария |
scripts/learning-smoke.mjs | Сквозная проверка учебного сценария без расходования аккаунта жюри |
scripts/social-smoke.mjs | Проверка семи демо-ролей, личных и кадровых полей, чатов, аудита и истории входов |
compose.yaml, Dockerfile | Docker запуск приложения и БД |
Environment Variables и PostgreSQL
Для Docker Compose достаточно .env, созданного из .env.example; POSTGRES_PASSWORD нужен контейнеру базы. Compose передает приложению PGHOST, PGPORT, PGDATABASE, PGUSER, PGPASSWORD. Для локального или Supabase PostgreSQL задайте DATABASE_URL в своем .env.
| Variable | Required | Purpose | Example (без настоящих секретов) |
|---|---|---|---|
POSTGRES_PASSWORD | Docker Compose | Пароль PostgreSQL и подключения backend | replace_with_local_password только для локального демо |
DATABASE_URL | Только запуск вне Compose | PostgreSQL/Supabase URI | Пусто в .env.example; заполнить локально |
APP_BIND_HOST | Нет | Интерфейс, на котором опубликован контейнер | 127.0.0.1 |
APP_PORT | Нет | Локальный порт reverse proxy upstream | 3000 |
PORT | Только запуск без Docker | Порт Node.js | 3001 |
APP_ORIGIN | Production | Разрешённый HTTPS origin для записи через API | https://careerquest.absystems.kz |
OPENAI_API_KEY | Только для реальных AI-сводок | OpenAI credential только на backend | Пусто; значение хранить лишь в серверном .env |
OPENAI_MODEL | Нет | Модель Responses API | gpt-4.1-mini |
На VPS задайте длинный случайный POSTGRES_PASSWORD до первой инициализации volume и APP_ORIGIN=https://careerquest.absystems.kz. Изменение строки пароля в .env после создания БД само по себе не меняет пароль уже существующего PostgreSQL-пользователя. .env.example содержит только безопасные заглушки. Ключ OpenAI не нужен для запуска, детерминированной карьерной рекомендации, обучения и HR Analytics.
Для Supabase: создайте проект, возьмите PostgreSQL URI в настройках Database и поместите его только в локальный DATABASE_URL (используйте Session Pooler, если требуется сетью). Пароль URI должен быть URL-кодирован при специальных символах. Приложение использует Supabase как PostgreSQL; Supabase service key не нужен. Схема из server/schema.sql применяется автоматически при запуске, после нее импортируются исходные файлы и отдельный demo learning content. Повторный запуск не стирает попытки, статусы и достижения. В SQL Editor Supabase можно выполнить содержимое server/schema.sql заранее, но приложение сделает это само.
Локальный запуск frontend/backend без Docker
Нужны Node.js 22+, npm и PostgreSQL 16+ (либо Supabase). Создайте пустую БД и пользователя с правом создавать таблицы, задайте DATABASE_URL в .env.
cp .env.example .env
npm ci
npm run dev
Откройте http://localhost:5173. Vite проксирует /api на http://localhost:3001. Локальный .env уже содержит APP_ORIGIN=http://localhost:5173 для проверки Origin. В PowerShell используйте Copy-Item вместо cp.
Для production-сборки без Docker:
npm run build
npm start
Приложение доступно на http://localhost:3001. Пустую БД можно предварительно инициализировать командой psql "$DATABASE_URL" -f server/schema.sql, но при обычном запуске миграция и seed выполняются автоматически. После обновления существующего стенда новые таблицы профилей, чатов и аудита создаются без удаления старых HR-данных.
Production Deployment — Ubuntu VPS
Адрес приложения: https://careerquest.absystems.kz. Нужны Ubuntu VPS с Docker Engine, Compose plugin, Nginx и доступом VPS к приватному GitHub-репозиторию (например, read-only deploy key). Официальная инструкция Docker для Ubuntu описывает установку Engine и Compose plugin. Эти команды выполняются на VPS после SSH-входа; адрес SSH, пароль, private deploy key и OpenAI-ключ не записывайте в репозиторий. DNS приложение не меняет. На текущем общем VPS порт 127.0.0.1:3000 занят другим сервисом, поэтому Career Quest использует 127.0.0.1:3012; на отдельном VPS можно выбрать свободный порт.
1. Clone и серверный .env
git clone [email protected]:BAITC-Hacks/hack-f02d3fd7-a-b-systems.git
cd hack-f02d3fd7-a-b-systems
cp .env.example .env
chmod 600 .env
nano .env
Доступ к приватному репозиторию нужно выдать VPS до git clone и git pull; публикуйте на GitHub только публичную часть deploy key. В .env замените заглушку POSTGRES_PASSWORD на новый случайный пароль, задайте APP_ORIGIN=https://careerquest.absystems.kz, оставьте APP_BIND_HOST=127.0.0.1 и установите APP_PORT=3012 для текущего VPS. OPENAI_API_KEY добавьте только на сервере, если нужны реальные AI-сводки. Не используйте пароль SSH как пароль БД. Сохраните файл с режимом 600.
2. Build, migrations/seed, запуск
docker compose config --quiet
docker compose build
docker compose run --rm app node dist/server/migrate.js
docker compose up -d
docker compose ps
curl -fsS http://127.0.0.1:3012/api/health
migrate.js применяет server/schema.sql, импортирует исходный dataset на пустой БД и создаёт демо-аккаунты, курс и чаты. Шаг повторяемый; приложение также выполняет его при собственном старте. Данные PostgreSQL находятся в именованном volume career_quest_db и сохраняются после restart и down без -v. docker compose ps должен показывать healthy для db и app; endpoint должен вернуть {"ok":true,"database":"ready"}. Container app работает от непривилегированного пользователя Node. PostgreSQL не публикует порт на хост; Node доступен только с 127.0.0.1:3012 на текущем VPS.
3. Nginx и HTTPS на одном домене
React build и /api обслуживает один Express-сервис. CORS для браузера не нужен: frontend делает относительные запросы /api на тот же домен. Reverse proxy должен передавать Host и X-Forwarded-Proto; это необходимо для Secure cookie и проверки Origin. Образец конфигурации — deploy/nginx/careerquest.conf.example, upstream в нём по умолчанию 127.0.0.1:3000; для текущего VPS замените на 127.0.0.1:3012. Лимит тела 20 МБ рассчитан на два импортируемых файла до 8 МБ и аватары.
Перед активацией образца проверьте существующие vhost: на домене уже может работать другой сайт. Не добавляйте второй server_name поверх него. Для нового vhost на текущем VPS:
sudo nginx -T 2>&1 | grep -n 'careerquest.absystems.kz'
sed 's/127.0.0.1:3000/127.0.0.1:3012/' deploy/nginx/careerquest.conf.example | sudo tee /etc/nginx/sites-available/careerquest.absystems.kz >/dev/null
sudo ln -s /etc/nginx/sites-available/careerquest.absystems.kz /etc/nginx/sites-enabled/careerquest.absystems.kz
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d careerquest.absystems.kz --redirect
curl -fsS https://careerquest.absystems.kz/api/health
Если vhost уже создан, пропустите команды sed/ln и проверьте фактический upstream. Если сертификат ещё не выпущен, следуйте инструкции Certbot для Nginx; затем можно проверить продление sudo certbot renew --dry-run. До корректного сертификата не считайте HTTPS deployment завершённым. Текущий Nginx и его существующие сайты проверяйте перед изменениями.
4. Логи, обновление, backup, restart и rollback
docker compose ps
docker compose logs --tail=100 app db
mkdir -p backups && chmod 700 backups
umask 077
docker compose exec -T db pg_dump -U career_quest -d career_quest -Fc > "backups/career_quest_$(date +%F_%H%M%S).dump"
Файлы backups/ игнорируются Git, но их нужно копировать в отдельное защищённое хранилище. Перед обновлением из main запомните предыдущий commit и сделайте backup:
git rev-parse HEAD > .deploy-previous-revision
git pull --ff-only origin main
docker compose config --quiet
docker compose build
docker compose run --rm app node dist/server/migrate.js
docker compose up -d
docker compose ps
curl -fsS http://127.0.0.1:3012/api/health
Перезапуск приложения не сбрасывает PostgreSQL:
docker compose restart app
curl -fsS http://127.0.0.1:3012/api/health
Если новый код не работает, верните предыдущую версию приложения (файл .deploy-previous-revision игнорируется Git):
git switch --detach "$(cat .deploy-previous-revision)"
docker compose build app
docker compose up -d --no-deps app
curl -fsS http://127.0.0.1:3012/api/health
Это не откатывает данные БД; перед обновлением нужен dump. Миграции в проекте добавочные, но совместимость старой версии с новой схемой всё равно нужно проверять. Для следующего обновления вернитесь на main командой git switch main и выполните проверку/обновление заново. Не используйте docker compose down -v на VPS: флаг -v удаляет PostgreSQL volume.
Dataset и загрузка данных жюри
Файл в data/ | Назначение |
|---|---|
employees.json | 200 синтетических сотрудников: роль, грейд, навыки, цель, руководитель |
skills.json | 60 навыков и требования 32 профилей ролей/грейдов |
events.json | 40 активностей, prerequisites, развиваемые навыки, gain/max_level |
activity_history.csv | 2743 записи участия со статусами completed, no_show, declined, dropped и др. |
demo_learning.json | Отдельный demo-курс; не изменяет смысл исходного каталога организаторов |
Формат входных полей описан в data/README.ru.md, также есть data/README.md и data/README.kz.md. Чтобы загрузить дополнительные данные:
- Войдите как
hrилиadmin, откройте «HR аналитика» → «Загрузить проверочные данные». - Выберите
employees.jsonи/илиactivity_history.csvтого же формата. Если CSV ссылается на нового сотрудника, отправьте оба файла одним импортом. - Нажмите «Импортировать» и проверьте ответ с числом добавленных/обновлённых записей. Совпадающие
employee_id/record_idобновляются, новые добавляются; неизвестные навыки, роли и мероприятия отклоняются. Лимит каждого файла — 8 МБ. - Найдите employee ID в «Команда» или HR Analytics и проверьте рекомендации. Для личного входа нового сотрудника
adminотдельно создаёт учетную запись и привязывает её к этому employee ID.
Screenshots
Скриншоты сделаны на синтетических демо-профилях, без API-ключей и серверных секретов.
| Карьерный обзор | Обучение и achievement |
|---|---|
![]() | ![]() |
| HR Analytics | Чат и OpenAI-сводка |
|---|---|
![]() | ![]() |
Другие экраны: Login, Career trajectory, Admin, Audit Log, Mobile chat.
Проверка сборки и API
npm test
npx tsc -p tsconfig.json --noEmit
npm run build
docker compose up --build -d
node scripts/smoke.mjs
node scripts/learning-smoke.mjs
node scripts/social-smoke.mjs
В PowerShell команды npm/npx при запрете .ps1 выполняются как npm.cmd/npx.cmd. Основной smoke-тест проверяет карьерный сценарий и три системные роли, learning smoke — quiz и achievement. social-smoke.mjs проверяет семь демо-ролей, запрет изменения кадровых и системных полей сотрудником, однократную дату рождения и исправление ADMIN, аватар, пароль, историю входов, фильтры аудита, видимость/запреты чатов и изоляцию клиента. Smoke-скрипты добавляют проверочных пользователей с уникальными ID в локальную БД; для чистого повторного показа используйте новую БД или Docker volume.
Known Limitations
- Публичные демо-аккаунты предназначены для локального стенда; перед эксплуатацией нужно сменить пароли и использовать HTTPS. Корпоративное SSO/MFA и централизованная неизменяемая SIEM-интеграция не реализованы; локальный аудит изменений и входов хранится в PostgreSQL.
- При отсутствии OpenAI-ключа работает воспроизводимый расчетный подбор. Реальный вызов OpenAI требует собственного ключа и доступа аккаунта.
- AI-сводки требуют OpenAI-ключ и доступ к API. Чаты обновляются опросом каждые 5 секунд, без WebSocket и вложений. Сводка — помощь для просмотра разговора; её вывод следует сверять с исходными сообщениями. Передача рабочих сообщений в OpenAI в реальном банке требует согласованной политики обработки данных.
- Полный перевод интерфейса после смены предпочитаемого языка и корпоративная интеграция с HRIS/идентификатором сотрудника пока не реализованы. Демонстрационный внешний клиент — локальная учетная запись, без публичной регистрации.
- Каталог датирован
2026-10-01: после его последних сессий часть запланированных мероприятий перестанет быть доступна; self-paced остаются. - Завершение активности подтверждается самим пользователем или ADMIN. В рабочей системе статус нужно получать из LMS/HRIS или подтверждать ответственным лицом.
- Demo learning содержит один фиксированный модуль и пять вопросов; это демонстрация полного цикла, без авторского редактора курсов, сертификатов и интеграции с LMS. Ручного сброса
completedчерез UI нет. - Готовность отражает покрытие навыков и не заменяет решение о повышении. Интерфейс русскоязычный, исходные названия навыков/событий сохранены на английском.
HackAlem AI / Halyk Bank
Halyk Career Quest разработан командой A&B Systems для кейса Halyk Bank в рамках HackAlem AI. Это хакатонный прототип внутреннего HR/AI-продукта, а не банковская production-система. Товарные знаки и бренд-материалы Halyk принадлежат их правообладателю и используются только в демонстрационном проекте.
Авторы коммитов
История коммитов
- 2026-09-23 17:22Document live VPS port and verified backup procedureasergazin
- 2026-09-23 17:00Prepare Career Quest for Docker Compose production deploymentasergazin
- 2026-09-23 16:24feat: add audited profiles, corporate chat and AI summariesasergazin
- 2026-09-23 15:40Apply official Halyk branding and faviconasergazin
- 2026-09-23 15:26Harden learning completion and verify career progressasergazin
- 2026-09-23 15:17Add demo learning course, quiz, achievements and HR progressasergazin
- 2026-09-23 14:51Add secure authentication, RBAC, admin users and responsive UIasergazin
- 2026-09-23 14:18feat: implement Career Quest recommendations and HR dashboardasergazin
Все коммиты (9)
- 2026-09-23 14:07docs: initialize Career Quest README and ignore rulesasergazin
Структура репозитория (72 файлов)
.dockerignore .env.example .gitignore Dockerfile README.md compose.yaml data/README.kz.md data/README.md data/README.ru.md data/activity_history.csv data/demo_learning.json data/employees.json data/events.json data/skills.json deploy/nginx/careerquest.conf.example docs/screenshots/admin-users.png docs/screenshots/audit-log.png docs/screenshots/career-trajectory.png docs/screenshots/chat-ai-summary.png docs/screenshots/chat-mobile.png docs/screenshots/employee-dashboard.png docs/screenshots/hr-analytics.png docs/screenshots/learning-achievement-mobile.png docs/screenshots/login.png index.html package-lock.json package.json public/brand/halyk-favicon.ico public/brand/halyk-favicon.svg public/brand/halyk-logo-white.svg public/brand/halyk-logo.svg scripts/learning-smoke.mjs scripts/smoke.mjs scripts/social-smoke.mjs server/admin.ts server/ai.test.ts server/ai.ts server/aiChat.ts server/audit.ts server/auth.ts server/chats.ts server/db.ts server/domain.test.ts server/domain.ts server/import.ts server/index.ts server/learning.ts server/migrate.ts server/profile.ts server/schema.sql server/types.ts src/AdminPanel.tsx src/App.tsx src/AuditPage.tsx src/Brand.tsx src/ChatsPage.tsx src/HRLearningPanel.tsx src/LearningPage.tsx src/LoginPage.tsx src/ProfilePage.tsx src/TeamPage.tsx src/UserAvatar.tsx src/api.ts src/auth.css src/branding.css src/learning.css src/main.tsx src/social.css src/styles.css tsconfig.json tsconfig.server.json vite.config.ts
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.



