Career Quest
AI-навигатор развития: сотрудник видит карьерную траекторию, готовность к целевому грейду и 1–3 рекомендованных шага с прозрачным обоснованием.
О проекте
Команда: DevSpark
Кейс HackAlem.ai: Менеджмент — Halyk Bank · кейс 1
Стадия: Доведённый продукт
Задача кейса: «Career Quest»: AI-навигатор, связывающий навыки сотрудника с шагами развития
Суть
AI-навигатор развития: сотрудник видит карьерную траекторию, готовность к целевому грейду и 1–3 рекомендованных шага с прозрачным обоснованием. У HR есть обзор проседающих компетенций, вовлечённости и риска ухода.
Как устроено
Детерминированный движок считает эффективный уровень навыков с учётом активностей после аттестации и разрывы до цели (критические навыки с весом 3). Он фильтрует допустимые активности и оценивает их как score = gap_value·(0.5+0.5·propensity)·fit·availability, затем жадно отбирает до 3 с диверсификацией. LLM получает шорт-лист топ-8 и выбирает 1–3 шага строгим JSON. Ответ проверяется (ID из шорт-листа, не меньше 3 типов факторов), при ошибке или превышении бюджета 9 с срабатывает режим правил. Есть grounded Q&A «спросите о своём пути», локализация kk/ru/en и HR-импорт.
Ключевые решения
- gap-weighted scoring
- Beta-like propensity estimate
- greedy diversified selection
- LLM shortlist selection
- structured outputs strict JSON
- response validation
- grounded Q&A
- attrition-risk score
- caching
Особенности
Блок «почему не наивный выбор» сравнивает рекомендацию с правилом «самый слабый навык». В eval/ 8 профилей-ловушек для сравнения с бейзлайном. LLM выбирает только из шорт-листа движка и укладывается в лимит 10 с. Числа на лендинге экспортированы из реального прогона продукта.
Стек
Python · FastAPI · Pydantic v2 · Uvicorn · React 18 · Vite · TypeScript · Tailwind CSS · Docker · docker compose · Makefile · pytest
Модели
gpt-4.1-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-c392aa23-devspark.
README
README.mdCareer Quest — AI-навигатор развития сотрудника
Career Quest решает задачу трека Halyk Bank / HackAlem AI (Кейс 1): превратить разрозненный поток HR-событий в понятную траекторию роста с объяснимой рекомендацией следующего шага.
Ядро проекта — качество и объяснимость рекомендации: решение опирается не на один признак («самый слабый навык»), а на грейд, фактический уровень навыков, разрывы до целевого грейда, историю участия, предусловия и доступность. Поверх детерминированного движка работает LLM-слой, который выбирает 1–3 активности из шорт-листа движка и формулирует обоснование на языке сотрудника.
1. Какую проблему решаем и для кого
Сотрудник получает поток HR-активностей без связи с его карьерной целью и требованиями следующего грейда. В результате обучение проходят «для галочки», а на добровольные активности низкая явка, хотя бюджет развития расходуется полностью.
- Основной пользователь — сотрудник с опытом 1–5 лет: видит профиль и траекторию, получает рекомендацию следующего шага с обоснованием, отмечает выполнение и видит, как сдвинулся прогресс.
- Второй пользователь — HR: видит, какие компетенции проседают чаще всего, у кого нет рекомендованного шага и как проходит участие по активностям.
2. Что реализовано
- Профиль и карьерная траектория. Роль, грейд, стаж, цель; лестница грейдов Junior → Middle → Senior → Lead с текущим и целевым; готовность к целевому грейду в %, критические навыки «met x/y», навыки vs требования цели.
- AI-рекомендация 1–3 шагов с обоснованием, опирающимся минимум на 3 фактора (грейд, разрывы навыков, история участия, требования следующего уровня, предусловия, доступность, устаревшая аттестация).
- Прозрачный расчёт. По каждой рекомендации — список факторов с реальными числами, ожидаемый прирост навыков, вклад в готовность, а также блок «почему не наивный выбор» (сравнение с правилом «самый слабый навык»).
- Обновление прогресса. Отметка «выполнено» пересчитывает навыки, готовность, траекторию и рекомендации.
- HR-обзор: проседающие компетенции, сотрудники без рекомендованного шага (с причиной и подсказкой), участие по активностям с флагом оттока, приватный сигнал снижения вовлечённости.
- Импорт данных жюри через интерфейс HR (upsert по id, устойчивый к плохим строкам).
- Локализация обоснования и интерфейса:
kk/ru/en. - Разграничение прав сотрудник/HR, приватность вовлечённости, запуск одной командой, работа без ключа LLM (режим правил).
- «Спросите о своём пути». Вопрос в свободной форме («почему это, а не мой самый слабый навык?») — ответ LLM строго по фактам профиля, без выдуманных чисел.
- Риск ухода в HR-обзоре — объяснимый балл 0–100 с причинами (отказы, просрочки, нет прогресса, нет цели). Повод для разговора, не рейтинг.
- Лёгкая геймификация. XP только за добровольные активности и закрытые критические навыки; приватно, без лидербордов.
- Адаптивный интерфейс. Автоматический аудит (элементы за краем экрана, обрезанный и вылезающий текст) на 375 / 768 / 1024 / 1280 px и трёх языках: без горизонтальной прокрутки и без обрезанных подписей; навыки показываются полными названиями.
- Лендинг продукта (
/): «живая» hero-карточка на реальных данных, «Путь» по грейдам, сравнение «наивное правило vs Career Quest», интерактивное «Отметить выполненным», HR-превью, KK/RU/EN, тёмная тема и входы в демо-профили.
3. Как работает основной сценарий
- Лендинг
/→ «Открыть демо-профиль» (или/app— выбор профиля, без пароля). - Вход как сотрудник (демо-выбор профиля, без пароля) →
GET /api/employees/{id}строит профиль: применяет к аттестованным навыкам активности, завершённые после даты последней аттестации (эффективный уровень), определяет цель и разрывы. GET /api/employees/{id}/recommendations?mode=ai&lang=ru→ движок формирует шорт-лист и оценки, LLM выбирает 1–3 шага и пишет обоснование; при недоступности LLM интерфейс мгновенно показывает результат режима правил.- Сотрудник отмечает активность выполненной →
POST /api/employees/{id}/activitiesпересчитывает навыки и готовность и возвращает новую рекомендацию. - HR открывает
GET /api/hr/overviewи, при необходимости, загружает профили жюри черезPOST /api/hr/import.
4. Алгоритм рекомендации (детерминированное ядро + LLM)
Эффективный уровень навыка. К аттестованному уровню применяются только
завершённые активности с датой позже last_review_date, по порядку дат:
new = max(cur, min(cur + gain, max_level)). Такие навыки помечаются «на пересмотре».
Цель. career_goal, если задан и отличается от текущей роли/грейда, иначе
следующий грейд той же роли. Lead без цели → рекомендаций нет (AT_TOP_NO_GOAL).
Разрыв. gap = max(0, required_target − effective). Критические навыки целевого
грейда имеют вес 3, остальные — 1.
Допуск активности (все условия): не обязательная (mandatory назначает HR);
подходит роль и грейд; выполнены предусловия по эффективным уровням; не завершена
ранее (исключение — регулярный клуб EV_036); доступна (self-paced или есть
будущая сессия); развивает хотя бы один навык с разрывом, причём effective < max_level.
Оценка (каждое число видно в интерфейсе):
gap_value = Σ w·min(прирост, разрыв) / Σ w·разрыв # доля закрытого взвешенного разрыва
propensity = (1 + позитив) / (2 + позитив + негатив) # по похожим активностям, ×0.5 старше 12 мес
fit = доля завершения формата (× 0.7 если remote и активность offline)
availability = 1.0 (self-paced / сессия ≤ 45 дн) · 0.8 (≤ 90 дн) · 0.5 (позже)
score = gap_value · (0.5 + 0.5·propensity) · fit · availability
Отбор — жадный, с диверсификацией (×0.5, если основной навык уже закрыт другой
рекомендацией), максимум 3. При ≥3 отказах/неявках на похожем формате движок
предпочитает другой формат. Пустой результат кодируется:
AT_TOP_NO_GOAL, TARGET_REACHED, NO_ELIGIBLE_EVENTS, PREREQUISITES_BLOCKED,
LOW_ENGAGEMENT.
Как выглядит объяснение. Каждый фактор — простой факт, числа за оценкой видны в блоке «Как это посчитано». Пример для E0028 (Leadership Foundations):
Senior needs Leadership 2 (you have 1)
Raises Leadership 1 → 2
Similar activities: 0 completed, 1 declined or missed
Online: you completed 50% of past ones
Next session 2026-10-08
Счётчики истории — реальные, а не взвешенные; если у человека нет опыта с форматом, так и написано (без выдуманного процента).
LLM-слой. Получает шорт-лист топ-8 кандидатов с факторами, разрывы (с пометкой
критичных), статистику участия, наивный baseline и язык. Возвращает строгий JSON:
1–3 выбора, каждое обоснование ссылается минимум на 3 реальных фактора кандидата.
Ответ валидируется (id ∈ шорт-лист, ≥3 различных типов факторов, слово «критический»
допустимо только при факторе critical_gap); при ошибке —
одна повторная попытка — только если в общем бюджете времени (9 с) её можно успеть, —
иначе fallback на режим правил с шаблонным обоснованием. Так AI-рекомендация
укладывается в лимит кейса 10 с.
Результаты кэшируются по (сотрудник, состояние, язык).
5. Технологии
- Backend: Python 3.11, FastAPI, Pydantic v2, Uvicorn,
openai(совместимый с OpenAI API клиент), pytest. Данные — в памяти, среда выполнения пишет вdata/runtime/. - AI: LLM через OpenAI-совместимый эндпоинт, по умолчанию
gpt-4.1-mini(structured outputs, strict JSON). Работает и без ключа (режим правил). - Frontend: React 18, Vite, TypeScript, Tailwind CSS, React Router — без UI-китов и библиотек графиков (шкалы навыков и HR-диаграммы — на CSS).
- Инфраструктура: один многостадийный
Dockerfile(node собирает SPA → python отдаёт/api/*и собранный SPA),docker compose,Makefile.
6. Архитектура
flowchart LR
UI[React SPA<br/>сотрудник / HR] -->|/api| API[FastAPI<br/>роутинг + авторизация]
API --> STORE[Store<br/>загрузка данных, upsert, runtime]
API --> ENGINE[Движок правил<br/>навыки, разрывы, допуск, оценка]
API --> LLM[LLM-слой<br/>выбор + обоснование]
LLM -->|шорт-лист топ-8| ENGINE
LLM -.->|fallback| ENGINE
LLM -->|structured JSON| OPENAI[(OpenAI-совместимый API)]
STORE --> DATA[(employees, events, skills, history)]
ENGINE --> DATA
- Store — единый источник данных: загружает стартовый набор,
data/extra,data/test_profiles,data/runtime; импорт и отметки выполнения обновляют данные и пересобирают представление движка. - Движок (
app/engine/) — чистый Python без FastAPI:dataset,skills,candidates,recommender. - LLM-слой (
app/llm/) —client,prompt,decide; полностью опционален. - API (
app/api/) — эндпоинты и мост к движку/LLM; HR-аналитика —app/hr/.
Основные эндпоинты: POST /api/auth/login, GET /api/demo/people,
GET /api/employees/{id}, GET /api/employees/{id}/recommendations?mode=&lang=,
POST /api/employees/{id}/activities, GET /api/catalog,
GET /api/hr/overview, GET /api/hr/employees, POST /api/hr/import,
POST /api/employees/{id}/ask, POST /api/landing/events, GET /api/health.
Лендинг
- Код —
frontend/src/landing/(React, без сторонних UI-китов); спецификация дизайна —docs/LANDING.md. - Все числа на лендинге — из продукта.
backend/scripts/export_landing_fixtures.pyпрогоняет движок и API на чистой копии данных и пишетfrontend/src/landing/fixtures.json(карточка E0028 с AI-обоснованием на трёх языках, ловушка против наивного правила, HR-превью только с инициалами, метрики).backend/scripts/render_og_image.pyрисует превью для соцсетейfrontend/public/og.png. Тестыbackend/tests/landingследят, что данные лендинга полные (все три языка), числа совпадают с набором данных, а в HR-превью только инициалы. - Страницы кабинета загружаются лениво: лендинг — ~83 КБ JS в gzip, страница
сотрудника — ~4 КБ.
prefers-reduced-motionи тёмная тема учитываются. - Аналитика — только два анонимных события (
demo_opened,contact_clicked) вdata/runtime/landing_events.jsonl; сторонних трекеров нет, лишние поля отклоняются.
7. Установка и запуск
Вариант A — одна команда (Docker)
docker compose up --build
Откроется на http://localhost:8000 (API и интерфейс с одного сервера).
Работает без ключа LLM. Чтобы включить AI-режим, создайте .env рядом с
docker-compose.yml:
LLM_API_KEY=sk-...
LLM_MODEL=gpt-4.1-mini
Если порт 8000 занят, укажите другой:
PORT=8010 docker compose up --build→ http://localhost:8010.
Вариант B — локальная разработка
# backend
cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
PYTHONPATH=. uvicorn app.main:app --reload --port 8000
# frontend (в отдельном терминале)
cd frontend
npm install
npm run dev # http://localhost:5173, проксирует /api на :8000
Тесты: cd backend && pytest -q. Оценка на trap-профилях: python eval/run_eval.py.
Команды make (из корня репозитория):
| Команда | Что делает |
|---|---|
make up | docker compose up --build — всё одной командой |
make test | тесты backend (pytest -q) |
make eval | оценка на 8 trap-профилях → eval/RESULTS.md |
make fixtures | пересобрать данные лендинга из движка и API (AI-часть — при LLM_API_KEY) |
make og | перерисовать превью для соцсетей frontend/public/og.png (нужен Pillow) |
Маршруты
| Путь | Что открывается |
|---|---|
/ | лендинг продукта |
/app | вход в демо (сотрудник или HR, без пароля) |
/app?demo=E0028 · /app?role=hr | сразу нужный кабинет (глубокие ссылки с лендинга) |
/me/{id} · /hr | кабинет сотрудника · HR-обзор |
8. Как проверить решение (сценарий для жюри)
- Лендинг. Откройте http://localhost:8000 — hero-карточка показывает реальную рекомендацию для E0028 (AI-обоснование на KK/RU/EN), раздел «Почему это, а не то» — ловушку публичных выступлений. Кнопка «Открыть демо-профиль» ведёт в кабинет.
- Импорт профилей жюри. Вход как HR → раздел «Import profiles & history» →
загрузить
employees.json/activity_history.csv(формат стартового набора) → отчёт покажет добавленные записи. - Объяснимая рекомендация. Вход как сотрудник (например, E0028, Backend Engineer · Middle → Senior): видны траектория, готовность, критические навыки, 1–3 рекомендации с факторами (реальные числа) и блок «почему не самый слабый навык».
- Обновление прогресса. «Отметить выполненным» → навык и готовность сдвигаются, появляется новая рекомендация.
- HR-обзор: проседающие компетенции, список без рекомендованного шага с подсказками, участие по активностям с флагами оттока.
- Устойчивость к «ловушкам».
python eval/run_eval.py— 8 синтетических профилей, на которых однофакторное правило ошибается; движок корректен на всех 8.
Проверка API без интерфейса:
curl -s localhost:8000/api/health
TOKEN=$(curl -s localhost:8000/api/auth/login -H 'content-type: application/json' \
-d '{"role":"employee","employee_id":"E0028"}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["token"])')
curl -s "localhost:8000/api/employees/E0028/recommendations?mode=ai&lang=ru" \
-H "Authorization: Bearer $TOKEN"
Результаты оценки на trap-профилях
Движок корректен на 8/8; наивный baseline «самый слабый навык» расходится с
движком на профилях, где он рекомендует отклонённую, заблокированную,
«упёршуюся в потолок» или уже закрытую активность (подробности и таблица —
eval/RESULTS.md).
9. Данные и интеграции
- Стартовый набор (
data/):employees.json(200),events.json(40),skills.json(60 навыков, требования по грейдам),activity_history.csv(2 743 записи). Дата «сегодня» —meta.as_of_date(2026-10-01), а не системные часы. - Синтетические trap-профили (
data/test_profiles/, E9001–E9008) для оценки. - Внешний сервис: OpenAI-совместимый API для LLM-слоя (опционально; конфиг через переменные окружения).
| Переменная | Назначение | По умолчанию |
|---|---|---|
LLM_API_KEY | ключ; пусто → режим правил | пусто |
LLM_BASE_URL | эндпоинт (пусто → OpenAI) | пусто |
LLM_MODEL | модель | gpt-4.1-mini |
LLM_TIMEOUT_S | таймаут запроса, сек | 8 |
LLM_BUDGET_S | общий бюджет AI-пути с повтором, сек | 9 |
Приватность и безопасность: внутренний контур; данные вовлечённости не видны
другим сотрудникам; права сотрудник/HR разграничены на сервере (чужой профиль и
HR-маршруты → 403); ключи не коммитятся (.env в .gitignore и .dockerignore);
нет публичных рейтингов сотрудников; нет механик вокруг обязательных процессов.
10. Ограничения
- Данные — синтетические, живут в памяти; постоянное хранилище не подключено
(среда выполнения пишет CSV/JSONL в
data/runtime/). - Демо-авторизация без пароля (подписанный токен с ролью); не для продакшена.
- AI-режим требует ключа и сетевого доступа; при их отсутствии используется режим правил (это штатное поведение, а не ошибка).
- Отметки выполнения в
data/runtime/сохраняются между перезапусками — перед «чистой» демонстрацией каталог можно очистить. - Данные лендинга — снимок: после изменения данных или движка перегенерируйте
python backend/scripts/export_landing_fixtures.py(иrender_og_image.py). - Задержка (измерено): правила — ~2 мс на сотрудника, AI-рекомендация — обычно 3–6 с, худший случай 7,6 с; бюджет 9 с, после него — режим правил (лимит кейса 10 с).
11. Deployed-версия
Публичного развёртывания нет — запуск локально одной командой (раздел 7).
Авторы коммитов
История коммитов
- 2026-09-23 17:30docs: document the AI time budget and measured latencygohawxx
- 2026-09-23 17:29landing: demo the public-speaking trap with E9001, not E0112geckwwo
- 2026-09-23 17:28llm: keep AI recommendations within the 10 s limitgeckwwo
- 2026-09-23 17:26fix: working port override — PORT=8010 docker compose up --buildgohawxx
- 2026-09-23 17:22ui: multi-factor chips, relative fit, hero skeleton, centred loginAlikkkhx
- 2026-09-23 17:22infra: make eval / fixtures / og, documented in the READMEgohawxx
- 2026-09-23 17:22test: guard the landing data — languages, dataset numbers, initials onlygeckwwo
- 2026-09-23 17:14docs: README reflects the polish passgohawxx
Все коммиты (51)
- 2026-09-23 17:14engine+llm: plain, accurate explanations; block 'critical' overclaimsgeckwwo
- 2026-09-23 17:09ui: fix clipping and overflow found by a layout audit; drop RechartsAlikkkhx
- 2026-09-23 17:02ui: product landing page at /, workspace moves to /appAlikkkhx
- 2026-09-23 17:00api: anonymous landing events; docs: landing, routes and new featuresgohawxx
- 2026-09-23 17:00landing: localize HR preview, focus it on voluntary drop-off, add share imagegeckwwo
- 2026-09-23 16:23landing: export real product output as landing fixturesgeckwwo
- 2026-09-23 16:18docs: landing page design spec (SaaS positioning, page map, interactions)gohawxx
- 2026-09-23 16:12ui: round the readiness ring and tidy the header on mobileAlikkkhx
- 2026-09-23 16:11test: cover ask endpoint auth and HR attrition/disengaged shapegohawxx
- 2026-09-23 16:10test: cover recurring club, remote penalty and the AI selection helpersgeckwwo
- 2026-09-23 16:07ui: add attrition-risk panel (HR) and voluntary XP badge (employee)Alikkkhx
- 2026-09-23 16:06hr: add explainable attrition-risk signalgohawxx
- 2026-09-23 16:03ui: add 'Ask about your path' box on the employee pageAlikkkhx
- 2026-09-23 16:02api: add POST /employees/{id}/ask for grounded Q&Agohawxx
- 2026-09-23 16:01llm: add grounded 'ask about your path' Q&Ageckwwo
- 2026-09-23 15:30ui: add KK/RU/EN language switcher to recommendationsAlikkkhx
- 2026-09-23 15:29fix: resolve project root by locating data/ so Docker serves data and SPAgohawxx
- 2026-09-23 15:26docs: full project README in Russiangohawxx
- 2026-09-23 15:22hr: implement disengagement signal and reason-specific no-step hintsgohawxx
- 2026-09-23 15:21eval: add 8 trap profiles and baseline-vs-engine evaluationgeckwwo
- 2026-09-23 15:12ui: build the HR dashboard and profile importAlikkkhx
- 2026-09-23 15:10api: route mode=ai to the AI layer and report it in healthgohawxx
- 2026-09-23 15:08llm: add AI decision layer over the rules enginegeckwwo
- 2026-09-23 14:59ui: apply auth session on login so the workspace opensAlikkkhx
- 2026-09-23 14:55engine: accept lang override so ?lang= localizes the rationalegeckwwo
- 2026-09-23 14:54store: keep engine dataset in sync after import and completionsgohawxx
- 2026-09-23 14:54engine: recommend high-gap employees instead of starving themgeckwwo
- 2026-09-23 14:44engine: load datasets and calculate skill stategeckwwo
- 2026-09-23 14:44engine: score explainable activity recommendationsgeckwwo
- 2026-09-23 14:44docs: tighten workflow and guardrail notesgeckwwo
- 2026-09-23 14:43ui: scaffold frontend clientAlikkkhx
- 2026-09-23 14:43ui: build employee path experienceAlikkkhx
- 2026-09-23 14:43ui: ignore frontend build artifactsAlikkkhx
- 2026-09-23 14:43ui: animate completed skill progressAlikkkhx
- 2026-09-23 14:40infra: add container workflowgohawxx
- 2026-09-23 14:39api: add platform routes and persistencegohawxx
- 2026-09-23 14:25contract: modelsgohawxx
- 2026-09-23 14:05chore: kickoff — shared agent spec, team plan, starter-kit datageckwwo
- 2026-09-23 13:54Update README.mdgohawxx
- 2026-09-23 13:51Update README with Career Quest descriptionAlikkkhx
- 2026-09-23 13:50Add current track information to READMERhys (GeckoNerd / Kenux)
- 2026-09-23 01:31Delete info.md.gohawxx
- 2026-09-23 01:19Create info.md.gohawxx
Структура репозитория (83 файлов)
.dockerignore .env.example .gitignore AGENTS.md Dockerfile Makefile PLAN.md README.md backend/app/__init__.py backend/app/api/__init__.py backend/app/api/routes.py backend/app/api/service.py backend/app/auth.py backend/app/engine/__init__.py backend/app/engine/candidates.py backend/app/engine/dataset.py backend/app/engine/recommender.py backend/app/engine/skills.py backend/app/hr/__init__.py backend/app/hr/analytics.py backend/app/llm/__init__.py backend/app/llm/client.py backend/app/llm/decide.py backend/app/llm/prompt.py backend/app/llm/qa.py backend/app/main.py backend/app/models.py backend/app/store/__init__.py backend/app/store/repository.py backend/pytest.ini backend/requirements.txt backend/scripts/compare_baseline.py backend/scripts/export_landing_fixtures.py backend/scripts/render_og_image.py backend/tests/api/test_platform.py backend/tests/engine/test_rules.py backend/tests/landing/test_fixtures.py backend/tests/llm/test_decide.py backend/tests/llm/test_qa.py data/README.kz.md data/README.md data/README.ru.md data/activity_history.csv data/employees.json data/events.json data/skills.json data/test_profiles/activity_history.csv data/test_profiles/employees.json docker-compose.yml docs/LANDING.md eval/RESULTS.md eval/expectations.json eval/make_test_profiles.py eval/run_eval.py frontend/.gitignore frontend/index.html frontend/package-lock.json frontend/package.json frontend/postcss.config.js frontend/public/favicon.svg frontend/public/og.png frontend/src/App.tsx frontend/src/api/client.ts frontend/src/api/types.ts frontend/src/landing/Hero.tsx frontend/src/landing/LandingPage.tsx frontend/src/landing/Path.tsx frontend/src/landing/Sections.tsx frontend/src/landing/analytics.ts frontend/src/landing/fixtures.json frontend/src/landing/hooks.ts frontend/src/landing/i18n.ts frontend/src/landing/landing.css frontend/src/main.tsx frontend/src/mocks/fixtures.ts frontend/src/pages/EmployeePage.tsx frontend/src/pages/HrPage.tsx frontend/src/styles.css frontend/tailwind.config.js frontend/tsconfig.app.json frontend/tsconfig.json frontend/tsconfig.node.json frontend/vite.config.ts
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.