AAYMA
RU
Войти

Qadam

Платформа, где бизнес описывает задачу своими словами, ИИ задаёт уточняющие вопросы и собирает карточку задачи; прозрачный рейтинг готовности…

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

О проекте

Команда: Kto mi?
Кейс HackAlem.ai: Образование — AI Sana
Стадия: Рабочий MVP

Задача кейса: Challenge Hub: превратить задачу бизнеса в задание для студенческих команд

Суть

Платформа, где бизнес описывает задачу своими словами, ИИ задаёт уточняющие вопросы и собирает карточку задачи; прозрачный рейтинг готовности, каталог, рекомендации командам и отклики.

Как устроено

TaskAiService через LlmClient (OpenAI Chat Completions со structured output по JSON-схемам или офлайн MockLlmClient) анализирует черновик, формирует уточняющие вопросы и карточку без выдуманных фактов. RatingService детерминированно считает готовность карточки 0–100 по 7 критериям с breakdown/missing/tips и уровнями DRAFT/WORKING/READY/PRIORITY. TaskMatcher рекомендует задачи командам по совпадению основ слов (первые 5 букв) с интересами и навыками; отклики и этапы подтверждает бизнес вручную (+10 баллов).

Ключевые решения

  • structured output
  • детерминированный рейтинг карточки
  • keyword stem matching
  • mock LLM client

Особенности

По коммитам команда начала с адаптивных уроков с пиктограммами ARASAAC и в середине хакатона развернулась в платформу бизнес-задач. Вызов LLM вынесен из транзакции БД: при сбое ИИ ничего не сохраняется; CI с покрытием на GitHub Actions.

Стек

Java 21 · Spring Boot 3.5 · Spring Data JPA · H2 · Maven · Docker Compose · GitHub Actions · JaCoCo · JUnit 5

Модели

gpt-4o-mini


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-db0dd8bc-kto-mi.

README

README.md

Qadam

CI

Qadam (каз. «шаг») — платформа бизнес-задач для студенческих команд: от сырой идеи к готовой задаче шаг за шагом.

Бизнес описывает задачу своими словами, ИИ задаёт уточняющие вопросы и собирает из черновика и ответов карточку задачи — без выдуманных фактов: если сведений нет, поле остаётся пустым. Прозрачный рейтинг (без ИИ) показывает, насколько карточка готова и что добавить. Бизнес вручную публикует задачу, студенческие команды получают рекомендации и откликаются, бизнес сам принимает отклики и подтверждает этапы работы (+10 баллов команде).

Содержание

  1. Команда
  2. Архитектура и стек
  3. Запуск
  4. Рейтинг карточки
  5. Каталог, рекомендации и отклики
  6. AI-функции
  7. API
  8. Тестовые сценарии

Команда

Команда хакатона «Kto mi?». Репозиторий: hack-db0dd8bc-kto-mi.

Архитектура и стек

Стек: Java 21, Spring Boot 3.5 (Web, Validation, Data JPA), Maven Wrapper, H2 (in-memory), Lombok, springdoc-openapi (Swagger UI), JUnit 5 + Spring Boot Test, JaCoCo. OpenAI Chat Completions вызывается через RestClient, без SDK. CI — GitHub Actions, поставка — Docker / Docker Compose.

 Браузер / Swagger UI
         │  REST /api/**
         ▼
 controller ── TaskController, TeamController, ProposalController, GlobalExceptionHandler
         │  тонкий слой: @Valid, DTO, делегирование в сервисы
         ▼
 service ──── TaskService ──► TaskAiService ──► llm.LlmClient ─┬─ MockLlmClient (по умолчанию, офлайн)
         │         │                                            └─ OpenAiLlmClient (structured output)
         │         └────────► RatingService (детерминированный рейтинг, без ИИ)
         │    TeamService ──► TaskMatcher (рекомендации по совпадению слов)
         │    ProposalService (отклики, решения бизнеса, этапы и баллы)
         ▼
 repository ─ Spring Data JPA ──► H2 (Task, Team, Proposal)
Пакет com.qadamНазначение
configконфигурация Spring, выбор LLM-клиента, OpenAPI, загрузка демо-данных
controllerREST-контроллеры, единый обработчик ошибок, примеры для Swagger
dtoзаписи запросов и ответов: TaskCard, TaskAnalysis, Rating, …
modelJPA-сущности Task, Team, Proposal; перечисления CardField, Industry, RatingLevel, статусы
repositoryрепозитории Spring Data JPA
serviceбизнес-логика: задачи, ИИ, рейтинг, команды, рекомендации, отклики
llmабстракция LlmClient, промпты; реализации llm.mock и llm.openai

Ключевые решения:

  • ИИ только готовит текст. Рейтинг, каталог, рекомендации и выбор команды — детерминированный код без ИИ.
  • Вызов LLM идёт вне транзакции БД. Если ИИ не справился, в базу ничего не сохраняется.
  • Статусы. Задача: DRAFT → PUBLISHED (только вручную). Отклик: PENDING → ACCEPTED / REJECTED (только вручную).

Запуск

По умолчанию приложение работает в mock-режиме: LLM не вызывается, ключ OpenAI не нужен.

Вариант 1. Docker Compose (нужен только Docker):

docker compose up --build

Контейнер считается здоровым, когда отвечает GET /api/health. Остановить: docker compose down.

Вариант 2. Maven Wrapper (нужен JDK 21 или новее):

.\mvnw.cmd spring-boot:run      # Windows
./mvnw spring-boot:run          # Linux / macOS

После запуска:

Переменные окружения (см. .env.example):

ПеременнаяПо умолчаниюНазначение
LLM_MODEmockmock — офлайн без сети, openai — настоящий LLM
OPENAI_API_KEY—обязателен при LLM_MODE=openai, иначе приложение не стартует
OPENAI_MODELgpt-4o-miniмодель OpenAI с поддержкой structured output
DEMO_DATA_ENABLEDtrueзаполнить пустую базу демо-данными при старте

Режим OpenAI. Скопируйте .env.example в .env и укажите:

LLM_MODE=openai
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o-mini

docker compose читает .env автоматически. При запуске через Maven задайте те же переменные в окружении (например, $env:LLM_MODE="openai"; $env:OPENAI_API_KEY="sk-..."). .env в git не коммитится.

Демо-данные. При старте в пустую базу добавляются синтетические данные: 5 черновиков разной полноты, 5 опубликованных задач всех четырёх уровней рейтинга, 5 команд и 5 откликов. ИИ при этом не вызывается, персональных данных нет (контакты на example.com). Отключить: DEMO_DATA_ENABLED=false.

Сборка и тесты: .\mvnw.cmd clean verify (Linux / macOS: ./mvnw clean verify). Тесты не ходят в сеть, отчёт о покрытии — target/site/jacoco/index.html.

Рейтинг карточки

Рейтинг считает RatingService — обычный код без ИИ, результат всегда одинаков для одной и той же карточки. Максимум — 100 баллов.

КритерийВесПравило начисления
Контекст и потребность20поле «Контекст» — 10, поле «Потребность» — 10
Данные и материалы20поле «Данные» заполнено — 20
Ожидаемый результат15поле «Ожидаемый результат» заполнено — 15
Критерии успеха15есть цифра или % — 15; заполнено без измеримого показателя — 7
Ограничения10поле «Ограничения» заполнено — 10
Пользователи10поле «Пользователи» заполнено — 10
Связь с бизнесом10поле «Контакт» — 5, поле «Формат взаимодействия» — 5

Когда поле засчитывается: оно не пустое и содержит не меньше 15 символов (у контакта — не меньше 5). Поле «Название» в рейтинге не участвует.

Уровни готовности:

УровеньБаллыНазваниеЧто это значит
DRAFT0–39Черновикв каталоге с пометкой «требует уточнения», в рекомендации не попадает
WORKING40–69Рабочая задачаможно начинать, но часть сведений придётся уточнить
READY70–89Готова к работесведений достаточно для старта
PRIORITY90–100Приоритетнаякарточка заполнена полностью

Рейтинг пересчитывается и сохраняется при каждом изменении карточки. Каждый ответ с задачей содержит объяснение оценки: баллы по критериям с причиной (breakdown), коды незаполненных полей (missing) и подсказки, сколько баллов даст каждое поле (tips):

"rating": {
  "score": 75,
  "level": "READY",
  "levelName": "Готова к работе",
  "breakdown": [
    { "criterion": "Критерии успеха", "points": 15, "maxPoints": 15, "reason": "Заполнено, есть измеримый показатель" },
    { "criterion": "Связь с бизнесом", "points": 5, "maxPoints": 10,
      "reason": "Контакт: заполнено (+5); Формат взаимодействия: не заполнено (0 из 5)" }
  ],
  "missing": ["constraints", "users", "interactionFormat"],
  "tips": ["Заполните «Ограничения»: +10 баллов", "Заполните «Пользователи»: +10 баллов",
           "Заполните «Формат взаимодействия»: +5 баллов"]
}

Каталог, рекомендации и отклики

Каталог (GET /api/catalog):

  • показывает только опубликованные задачи (PUBLISHED); неопубликованные (status=DRAFT) в каталог не попадают, их можно открыть только по GET /api/tasks/{id};
  • сортировка — по убыванию рейтинга, при равном рейтинге — по возрастанию id;
  • фильтры (оба необязательны, можно сочетать): industry — код отрасли из GET /api/industries, level — уровень рейтинга (DRAFT, WORKING, READY, PRIORITY);
  • опубликованные задачи уровня DRAFT остаются в каталоге, но помечены needsClarification=true и clarificationNote="требует уточнения".

Публикация — только вручную (POST /api/tasks/{id}/publish), без проверки на минимальный рейтинг: бизнес сам решает, когда задача готова.

Рекомендации для команды (GET /api/teams/{id}/recommendations, TaskMatcher):

  • берутся опубликованные задачи уровня не ниже WORKING;
  • интересы, навыки и технологии команды сравниваются с текстом задачи (название отрасли и поля карточки, кроме контакта и формата взаимодействия);
  • слова приводятся к нижнему регистру, стоп-слова отбрасываются, слова сравниваются по основе (первые 5 букв);
  • задачи сортируются по числу совпадений (matchScore), в ответе видно, какие слова совпали (matchedKeywords).

Отклики:

  • откликнуться можно только на опубликованную задачу (иначе 409);
  • количество откликов не ограничено: одна команда может отправить несколько, на задачу может откликнуться сколько угодно команд;
  • выбор команды — только вручную. Бизнес сам принимает или отклоняет каждый отклик (accept / reject, только из статуса PENDING). Можно принять несколько откликов или ни одного. Ни ИИ, ни рейтинг, ни рекомендации команду не выбирают;
  • в списке откликов видны название команды и её баллы — они помогают бизнесу принять решение;
  • этап работы подтверждает бизнес (confirm-milestone, только для принятого отклика): команда получает +10 баллов, счётчик этапов отклика растёт на 1.

AI-функции

ИИ используется ровно в двух местах, оба — на стороне бизнеса до публикации:

ФункцияМетод APIЧто делает
Анализ черновикаPOST /api/tasks/analyzeнаходит незаполненные поля карточки и задаёт не меньше 3 вопросов
Сборка карточкиPOST /api/tasksсобирает карточку строго из черновика и ответов

Промпты и схемы:

Что ИИ не делает:

  • не выдумывает факты. Промпт запрещает добавлять цифры, имена, технологии, сроки, контакты и цели, которых нет в черновике и ответах. Нет сведений — поле остаётся пустой строкой. Пустое поле честно снижает рейтинг, и бизнес видит, что дописать;
  • не выбирает команду, не публикует задачу и не ставит оценку: это делают бизнес и детерминированный код.

Пример: анализ черновика

Запрос POST /api/tasks/analyze:

{
  "draftText": "Мы сеть из 12 кофеен в Алматы. Хотим понять, почему в будни после обеда падают продажи. Есть выгрузка чеков из кассовой системы за 2 года в Excel.",
  "industry": "HORECA"
}

Ответ (mock-режим, ничего не сохраняется):

{
  "missingFields": ["users", "constraints", "expectedResult", "successCriteria", "contact", "interactionFormat"],
  "questions": [
    { "field": "users", "question": "Кто будет пользоваться результатом: клиенты, сотрудники, руководители?" },
    { "field": "constraints", "question": "Есть ли ограничения: сроки, бюджет, обязательные технологии, правила работы с данными?" },
    { "field": "expectedResult", "question": "Что вы хотите получить в итоге: прототип, отчёт, модель, сервис?" },
    { "field": "successCriteria", "question": "По каким измеримым показателям вы поймёте, что задача решена (цифры, проценты)?" },
    { "field": "contact", "question": "Как команде связаться с представителем компании (имя, роль, почта или телефон)?" },
    { "field": "interactionFormat", "question": "Как вы готовы работать с командой: как часто встречаться, онлайн или очно?" }
  ]
}

Пример: сборка карточки

Запрос POST /api/tasks — тот же черновик и ответы бизнеса на часть вопросов:

{
  "draftText": "Мы сеть из 12 кофеен в Алматы. Хотим понять, почему в будни после обеда падают продажи. Есть выгрузка чеков из кассовой системы за 2 года в Excel.",
  "industry": "HORECA",
  "answers": [
    { "field": "expectedResult", "answer": "Дашборд с продажами по часам и рекомендации по акциям." },
    { "field": "successCriteria", "answer": "Рост дневной выручки после обеда на 10% за 2 месяца." },
    { "field": "contact", "answer": "Операционный менеджер, [email protected]" }
  ]
}

Ответ 201 Created (сокращён). Поля, о которых бизнес ничего не сказал (users, constraints, interactionFormat), остались пустыми:

{
  "id": 11,
  "industry": "HORECA",
  "industryName": "Гостиницы и общепит",
  "status": "DRAFT",
  "title": "Хотим понять, почему в будни после обеда падают продажи",
  "context": "Мы сеть из 12 кофеен в Алматы.",
  "need": "Хотим понять, почему в будни после обеда падают продажи.",
  "users": "",
  "data": "Есть выгрузка чеков из кассовой системы за 2 года в Excel.",
  "constraints": "",
  "expectedResult": "Дашборд с продажами по часам и рекомендации по акциям.",
  "successCriteria": "Рост дневной выручки после обеда на 10% за 2 месяца.",
  "contact": "Операционный менеджер, [email protected]",
  "interactionFormat": "",
  "rating": { "score": 75, "level": "READY", "levelName": "Готова к работе", "...": "..." },
  "needsClarification": false,
  "clarificationNote": null
}

Обработка некорректного ответа ИИ

  1. OpenAiLlmClient запрашивает ответ в режиме response_format: json_schema, strict: true, таймаут — 60 с.
  2. TaskAiService проверяет результат через Bean Validation: не меньше 3 вопросов, известные коды полей, допустимая длина полей карточки.
  3. Невалидный JSON, отказ модели, обрезанный ответ или нарушение правил — одна повторная попытка.
  4. Если и вторая попытка неудачна, либо LLM недоступен (сетевая ошибка, HTTP-ошибка — без повтора), API возвращает 502 с понятным сообщением, а в базу ничего не сохраняется:
{
  "status": 502,
  "error": "Bad Gateway",
  "message": "Не удалось обработать задачу с помощью ИИ. Попробуйте ещё раз чуть позже",
  "timestamp": "2026-09-23T10:15:30Z"
}

Mock-режим

LLM_MODE=mock (по умолчанию) включает MockLlmClient — детерминированный офлайн-клиент для демо, CI и тестов:

  • делит черновик на предложения и раскладывает их по полям карточки по ключевым словам (без совпадений — в «Контекст»); название — первое предложение о потребности;
  • ответы бизнеса дописывает в их поля;
  • analyze спрашивает о незаполненных полях и добирает до 3 вопросов самыми слабыми полями;
  • никогда не придумывает текст: в карточке только предложения из черновика и ответов.

API

Полное описание с примерами — в Swagger UI (/swagger-ui.html).

Метод и адресЧто делает
POST /api/tasks/analyze{draftText, industry} → недостающие поля и не меньше 3 вопросов
POST /api/tasks{draftText, industry, answers: [{field, answer}]} → задача DRAFT
GET /api/tasks/{id}задача с полями карточки и рейтингом
PUT /api/tasks/{id}/cardправка карточки (все поля заменяются), пересчёт рейтинга
POST /api/tasks/{id}/publishручная публикация (PUBLISHED)
GET /api/catalog?industry=&level=опубликованные задачи по убыванию рейтинга
GET /api/industriesотрасли: код и название
GET /api/teamsкоманды с интересами, навыками, технологиями и баллами
GET /api/teams/{id}/recommendationsзадачи уровня от WORKING по совпадению навыков и интересов команды
POST /api/tasks/{id}/proposalsотклик {teamId, idea, plan, duration, prototypeUrl}, только на опубликованную задачу
GET /api/tasks/{id}/proposalsотклики на задачу в порядке поступления
POST /api/proposals/{id}/accept, /rejectрешение бизнеса по отклику
POST /api/proposals/{id}/confirm-milestoneподтверждение этапа, команда получает +10 баллов

Валидация: черновик — 20–5000 символов, отрасль обязательна, не больше 20 ответов с известным полем; поля карточки — до 3000 символов (название — до 200, контакт — до 300); отклик: идея — 10–2000 символов, план — 10–4000, срок обязателен, ссылка на прототип необязательна и должна начинаться с http(s)://.

Ошибки возвращаются в едином формате с сообщением на русском:

{
  "status": 404,
  "error": "Not Found",
  "message": "Задача с id=42 не найдена",
  "timestamp": "2026-09-23T10:15:30Z"
}

Коды: 400 — ошибка валидации или некорректный JSON (с полем fieldErrors), 404 — не найдено, 409 — действие недоступно в текущем статусе (например, отклик на неопубликованную задачу), 502 — ИИ не смог обработать задачу, 500 — непредвиденная ошибка.

Тестовые сценарии

Демо-сценарий (Swagger UI, mock-режим, демо-данные включены)

  1. Запустите приложение (docker compose up --build) и откройте http://localhost:8080/swagger-ui.html.
  2. GET /api/industries — список отраслей; возьмите код HORECA.
  3. POST /api/tasks/analyze с черновиком о кофейнях из примера выше — ИИ нашёл 6 незаполненных полей и задал 6 вопросов. В базе ничего не появилось.
  4. POST /api/tasks с черновиком и ответами на 3 вопроса — создана задача DRAFT с рейтингом 75 (READY). Пустые поля users, constraints, interactionFormat — ИИ их не выдумал; в tips видно, сколько баллов даст каждое.
  5. PUT /api/tasks/{id}/card — допишите пользователей, ограничения и формат взаимодействия (готовое тело есть в примере Swagger) — рейтинг вырос до 100 (PRIORITY).
  6. POST /api/tasks/{id}/proposals до публикации — 409: откликнуться на черновик нельзя.
  7. POST /api/tasks/{id}/publish — задача опубликована.
  8. GET /api/catalog — задача в каталоге, сортировка по рейтингу. Демо-задача уровня DRAFT внизу с пометкой «требует уточнения». Проверьте фильтры ?industry=HORECA и ?level=READY.
  9. GET /api/teams, затем GET /api/teams/1/recommendations — для команды Data Wizards первой идёт задача про пустые полки: совпали «розничная торговля» и «прогнозирование». Задач уровня DRAFT в рекомендациях нет.
  10. Отправьте два отклика на новую задачу от разных команд (teamId 1 и 5) — ограничений на количество нет.
  11. GET /api/tasks/{id}/proposals — бизнес видит оба отклика с названием и баллами команды.
  12. POST /api/proposals/{id}/accept для одного отклика, /reject для другого. Повторное решение — 409.
  13. POST /api/proposals/{id}/confirm-milestone для принятого отклика — баллы команды выросли на 10 (проверьте в GET /api/teams). Для отклонённого отклика — 409.

Автотесты

Запуск: .\mvnw.cmd clean verify. Все тесты работают офлайн (LLM_MODE=mock, демо-данные выключены) и выполняются в CI на каждый push в main и каждый pull request.

КлассЧто проверяет
TaskFlowTestсквозной сценарий от черновика до принятого отклика и подтверждения этапа; сортировка каталога и пометка DRAFT; рекомендации без черновых и неопубликованных задач; правила accept / reject / milestone; валидация всех запросов; 404 на русском; список отраслей
TaskControllerLlmFailureTestпри сбое ИИ API отвечает 502 и ничего не сохраняет
RatingServiceTestвес каждого критерия, пустая и полная карточка, половина баллов за критерии без цифр, минимальная длина поля, границы уровней, склонение «баллов»
TaskAiServiceTestодна повторная попытка при невалидном ответе (мало вопросов, неизвестное поле, слишком длинная карточка), ошибка после двух попыток, без повтора при недоступном LLM
TaskMatcherTestподсчёт совпадений, учёт названия отрасли, стоп-слова и регистр
MockLlmClientTestкарточка только из предложений черновика, ответы в своих полях, не меньше 3 вопросов, детерминированность
OpenAiLlmClientTestзапрос со structured output, разбор ответа; невалидный JSON, отказ модели, обрезанный ответ и HTTP-ошибка
TaskSchemaTestJSON-схемы совпадают с DTO, CardField.CODE_PATTERN содержит все поля
LlmConfigTestmock по умолчанию, OpenAI с ключом, отказ старта без ключа и с неизвестным режимом
DemoDataLoaderTestдемо-данные создаются в пустой базе и не дублируются в заполненной
HealthControllerTest, QadamApplicationTestshealth check и запуск контекста Spring
Звёзды
⭐ 0
Форки
0
Язык
Java
Последний push
в прошлом месяце
Коммиты
32
Авторы
4
Файлы
106
Ветки
10

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

honor 19vuus1d 8kaharnasyrhan 4Kakhar Nassyrkhan 1

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

  • 2026-09-23 17:59docs: prepare Qadam README for hackathon presentationkaharnasyrhan
  • 2026-09-23 17:54Merge pull request #9 from BAITC-Hacks/feature/business-frontendvuus1d
  • 2026-09-23 17:51merge main into business frontendkaharnasyrhan
  • 2026-09-23 17:39Merge pull request #8 from BAITC-Hacks/docs/readmevuus1d
  • 2026-09-23 17:34feat: add Qadam business frontendkaharnasyrhan
  • 2026-09-23 17:29docs: complete README with architecture, rating, catalog, AI and test scenarioshonor
  • 2026-09-23 17:23Merge pull request #7 from BAITC-Hacks/feature/business-tasksvuus1d
  • 2026-09-23 17:23docs: describe the business task platform in README and CLAUDE.mdhonor
Все коммиты (32)
  • 2026-09-23 17:23feat: turn Qadam into a business task platform for studentshonor
  • 2026-09-23 16:44Merge pull request #6 from BAITC-Hacks/feature/frontendKakhar Nassyrkhan
  • 2026-09-23 16:30feat: add Qadam adaptive learning frontendkaharnasyrhan
  • 2026-09-23 16:13Merge pull request #5 from BAITC-Hacks/feature/ci-dockervuus1d
  • 2026-09-23 16:11docs: add CI badge, quick start and CI/Docker noteshonor
  • 2026-09-23 16:11build: add JaCoCo coverage report on verifyhonor
  • 2026-09-23 16:11build: add GitHub Actions CI workflow with coverage artifacthonor
  • 2026-09-23 16:11build: add multi-stage Dockerfile and docker compose setuphonor
  • 2026-09-23 15:20Merge pull request #4 from BAITC-Hacks/feature/rest-endpointsvuus1d
  • 2026-09-23 15:18feat: add lesson REST API with teacher review workflowhonor
  • 2026-09-23 15:18test: cover lesson API, error handling and demo datahonor
  • 2026-09-23 15:18docs: document REST endpoints, error format and demo datahonor
  • 2026-09-23 14:54Merge pull request #3 from BAITC-Hacks/feature/pictogramsvuus1d
  • 2026-09-23 14:48feat: enrich lesson cards with ARASAAC pictogramshonor
  • 2026-09-23 14:48docs: add ARASAAC attribution and pictogram layer noteshonor
  • 2026-09-23 14:35Merge pull request #2 from BAITC-Hacks/feature/llm-agentvuus1d
  • 2026-09-23 14:33feat: add LLM layer with OpenAI and mock clientshonor
  • 2026-09-23 14:33docs: describe LLM layer and project name in CLAUDE.mdhonor
  • 2026-09-23 14:21Merge pull request #1 from BAITC-Hacks/feature/domain-modelvuus1d
  • 2026-09-23 14:19feat: add lesson domain model with adaptation profileshonor
  • 2026-09-23 14:11chore: add gitignore, gitattributes and env examplehonor
  • 2026-09-23 14:11build: set up Maven project with Spring Boot 3.5 and Maven Wrapperhonor
  • 2026-09-23 14:11feat: add application skeleton and GET /api/health endpointhonor
  • 2026-09-23 14:11docs: add CLAUDE.md and project overview to READMEhonor
Структура репозитория (106 файлов)
.dockerignore
.env.example
.gitattributes
.github/workflows/ci.yml
.gitignore
.mvn/wrapper/maven-wrapper.properties
CLAUDE.md
Dockerfile
README.md
docker-compose.yml
mvnw
mvnw.cmd
pom.xml
src/main/java/com/qadam/QadamApplication.java
src/main/java/com/qadam/config/DemoDataLoader.java
src/main/java/com/qadam/config/LlmConfig.java
src/main/java/com/qadam/config/LlmProperties.java
src/main/java/com/qadam/config/OpenApiConfig.java
src/main/java/com/qadam/config/package-info.java
src/main/java/com/qadam/controller/ApiExamples.java
src/main/java/com/qadam/controller/GlobalExceptionHandler.java
src/main/java/com/qadam/controller/HealthController.java
src/main/java/com/qadam/controller/ProposalController.java
src/main/java/com/qadam/controller/TaskController.java
src/main/java/com/qadam/controller/TeamController.java
src/main/java/com/qadam/dto/AnalyzeTaskRequest.java
src/main/java/com/qadam/dto/ClarifyingQuestion.java
src/main/java/com/qadam/dto/CreateProposalRequest.java
src/main/java/com/qadam/dto/CreateTaskRequest.java
src/main/java/com/qadam/dto/ErrorResponse.java
src/main/java/com/qadam/dto/FieldAnswer.java
src/main/java/com/qadam/dto/FieldErrorResponse.java
src/main/java/com/qadam/dto/HealthResponse.java
src/main/java/com/qadam/dto/IndustryResponse.java
src/main/java/com/qadam/dto/ProposalResponse.java
src/main/java/com/qadam/dto/Rating.java
src/main/java/com/qadam/dto/RecommendationResponse.java
src/main/java/com/qadam/dto/TaskAnalysis.java
src/main/java/com/qadam/dto/TaskCard.java
src/main/java/com/qadam/dto/TaskResponse.java
src/main/java/com/qadam/dto/TeamResponse.java
src/main/java/com/qadam/llm/LlmClient.java
src/main/java/com/qadam/llm/LlmException.java
src/main/java/com/qadam/llm/LlmInvalidResponseException.java
src/main/java/com/qadam/llm/TaskPrompts.java
src/main/java/com/qadam/llm/mock/MockLlmClient.java
src/main/java/com/qadam/llm/openai/ChatCompletionRequest.java
src/main/java/com/qadam/llm/openai/ChatCompletionResponse.java
src/main/java/com/qadam/llm/openai/OpenAiLlmClient.java
src/main/java/com/qadam/llm/package-info.java
src/main/java/com/qadam/model/CardField.java
src/main/java/com/qadam/model/Industry.java
src/main/java/com/qadam/model/Proposal.java
src/main/java/com/qadam/model/ProposalStatus.java
src/main/java/com/qadam/model/RatingLevel.java
src/main/java/com/qadam/model/StringListConverter.java
src/main/java/com/qadam/model/Task.java
src/main/java/com/qadam/model/TaskStatus.java
src/main/java/com/qadam/model/Team.java
src/main/java/com/qadam/model/package-info.java
src/main/java/com/qadam/repository/ProposalRepository.java
src/main/java/com/qadam/repository/TaskRepository.java
src/main/java/com/qadam/repository/TeamRepository.java
src/main/java/com/qadam/repository/package-info.java
src/main/java/com/qadam/service/DemoData.java
src/main/java/com/qadam/service/InvalidStateException.java
src/main/java/com/qadam/service/LlmFailureException.java
src/main/java/com/qadam/service/NotFoundException.java
src/main/java/com/qadam/service/ProposalService.java
src/main/java/com/qadam/service/RatingService.java
src/main/java/com/qadam/service/TaskAiService.java
src/main/java/com/qadam/service/TaskMatcher.java
src/main/java/com/qadam/service/TaskService.java
src/main/java/com/qadam/service/TeamService.java
src/main/java/com/qadam/service/package-info.java
src/main/resources/application.yml
src/main/resources/llm/task-analysis.schema.json
src/main/resources/llm/task-card.schema.json
src/main/resources/prompts/analyze-task.md
src/main/resources/prompts/build-card.md
src/main/resources/static/api.mjs
src/main/resources/static/app.js
src/main/resources/static/favicon.svg
src/main/resources/static/index.html
src/main/resources/static/lesson-utils.mjs
src/main/resources/static/mock-data.mjs
src/main/resources/static/mock-service.mjs
src/main/resources/static/styles.css
src/main/resources/static/tests/business-flow.test.mjs
src/main/resources/static/ui-utils.mjs
src/test/frontend/README.md
src/test/frontend/lesson-utils.test.mjs
src/test/frontend/preview.mjs
src/test/java/com/qadam/QadamApplicationTests.java
src/test/java/com/qadam/config/DemoDataLoaderTest.java
src/test/java/com/qadam/config/LlmConfigTest.java
src/test/java/com/qadam/controller/HealthControllerTest.java
src/test/java/com/qadam/controller/TaskControllerLlmFailureTest.java
src/test/java/com/qadam/controller/TaskFlowTest.java
src/test/java/com/qadam/llm/mock/MockLlmClientTest.java
src/test/java/com/qadam/llm/openai/OpenAiLlmClientTest.java
src/test/java/com/qadam/llm/openai/TaskSchemaTest.java
src/test/java/com/qadam/service/RatingServiceTest.java
src/test/java/com/qadam/service/TaskAiServiceTest.java
src/test/java/com/qadam/service/TaskMatcherTest.java
src/test/resources/application.properties
Ветки (10)

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

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

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