AAYMA
RU
Войти

Career Quest — DomaDoma

Career Quest на FastAPI и SQLite: профиль сотрудника, рекомендации шагов развития (LLM с фолбэком), завершение активности с пересчётом навыков и…

Рабочий MVP
Команда «DomaDoma» 3💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: 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.md

Career 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}.

  1. Скопировать .env.example в .env.
  2. Задать случайный JWT_SECRET минимум 32 байта и DEMO_PASSWORD минимум 8 символов. Например, секрет можно сгенерировать локально через python -c "import secrets; print(secrets.token_urlsafe(48))".
  3. Владелец ключа отдельно задаёт OPENAI_API_KEY и OPENAI_MODEL для AI-демо.
  4. Запустить 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/employeesHR/admin
GET /api/employees/{id}employee self, HR/admin
GET /api/employees/{id}/recommendations?lang=kkemployee self, HR/admin
POST /api/employees/{id}/activities/{event_id}/completeemployee self/admin
GET /api/hr/overviewHR/admin
POST /api/admin/uploadadmin

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 без изменения его исходников и общего контракта.

Звёзды
⭐ 0
Форки
0
Язык
TypeScript
Последний push
в прошлом месяце
Коммиты
15
Авторы
3
Файлы
97
Ветки
4

Авторы коммитов

karim312k1 7Aldiyar Zharkem 5Nurbo 3

История коммитов

  • 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
Ветки (4)

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.