Qadam
Платформа, где бизнес описывает задачу своими словами, ИИ задаёт уточняющие вопросы и собирает карточку задачи; прозрачный рейтинг готовности…
О проекте
Команда: 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.mdQadam
Qadam (каз. «шаг») — платформа бизнес-задач для студенческих команд: от сырой идеи к готовой задаче шаг за шагом.
Бизнес описывает задачу своими словами, ИИ задаёт уточняющие вопросы и собирает из черновика и ответов карточку задачи — без выдуманных фактов: если сведений нет, поле остаётся пустым. Прозрачный рейтинг (без ИИ) показывает, насколько карточка готова и что добавить. Бизнес вручную публикует задачу, студенческие команды получают рекомендации и откликаются, бизнес сам принимает отклики и подтверждает этапы работы (+10 баллов команде).
Содержание
- Команда
- Архитектура и стек
- Запуск
- Рейтинг карточки
- Каталог, рекомендации и отклики
- AI-функции
- API
- Тестовые сценарии
Команда
Команда хакатона «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, загрузка демо-данных |
controller | REST-контроллеры, единый обработчик ошибок, примеры для Swagger |
dto | записи запросов и ответов: TaskCard, TaskAnalysis, Rating, … |
model | JPA-сущности 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
После запуска:
- Health check: http://localhost:8080/api/health →
{"status":"ok"} - Swagger UI: http://localhost:8080/swagger-ui.html (в нём есть примеры запросов для всех методов)
- Консоль H2: http://localhost:8080/h2-console (JDBC URL
jdbc:h2:mem:qadam)
Переменные окружения (см. .env.example):
| Переменная | По умолчанию | Назначение |
|---|---|---|
LLM_MODE | mock | mock — офлайн без сети, openai — настоящий LLM |
OPENAI_API_KEY | — | обязателен при LLM_MODE=openai, иначе приложение не стартует |
OPENAI_MODEL | gpt-4o-mini | модель OpenAI с поддержкой structured output |
DEMO_DATA_ENABLED | true | заполнить пустую базу демо-данными при старте |
Режим 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). Поле «Название» в рейтинге не участвует.
Уровни готовности:
| Уровень | Баллы | Название | Что это значит |
|---|---|---|---|
DRAFT | 0–39 | Черновик | в каталоге с пометкой «требует уточнения», в рекомендации не попадает |
WORKING | 40–69 | Рабочая задача | можно начинать, но часть сведений придётся уточнить |
READY | 70–89 | Готова к работе | сведений достаточно для старта |
PRIORITY | 90–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 | собирает карточку строго из черновика и ответов |
Промпты и схемы:
- системные промпты:
prompts/analyze-task.md,prompts/build-card.md; - строгие JSON-схемы ответа:
llm/task-analysis.schema.json,llm/task-card.schema.json.TaskSchemaTestпроверяет, что схемы совпадают с DTO.
Что ИИ не делает:
- не выдумывает факты. Промпт запрещает добавлять цифры, имена, технологии, сроки, контакты и цели, которых нет в черновике и ответах. Нет сведений — поле остаётся пустой строкой. Пустое поле честно снижает рейтинг, и бизнес видит, что дописать;
- не выбирает команду, не публикует задачу и не ставит оценку: это делают бизнес и детерминированный код.
Пример: анализ черновика
Запрос 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
}
Обработка некорректного ответа ИИ
OpenAiLlmClientзапрашивает ответ в режимеresponse_format: json_schema, strict: true, таймаут — 60 с.TaskAiServiceпроверяет результат через Bean Validation: не меньше 3 вопросов, известные коды полей, допустимая длина полей карточки.- Невалидный JSON, отказ модели, обрезанный ответ или нарушение правил — одна повторная попытка.
- Если и вторая попытка неудачна, либо 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-режим, демо-данные включены)
- Запустите приложение (
docker compose up --build) и откройте http://localhost:8080/swagger-ui.html. GET /api/industries— список отраслей; возьмите кодHORECA.POST /api/tasks/analyzeс черновиком о кофейнях из примера выше — ИИ нашёл 6 незаполненных полей и задал 6 вопросов. В базе ничего не появилось.POST /api/tasksс черновиком и ответами на 3 вопроса — создана задачаDRAFTс рейтингом 75 (READY). Пустые поляusers,constraints,interactionFormat— ИИ их не выдумал; вtipsвидно, сколько баллов даст каждое.PUT /api/tasks/{id}/card— допишите пользователей, ограничения и формат взаимодействия (готовое тело есть в примере Swagger) — рейтинг вырос до 100 (PRIORITY).POST /api/tasks/{id}/proposalsдо публикации —409: откликнуться на черновик нельзя.POST /api/tasks/{id}/publish— задача опубликована.GET /api/catalog— задача в каталоге, сортировка по рейтингу. Демо-задача уровняDRAFTвнизу с пометкой «требует уточнения». Проверьте фильтры?industry=HORECAи?level=READY.GET /api/teams, затемGET /api/teams/1/recommendations— для команды Data Wizards первой идёт задача про пустые полки: совпали «розничная торговля» и «прогнозирование». Задач уровняDRAFTв рекомендациях нет.- Отправьте два отклика на новую задачу от разных команд (
teamId1 и 5) — ограничений на количество нет. GET /api/tasks/{id}/proposals— бизнес видит оба отклика с названием и баллами команды.POST /api/proposals/{id}/acceptдля одного отклика,/rejectдля другого. Повторное решение —409.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-ошибка |
TaskSchemaTest | JSON-схемы совпадают с DTO, CardField.CODE_PATTERN содержит все поля |
LlmConfigTest | mock по умолчанию, OpenAI с ключом, отказ старта без ключа и с неизвестным режимом |
DemoDataLoaderTest | демо-данные создаются в пустой базе и не дублируются в заполненной |
HealthControllerTest, QadamApplicationTests | health check и запуск контекста Spring |
Авторы коммитов
История коммитов
- 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
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.