Career Quest
Веб-приложение Career Quest: сотрудник получает 1–3 объяснимых шага развития к следующему грейду, HR видит дефициты компетенций, участие и…
О проекте
Команда: IRTIDA
Кейс HackAlem.ai: Менеджмент — Halyk Bank · кейс 1
Стадия: Доведённый продукт
Задача кейса: «Career Quest»: AI-навигатор, связывающий навыки сотрудника с шагами развития
Суть
Веб-приложение Career Quest: сотрудник получает 1–3 объяснимых шага развития к следующему грейду, HR видит дефициты компетенций, участие и сотрудников без доступного шага. Импортирует официальный Kit (200 профилей, 60 навыков, 40 событий, 2 743 записи истории).
Как устроено
Kit импортируется в SQLite; по умолчанию AI_PROVIDER=rules — детерминированный многофакторный подбор мероприятий по следующему грейду, разрыву и критичности навыков, истории участия, prerequisites и расписанию. Опциональный модуль NVIDIA Career AI (Nemotron 3 Super) одним запросом формулирует до трёх персональных практических заданий; ответ валидируется по JSON-схеме и ID мероприятий/навыков, а прирост навыков считает сервер, не LLM. Есть роли (сотрудник, HR, руководитель, оператор, супервизор, клиент), приглашения с хешированными кодами, scrypt-пароли, RU/EN/ҚАЗ.
Ключевые решения
- rule-based multi-factor recommendation
- JSON schema validation of LLM output
- fallback to rules
- scrypt password hashing
- invite-code RBAC
Особенности
Чёткое разделение: LLM только формулирует практику, а числовой эффект и рост навыков считает сервер по каталогу; повтор активности не начисляет прирост дважды. В LLM не передаются имя, ID сотрудника и сырая история. Большой набор тестов (backend + frontend e2e) и Windows-лаунчер с автоподбором порта.
Стек
Python · FastAPI · SQLite · React · TypeScript · Vite · Docker · GitHub Actions
Модели
NVIDIA Nemotron 3 Super · OpenAI
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-aa88eec9-irtida.
README
README.mdCareer Quest
AI-навигатор развития сотрудников для HackAlem AI, трек Halyk Bank. Связывает обучение с карьерной целью: профиль → требования следующего грейда → 1–3 объяснимых шага → выполнение → обновлённые навыки. HR видит дефициты компетенций, участие и сотрудников без доступного следующего шага. Публичных рейтингов сотрудников нет.
Поддерживаются все восемь профессиональных ролей Kit: разработка, аналитика, QA, продукт, HR, продажи и клиентская поддержка. Тип аккаунта выбирается отдельно: сотрудник, HR, руководитель подразделения, оператор, супервизор или клиент контакт-центра. Голосовой робот относится к кейсу Voice Router; для клиента здесь добавлен отдельный вход и личный кабинет, без голосового AI.
Нужен HR-доступ для выдачи приглашений? На компьютере с базой данных запустите create-hr.bat после первого запуска start.bat. Батник попросит новый логин, имя и пароль в терминале и создаст HR-аккаунт без приглашения, даже если первый HR уже есть. Он показывает путь к выбранной базе: по умолчанию используется data/career-quest-kit.db при наличии Kit; при заданном DATABASE_URL — указанная база. Существующие аккаунты и прогресс сохраняются. После создания войдите с ролью HR и откройте «Аккаунты и доступ» для выдачи кодов сотрудникам. Храните доступ к этому локальному административному батнику только у тех, кто управляет сервером.
Запуск на Windows
Нужны Python 3.11+, Node.js 22+ и npm. Дважды щёлкните start.bat в корне проекта или выполните:
.\start.bat
Скрипт создаёт .venv, устанавливает недостающие зависимости, собирает frontend, запускает FastAPI и открывает браузер после готовности сервера. Первый запуск требует интернета для зависимостей. Остановка — Ctrl+C в окне запуска.
Обычный адрес — http://127.0.0.1:8000. Если порт занят, выбирается следующий свободный из ближайших 50; смотрите фактический адрес в окне запуска. Windows 10048 означает занятый порт, а не ошибку сборки frontend. Чужие процессы не закрываются.
.\start.bat 8017
.\run.ps1 -Port 8017 -NoBrowser
# Ошибка вместо автоматического выбора другого порта:
.\run.ps1 -Port 8017 -StrictPort
Другие ОС или терминал: python run.py, с --open-browser для открытия браузера. Для Python вне PATH: ./run.ps1 -PythonExe 'C:\path\to\python.exe'. Launcher добавляет loopback-origin выбранного порта к ALLOWED_ORIGINS, сохраняя остальные адреса.
После обновления зависимостей: .venv\Scripts\python.exe -m pip install -r server/requirements-dev.txt и npm.cmd --prefix web ci.
Полный Kit и сохранение данных
Локальный каталог: career_quest_dataset/case_1/career_quest_dataset/. Launcher автоматически импортирует четыре исходных файла в новую базу data/career-quest-kit.db:
| Данные | Количество |
|---|---|
| Профили сотрудников | 200 |
| Навыки | 60 |
| События | 40 |
| Записи истории за 24 месяца | 2 743 |
| Профессиональные роли | 8 |
Импорт выполняется один раз. Повторный запуск сохраняет аккаунты, приглашения, прогресс и профили жюри. Старая база data/career-quest.db не удаляется. Явный DATABASE_URL имеет приоритет: неизменённый исходный demo можно заменить, а demo с прогрессом требует нового пути БД.
На другой машине положите Kit в этот каталог либо задайте CAREER_QUEST_KIT_DIR абсолютным путём к четырём файлам. Без Kit приложение запускается с пустой базой: первый HR загрузит набор через Импорт данных. Kit и SQLite не публикуются в Git.
employees.json содержит профили, а не готовые пароли. Все 40 событий видны HR, но конкретному сотруднику предлагаются только подходящие по роли, грейду, prerequisites, истории, расписанию и приросту. Четыре обязательных события исключены из добровольных квестов.
Первый вход и аккаунты
- На новой базе откройте первичную настройку HR на странице входа: имя, логин и пароль от 12 символов. Она закрывается после создания первого HR. Если HR-доступа больше нет, локальный администратор запускает
create-hr.batна сервере и создаёт дополнительную учётную запись без изменения старой. Обычная форма по умолчанию предлагает вход сотруднику. - В HR → Аккаунты и доступ выберите внутреннюю роль и профиль сотрудника из Kit, затем создайте приглашение. Для второго HR профиль сотрудника не требуется.
- Передайте одноразовый код участнику. Он действует 24 часа; в базе хранится только хеш. Приложение само не отправляет письма.
- Участник выбирает регистрацию и свою роль в раскрывающемся списке, задаёт логин и пароль. Приглашение подтверждает внутреннюю роль и связывает аккаунт с конкретным employee_id.
- Клиент контакт-центра выбирает роль клиента и регистрируется без приглашения: имя, логин и пароль. Такой аккаунт не создаёт профиль сотрудника и не получает доступ к данным компании.
- Затем используется обычный вход с тем же типом аккаунта. Выбор привилегированной роли в списке сам по себе не выдаёт права.
| Тип аккаунта | Доступ |
|---|---|
| Сотрудник | Личная траектория, навыки, история и выполнение собственных квестов |
| Оператор контакт-центра | Собственное профессиональное развитие, как у другого сотрудника |
| Руководитель подразделения / супервизор | Личное развитие и просмотр прямых подчинённых по manager_id из Kit; без доступа к чужим командам |
| HR-специалист | Общая команда, каталог, аналитика, импорт и приглашения |
| Клиент контакт-центра | Отдельный личный кабинет; без HR, профилей сотрудников и корпоративной истории |
Руководитель, супервизор и HR не завершают квесты за других людей. Кнопка пользователя в верхней панели открывает аккаунт. Все пункты breadcrumb, включая текущий, — ссылки на конкретные разделы; адрес сохраняет выбранный профиль, поддерживает обновление и переходы назад/вперёд. Сервер проверяет доступ и при открытии прямой ссылки.
Центр интерфейса сотрудника — следующий полезный шаг: его связь с целью, фактический ожидаемый прирост навыков и собственный прогресс. Сравнения с коллегами и обязательных наград нет. Переключатель RU / EN / ҚАЗ переводит интерфейс, стандартные названия Kit и объяснения; произвольные импортированные описания сохраняют язык источника.
Пароли хешируются scrypt с солью. Сессия — HttpOnly/SameSite=Strict cookie на 8 часов; попытки входа ограничены. DEMO_MODE=false по умолчанию. Старый /auth/demo оставлен для изолированных тестов с явным DEMO_MODE=true; этот режим позволяет вход без пароля и не подходит для обычной эксплуатации.
Как проверить решение
- Запустить
start.bat, создать HR, проверить 200 сотрудников / 40 событий / 60 навыков. - Открыть профили разных ролей, включая продажи и поддержку. Проверить грейд, историю, навыки и требования следующего уровня.
- Создать приглашение, зарегистрироваться сотрудником, запросить 1–3 рекомендации. Обоснование содержит грейд, разрывы, требования следующего уровня и историю участия.
- Сравнить ожидаемый прирост с результатом выполнения квеста. Обновить страницу: прогресс сохраняется. Повтор той же активности/сессии не начисляет прирост второй раз.
- Вернуться в HR: дефициты, отсутствие шага с причинами, участие, каталог, импорт и аккаунты. У сотрудника нет доступа к чужим профилям или HR API.
- Проверить раскрывающийся список всех шести ролей при входе/регистрации, три языка и профиль из верхней панели. Пригласить руководителя или супервизора на профиль с подчинёнными: в обзоре только его команда.
- Открыть прямую ссылку на профиль/вкладку, обновить страницу, проверить назад/вперёд и ссылку текущего breadcrumb. Чужой профиль сотруднику недоступен даже по скопированной ссылке.
- Зарегистрировать клиента без приглашения: доступен только собственный кабинет, без корпоративной информации. Через HR-импорт загрузить профили/историю жюри в исходной схеме.
- Включить
NVIDIA_AI_MOCK=trueи проверить персональную практику без ключа. Для живой проверки после разрешения на облачную обработку настроить NVIDIA по разделу ниже и убедиться, что ответ имеетmode=nvidia, а ID исходного мероприятия существует в каталоге. Проверить, что упражнение само не меняет уровень навыка.
Нейросеть NVIDIA и рекомендации
В проект интегрирован модуль NVIDIA Career AI на базе готовой LLM NVIDIA Nemotron 3 Super. Он берёт текущие навыки сотрудника из backend, сверяет их с требованиями следующего грейда в текущей роли, отбирает доступные мероприятия из Kit и одним запросом к NVIDIA формулирует до трёх персональных практических заданий. Ответ проходит проверку JSON, ID мероприятий и навыков. Числовой эффект рассчитывает сервер по каталогу, а не нейросеть. Практическое задание — совет по подготовке к мероприятию; само по себе оно не начисляет баллы и не повышает уровень навыка. Рост происходит при подтверждённом выполнении исходного мероприятия.
По умолчанию AI_PROVIDER=rules — объяснимый многофакторный подбор мероприятий без сетевого вызова нейросети. Он учитывает следующий грейд, разрыв и критичность навыков, историю участия и допустимость события. На экране указывается фактический режим ответа. Нейросеть не обучалась на профилях Kit: используется готовая модель с проверяемым контекстом. Имя, ID сотрудника и строки сырой истории не отправляются провайдеру.
Для подбора 1–3 исходных мероприятий сохраняются адаптеры OpenAI/NVIDIA: модель выбирает ID из допустимого списка, а backend валидирует ответ и рассчитывает прирост. Новая NVIDIA-персонализация добавляет практическое упражнение и объяснение для текущего профиля. При недоступности провайдера основной подбор остаётся доступным по правилам; такой ответ явно помечается fallback.
Для живого запроса получите ключ на странице NVIDIA Nemotron 3 Super. В корне этого проекта создайте .env из шаблона, если его ещё нет, и откройте для редактирования:
if (-not (Test-Path .env)) { Copy-Item .env.example .env }
notepad .env
Заполните серверные настройки в .env:
AI_PROVIDER=nvidia
NVIDIA_API_KEY=вставьте_свой_ключ_локально
NVIDIA_MODEL=nvidia/nemotron-3-super-120b-a12b
NVIDIA_AI_MOCK=false
NVIDIA_TIMEOUT_SECONDS=8
NVIDIA_MAX_TOKENS=1800
AI_DATA_POLICY_APPROVED=true
AI_DATA_POLICY_APPROVED=true ставьте только после разрешения организаторов на передачу соответствующих данных облачному сервису; синтетичность Kit сама по себе не отменяет это ограничение. Ключ остаётся только на backend: не отправляйте его в чат, Git или VITE_*. .env игнорируется Git. Перезапустите start.bat, войдите сотрудником с профилем Kit и нажмите кнопку персональной практики в профиле. Endpoint POST /api/v1/employees/{employee_id}/personalization берёт навыки из текущей базы и разрешает запрос только на свой профиль; тело запроса с данными сотрудника ему не нужно. Нужен каталог формата Kit, но сами файлы после импорта модулю уже не требуются. Межролевой переход из career_goal новый модуль пока не моделирует.
Проверка без ключа и расходов: в .env оставьте AI_PROVIDER=rules, задайте NVIDIA_AI_MOCK=true и перезапустите start.bat. Та же кнопка выдаёт mode=mock на основе текущих данных базы, не обращаясь к NVIDIA. Это проверяет сценарий и формат ответа, но не является доказательством живой нейросети. Чтобы сделать один настоящий вызов, верните NVIDIA_AI_MOCK=false, AI_PROVIDER=nvidia, добавьте ключ и разрешение, перезапустите сервер, затем нажмите кнопку один раз. Успешный ответ нового модуля имеет mode=nvidia и имя модели; в этом окружении живой вызов без ключа не проверялся. При ошибке проверьте ключ/доступ к модели (401/403), квоту (429), имя модели (404) и сеть/таймаут.
Дополнительный прежний адаптер OpenAI включается через AI_PROVIDER=openai, OPENAI_API_KEY и OPENAI_MODEL. Он используется для выбора исходных мероприятий, а не для новых практических заданий NVIDIA.
| Режим | Значение |
|---|---|
ai | Проверенный модельный выбор исходных мероприятий (/recommendations) с provider/model |
rules | Подбор исходных мероприятий без нейросети |
fallback | Облачный выбор недоступен или ответ невалиден; показан подбор по правилам |
nvidia | Проверенная живая персональная практика нового модуля (/personalization) |
mock | Локальная проверка персональной практики без сетевого запроса |
no_candidates | Нет допустимых активностей; сетевой запрос не нужен |
cached=true | Сохранённый ответ /recommendations указанного режима |
Бюджет прежнего AI-подбора — 7 секунд, максимум 8, без повторов. Его кэш — час, fallback — 30 секунд; квоты — 6 запросов/минуту на профиль и 300/сутки на приложение. Это не денежный бюджет. Новый модуль делает один ограниченный NVIDIA-запрос без скрытого повтора. Фактическая задержка и качество русского/казахского ответа требуют живой проверки. store=false в OpenAI не является гарантией Zero Data Retention.
Обычные автоматические тесты не используют сеть и ключи. Из корня проекта на Windows можно отдельно проверить интеграцию: .venv\Scripts\python.exe -m pytest -q server/tests/test_nvidia_personalization.py. Затем запустите .\start.bat и выполните описанные выше шаги через интерфейс. Команда .venv\Scripts\python.exe -m server.app.ai.smoke --synthetic проверяет только старый OpenAI-адаптер; работу нового NVIDIA-модуля подтверждает ответ с фактическим mode=nvidia.
Импорт Kit и профилей жюри
HR → Импорт данных → выбрать employees.json, skills.json, events.json, activity_history.csv → Проверить → просмотреть счётчики → Импортировать. Изменение файлов требует новой проверки. Импорт атомарен; ошибки содержат файл и поле.
Для дополнительного профиля/истории в базе Kit достаточно employees.json и/или activity_history.csv. Сохраняйте исходные оболочки JSON с meta, имена файлов и колонки CSV. Ссылки должны существовать или поступать одновременно. Повтор одинаковых записей не создаёт дублей; конфликтующий ID отклоняет запрос. Форматы demo-v1 и kit-v1 не смешиваются.
API: POST /api/v1/imports/kit?dry_run=true|false&replace_demo=true|false, multipart files, максимум 5 000 000 байт. Полный набор: 200/60/40/2 743, completed_after_review=318, предупреждение о 544 повторных обязательных мероприятиях. Эти записи сохраняются и не дают прироста. Замена demo допускается только без прогресса и связанных аккаунтов/приглашений.
Локальный CLI без браузера:
$env:DATABASE_URL='sqlite:///./data/private/rehearsal.db'
.venv\Scripts\python.exe -m server.app.import_kit_cli 'career_quest_dataset/case_1/career_quest_dataset' --dry-run
.venv\Scripts\python.exe -m server.app.import_kit_cli 'career_quest_dataset/case_1/career_quest_dataset'
python run.py
Расчёт прогресса
- Срез Kit — 2026-10-01. Уровни относятся к
last_review_date; завершения строго после оценки воспроизводят прирост. Отсутствующий навык Kit равен 0. - Прирост:
max(0, min(gain, max_level - current, 5 - current)). Прогноз и завершение используют одну серверную логику. - Траектория: Junior → Middle → Senior → Lead в текущей роли. У Lead нет следующего грейда.
career_goalсохраняется; смена роли пока не моделируется. - Покрытие:
100 × sum(min(current, required)) / sum(required), округление до целого. Это метрика приложения. 100% не повышает грейд автоматически. Critical-навыки отмечены отдельно. - Двойной вес сокращения critical-разрыва в rules — решение приложения, не правило организаторов. Пропуски помогают подобрать альтернативный формат, а не назначить санкции.
- Повторяемое добровольное событие —
EV_036, сoccurrence_idтекущей сессии. Повтор той же сессии идемпотентен. - Все статусы истории сохраняются. HR считает участия, не уникальных людей; совместимый missed уже включает no_show.
Технологии и архитектура
React 19, TypeScript, Vite; Python, FastAPI, SQLAlchemy, SQLite; OpenAI SDK, httpx и Pydantic для NVIDIA; pytest и node:test. Один origin: React → REST /api/v1 → FastAPI → SQLite. AI работает только на backend: интегрированный пакет — server/nvidia_career_ai/, адаптер актуальных данных — server/app/ai/personalization_adapter.py, защищённый маршрут — server/app/ai/personalization_routes.py. Расчёты — server/app/domain/, импорт — kit_import.py/import_service.py, аккаунты — auth.py, локализация — localization.py и web/src/i18n.tsx.
Изменяющие запросы требуют X-Requested-With: CareerQuest и разрешённого Origin. Для HTTPS нужен COOKIE_SECURE=true. Это локальный хакатонный прототип: SSO/MFA, восстановление пароля, production-миграции и резервные копии ещё предстоит настроить. .env, ключи, SQLite, Kit, логи, зависимости и сборки исключены из Git.
Автоматические проверки и разработка
.venv\Scripts\python.exe -m pytest -q
.venv\Scripts\python.exe -m pip check
npm.cmd --prefix web test
npm.cmd --prefix web run build
git diff --check
Браузерный сценарий: npm.cmd --prefix web run test:e2e (нужен установленный Edge; CQ_BROWSER_CHANNEL=chrome выбирает Chrome). Тест использует отдельную синтетическую БД, не браузер пользователя. Скриншоты сохраняются в игнорируемом web/test-results/.
На Linux/macOS используйте npm вместо npm.cmd. Для полного Kit: $env:CAREER_QUEST_KIT_DIR=(Resolve-Path 'career_quest_dataset/case_1/career_quest_dataset').Path. Без переменной внешние данные пропускаются; CI использует независимые synthetic fixtures. Живой HTTP-прогон через frontend API-клиент: npm.cmd --prefix web run test:integration. При проблемах ACL pytest используйте новый пустой путь --basetemp=data/private/pytest-run-unique -p no:cacheprovider.
Разработка: backend python -m server.app.local_server --port 8000; отдельно npm.cmd --prefix web run dev. Добавьте Vite origin в ALLOWED_ORIGINS для POST. Документация API — /docs.
Docker
docker compose up --build
Адрес http://127.0.0.1:8000, БД в томе quest-data. Kit не включён в image: загрузите его через HR. Из-за bridge-адреса клиента первичного HR в Docker создают локально внутри контейнера:
docker compose exec app python -m server.app.setup_account
CLI интерактивно запросит имя, логин и пароль без вывода пароля. После этого войдите в браузере. Настройки .env применяются через docker compose up -d --force-recreate. Фактический Docker smoke в этой Windows-сессии не выполнялся.
Сверка с ТЗ и следующие улучшения: docs/TZ_AUDIT.md. Технические проверки: docs/INTEGRATION.md. Старые handoff-документы описывают промежуточные ветки; текущий README имеет приоритет.
Авторы коммитов
История коммитов
- 2026-09-23 17:59Add safe local HR account creation command and testsn54cnd
- 2026-09-23 17:58Add files via uploadn54cnd
- 2026-09-23 17:46Integrate NVIDIA Career AI personalized practicen54cnd
- 2026-09-23 17:35Add stakeholder accounts and persistent workspace navigationn54cnd
- 2026-09-23 17:17Checkpoint current Career Quest project before navigation updatesn54cnd
- 2026-09-23 17:01Load full Career Quest Kit and add secure trilingual workflowsn54cnd
- 2026-09-23 16:45Add files via uploadn54cnd
- 2026-09-23 15:55Merge completed Career Quest into mainn54cnd
Все коммиты (21)
- 2026-09-23 15:54Add Windows launcher for Career Questn54cnd
- 2026-09-23 15:45Integrate Career Quest frontend, backend and official Kitn54cnd
- 2026-09-23 15:41прототип программы -- на согласовании.bugEnjoyer777
- 2026-09-23 15:35Add files via uploadn54cnd
- 2026-09-23 15:13Document backend API integration and official kit verificationn54cnd
- 2026-09-23 15:10Document frontend contracts and backend integration checksn54cnd
- 2026-09-23 15:07Implement official kit import, deterministic progression, safe AI and backend validationn54cnd
- 2026-09-23 15:07Build gamified career journey and reliable employee and HR flowsn54cnd
- 2026-09-23 14:45Add files via uploadn54cnd
- 2026-09-23 14:28Checkpoint current Career Quest staten54cnd
- 2026-09-23 14:14Split backend and frontend work plansn54cnd
- 2026-09-23 14:01Document GitHub working branchn54cnd
- 2026-09-23 13:59Build Career Quest MVP foundationn54cnd
Структура репозитория (108 файлов)
.dockerignore .env.example .github/workflows/checks.yml .gitignore BACKEND_TASK.md Dockerfile FRONTEND_TASK.md README.md TASKS.md compose.yaml create-hr.bat data/private/.gitkeep docs/BACKEND_HANDOFF.md docs/DECISIONS.md docs/DEMO.md docs/FRONTEND_HANDOFF.md docs/INTEGRATION.md docs/TZ_AUDIT.md docs/VERIFICATION.md examples/additional-profile.json examples/demo.json pytest.ini run.ps1 run.py server/app/__init__.py server/app/ai/__init__.py server/app/ai/personalization_adapter.py server/app/ai/personalization_routes.py server/app/ai/providers.py server/app/ai/smoke.py server/app/auth.py server/app/bootstrap.py server/app/config.py server/app/create_hr_account.py server/app/db.py server/app/domain/__init__.py server/app/domain/progression.py server/app/import_kit_cli.py server/app/import_service.py server/app/ingest.py server/app/kit_import.py server/app/kit_schemas.py server/app/local_server.py server/app/localization.py server/app/main.py server/app/middleware.py server/app/schemas.py server/app/services.py server/app/setup_account.py server/nvidia_career_ai/__init__.py server/nvidia_career_ai/context.py server/nvidia_career_ai/dataset_loader.py server/nvidia_career_ai/nvidia_client.py server/nvidia_career_ai/personalization_service.py server/nvidia_career_ai/prompts.py server/nvidia_career_ai/schemas.py server/requirements-dev.txt server/requirements.txt server/tests/test_ai_provider.py server/tests/test_api_safety.py server/tests/test_auth.py server/tests/test_bootstrap.py server/tests/test_core.py server/tests/test_create_hr_account.py server/tests/test_imports.py server/tests/test_kit_api.py server/tests/test_kit_import.py server/tests/test_launcher.py server/tests/test_localization.py server/tests/test_nvidia_personalization.py server/tests/test_official_kit_local.py server/tests/test_progress_hr.py server/tests/test_roles.py start.bat web/.gitignore web/index.html web/package-lock.json web/package.json web/src/api.ts web/src/components/AccountView.tsx web/src/components/AccountsView.tsx web/src/components/AuthView.tsx web/src/components/CatalogView.tsx web/src/components/HrView.tsx web/src/components/Icons.tsx web/src/components/ImportPanel.tsx web/src/components/ProfileView.tsx web/src/i18n.tsx web/src/import-state.ts web/src/main.tsx web/src/navigation.ts web/src/roles.ts web/src/style.css web/src/styles/app-shell.css web/src/styles/responsive.css web/src/view-model.ts web/tests/auth.test.mjs web/tests/core.test.mjs web/tests/e2e.mjs web/tests/fixtures/import-invalid.json web/tests/fixtures/import-valid.json web/tests/integration-api.mjs web/tests/navigation.test.mjs web/tests/preview-server.mjs web/tests/run.mjs web/tests/views.test.mjs web/tsconfig.json web/vite.config.mjs
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.