Career Quest — DomaDoma
Career Quest на FastAPI и SQLite: профиль сотрудника, рекомендации шагов развития (LLM с фолбэком), завершение активности с пересчётом навыков и…
О проекте
Команда: DomaDoma
Кейс HackAlem.ai: Менеджмент — Halyk Bank · кейс 1
Стадия: Рабочий MVP
Задача кейса: «Career Quest»: AI-навигатор, связывающий навыки сотрудника с шагами развития
Суть
Career Quest на FastAPI и SQLite: профиль сотрудника, рекомендации шагов развития (LLM с фолбэком), завершение активности с пересчётом навыков и readiness, HR-обзор и импорт данных. Frontend на React.
Как устроено
Официальный синтетический набор (employees, events, skills, activity_history) один раз загружается в SQLite. Локальный движок recommendation/engine.py считает gain и readiness. service.py строит рекомендации через OpenAI (gpt-4.1) с таймаутом 8 с, без ключа работает явно обозначенный fallback. Complete идемпотентен через заголовок Idempotency-Key и ведёт ревизии профиля. Доступ через JWT, роли employee, hr и admin, пароли хешируются Argon2. Импорт данных проходит валидацию и отдаёт 409 при конфликтах.
Ключевые решения
- guarded LLM layer with fallback
- idempotent completion
- readiness recalculation
- JWT RBAC
- Argon2
Особенности
Идемпотентное завершение активности с ревизиями профиля: повтор не повышает навык второй раз. LLM-объяснения отделены от детерминированного пересчёта прогресса, Complete не ждёт LLM. Работа разделена по ролям участников через файлы prompts/.
Стек
Python · FastAPI · SQLite · React · TypeScript · Vite · Playwright · Docker Compose · pytest
Модели
gpt-4.1
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-c5a4e53f-domadoma.
README
README.mdCareer Quest — DomaDoma
FastAPI + SQLite backend для Career Quest. Python 3.12; UI и recommendation engine разрабатываются отдельно. Полный контракт и граница интеграции: docs/backend.md.
Текущее состояние: backend подключён к AI engine/service из 3f45c46.
Работают профиль, рекомендации, Complete с пересчётом навыков/readiness и HR.
Без OPENAI_API_KEY рекомендации работают в явно обозначенном fallback-режиме.
Frontend добавлен: вход, профиль, рекомендации, Complete, история, HR и импорт.
Сборка интерфейса: cd frontend, npm ci, npm run build; затем backend
раздаёт frontend/dist на своём адресе. Локально сейчас http://127.0.0.1:8765.
Основной интерфейс команды: frontend/README.md.
Наш альтернативный вариант сохранён в frontend-preview/: docs/frontend.md.
Старый черновик в work/ в сборку не входит.
Итоговый запуск после интеграции
Требуются Docker Engine/Desktop, Compose и файлы всех трёх участников:
frontend/package.json + lockfile с npm run build → dist,
backend/recommendation/{engine.py,service.py,requirements-ai.txt},
data/{skills.json,events.json,employees.json,activity_history.csv}.
- Скопировать
.env.exampleв.env. - Задать случайный
JWT_SECRETминимум 32 байта иDEMO_PASSWORDминимум 8 символов. Например, секрет можно сгенерировать локально черезpython -c "import secrets; print(secrets.token_urlsafe(48))". - Владелец ключа отдельно задаёт
OPENAI_API_KEYиOPENAI_MODELдля AI-демо. - Запустить
docker compose up --build.
Адрес: http://localhost:8000. Swagger: http://localhost:8000/docs. Один контейнер раздаёт API и SPA; SQLite сохраняется в named volume. Полная Docker-сборка пока не проверена. Production-сборка frontend проверена отдельно.
Разработка backend отдельно
Из корня репозитория, Python 3.12:
python -m venv backend/.venv
.\backend\.venv\Scripts\python.exe -m pip install -r backend/requirements.txt -r backend/requirements-dev.txt
# Общий исходный набор из main:
$env:DATA_DIR = "data"
$env:JWT_SECRET = [System.Convert]::ToBase64String([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(48))
$env:DEMO_PASSWORD = "choose-a-private-demo-password"
.\backend\.venv\Scripts\python.exe -m uvicorn backend.main:app --reload
На Windows PowerShell 5.1 вместо GetBytes(48) можно задать секрет,
сгенерированный приведённой выше Python-командой. Секрет не коммитить.
Для запуска без платных вызовов оставьте OPENAI_API_KEY незаданным или пустым.
Uvicorn в этом режиме использует переменные окружения; .env автоматически
читает только Compose. Для frontend dev использовать Vite proxy /api → http://localhost:8000.
Для проверки OpenAI перед запуском Uvicorn задайте OPENAI_API_KEY в окружении
своего терминала и $env:OPENAI_MODEL = "gpt-4.1". У каждого участника свой
локальный ключ: .env в Git не передаётся. Если порт 8000 занят, добавьте
к команде Uvicorn --port 8765; Swagger будет на http://127.0.0.1:8765/docs.
Demo-аккаунты и API
Логины: employee, hr, admin. На первом запуске всем задаётся DEMO_PASSWORD,
сохраняется только Argon2-хеш. Employee связан с E0002 (настраивается
DEMO_EMPLOYEE_ID при первоначальном создании аккаунта). Смена env после seed
не перезаписывает существующие пароли. JWT действует 30 минут по реальному времени.
POST /api/auth/login с {"username":"admin","password":"<ваш пароль>"}
возвращает токен. Дальше передавать Authorization: Bearer <token>.
| Endpoint | Доступ |
|---|---|
GET /api/health | публичный |
GET /api/auth/me | любой вошедший |
GET /api/employees | HR/admin |
GET /api/employees/{id} | employee self, HR/admin |
GET /api/employees/{id}/recommendations?lang=kk | employee self, HR/admin |
POST /api/employees/{id}/activities/{event_id}/complete | employee self/admin |
GET /api/hr/overview | HR/admin |
POST /api/admin/upload | admin |
Upload — один multipart-запрос с employees_file и history_file.
Пример нового профиля: employees.json,
пустая история с правильным заголовком: history.csv.
Можно отправить через Swagger после добавления Bearer-заголовка клиентом или curl:
curl http://localhost:8000/api/admin/upload \
-H "Authorization: Bearer $TOKEN" \
-F employees_file=@backend/examples/employees.json \
-F history_file=@backend/examples/history.csv
Лимит каждого файла 5 MiB; UTF-8 и BOM поддерживаются. Оба файла валидируются до записи. Повтор history пропускается, конфликт record_id → 409 без частичного импорта. Профиль с прежним ID обновляет версию. При demo-завершениях замена отличающегося baseline пока запрещена 409 до согласования reconciliation с AI.
Complete: JSON {"occurrence_key":null}, заголовок Idempotency-Key с уникальным
ключом операции. Для EV_036 occurrence_key — дата рекомендованной сессии.
Повтор не повышает навыки снова. Ответ содержит профиль; рекомендации запрашиваются
отдельно. При stale_revision повторить GET рекомендаций. Grade не повышается автоматически.
SQLite загружает исходный набор только один раз. Модельная дата берётся из набора:
2026-10-01; JWT и системные timestamps используют реальные часы. Не удаляйте
volume/SQLite для обычного рестарта. Complete использует локальный движок и не ждёт LLM.
Проверки и ограничения
.\backend\.venv\Scripts\python.exe -m pytest tests/backend tests/ai -q
Тесты используют синтетический исходный набор из data/ или текущего work/karim312k1/.
Часть HTTP-тестов использует тестовый DomainDouble; интеграционные тесты
test_ai_integration.py используют настоящий engine/service и SQLite.
Результат: 40 passed. Ключ и платные запросы не нужны. Проверенные версии прямых
Python-зависимостей зафиксированы в requirements; AI-зависимости принадлежат напарнику.
Локальные проверки сейчас выполняются Python 3.13.5; Python 3.12 и полный Docker
остаются интеграционными проверками.
Проверены реальные gain/readiness, HR, fallback, повтор Complete и состояние
после рестарта. HTTP smoke: E0002 + EV_005 → System Design 1 → 2,
readiness 62 → 66, revision 1 → 2. Отдельно выполнен реальный HTTP-запрос через
backend к OpenAI (gpt-4.1): source=llm, fallback_reason=null,
2 рекомендации для E0002. Health, login и профиль вернули 200;
доступ employee к чужому профилю — 403. Подробнее: docs/backend.md.
Подтверждённые вопросы к качеству AI-объяснений и локализации перечислены
в docs/backend.md. Backend ограничивает запрос 8 секундами.
Это demo auth, без регистрации/refresh/SSO и без заявления о production-защите.
Источники: синтетический набор Career Quest v1.0 и его README.ru.md; пользовательский контракт Backend/Integration v1. Исходный engine получен из main вместе с общими документами. AI service подключён из коммита напарника 3f45c46 без изменения его исходников и общего контракта.
Авторы коммитов
История коммитов
- 2026-09-23 18:02merge: preserve team frontend and keep alternate dashboard previewkarim312k1
- 2026-09-23 18:00feat(frontend): add Career Quest dashboard connected to backendkarim312k1
- 2026-09-23 17:42Merge pull request #3 from BAITC-Hacks/feat/frontendAldiyar Zharkem
- 2026-09-23 17:39Merge remote-tracking branch 'origin/main' into feat/frontendNurbo
- 2026-09-23 17:25merge: reconcile frontend branchNurbo
- 2026-09-23 17:22feat: implement Career Quest frontendNurbo
- 2026-09-23 17:19feat(frontend): add connected demo screenschampaldi
- 2026-09-23 17:01docs(backend): record live OpenAI verification and team setupkarim312k1
Все коммиты (15)
- 2026-09-23 16:39feat(backend): integrate AI service and persist completion progresskarim312k1
- 2026-09-23 15:53feat: add recommendation service and guarded LLM layerchampaldi
- 2026-09-23 15:22Merge origin/main into feat/backend-corekarim312k1
- 2026-09-23 15:15feat(backend): add SQLite API, auth, imports and integration boundarykarim312k1
- 2026-09-23 15:07chore: fix recommendation directory namechampaldi
- 2026-09-23 15:05chore: initialize Career Quest projectchampaldi
- 2026-09-23 13:38Create Karim's workspace folderkarim312k1
Структура репозитория (97 файлов)
.dockerignore .env.example .gitignore AGENTS.md Dockerfile README.md START_HERE.md backend/__init__.py backend/auth.py backend/config.py backend/errors.py backend/examples/employees.json backend/examples/history.csv backend/integration.py backend/loading.py backend/main.py backend/models.py backend/recommendation/demo.py backend/recommendation/engine.py backend/recommendation/requirements-ai.txt backend/recommendation/service.py backend/repository.py backend/requirements-core.txt backend/requirements-dev.txt backend/requirements.txt backend/schemas.py compose.yaml data/activity_history.csv data/employees.json data/events.json data/skills.json docs/ai.md docs/architecture.md docs/backend.md docs/baseline_test_log.txt docs/contracts.md docs/frontend.md docs/references.md docs/source_notes.md docs/task.md frontend-preview/index.html frontend-preview/package-lock.json frontend-preview/package.json frontend-preview/playwright.config.ts frontend-preview/src/AdminPanel.tsx frontend-preview/src/App.tsx frontend-preview/src/main.tsx frontend-preview/src/styles.css frontend-preview/tests/journey.spec.ts frontend-preview/tsconfig.json frontend-preview/vite.config.ts frontend/.gitignore frontend/README.md frontend/index.html frontend/package-lock.json frontend/package.json frontend/src/App.test.tsx frontend/src/App.tsx frontend/src/api.ts frontend/src/api/client.ts frontend/src/api/http.test.ts frontend/src/api/http.ts frontend/src/api/types.ts frontend/src/components/Recommendations.tsx frontend/src/components/SkillsTable.tsx frontend/src/components/common.tsx frontend/src/i18n.ts frontend/src/main.tsx frontend/src/mocks/client.test.ts frontend/src/mocks/client.ts frontend/src/mocks/fixtures.ts frontend/src/mocks/privileged.ts frontend/src/pages/Login.tsx frontend/src/pages/Management.test.tsx frontend/src/pages/Management.tsx frontend/src/pages/Profile.tsx frontend/src/pages/Upload.test.tsx frontend/src/pages/Upload.tsx frontend/src/state/employee.test.ts frontend/src/state/employee.ts frontend/src/styles.css frontend/src/test/fixtures.ts frontend/src/test/setup.ts frontend/src/vite-env.d.ts frontend/tsconfig.app.json frontend/tsconfig.json frontend/vite.config.ts prompts/01_AI.md prompts/02_BACKEND.md prompts/03_FRONTEND.md tests/ai/make_fixtures.py tests/ai/test_engine.py tests/ai/test_service.py tests/backend/test_ai_integration.py tests/backend/test_api.py tests/backend/test_repository.py work/karim312k1/README.md
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.