Собрано
Веб-приложение подбора до трёх event-подрядчиков из каталога 66 анкет с проверяемыми объяснениями.
О проекте
Команда: Volga Production
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Доведённый продукт
Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор
Суть
Веб-приложение подбора до трёх event-подрядчиков из каталога 66 анкет с проверяемыми объяснениями. Для ведущих есть отдельное AI-сравнение и чат для уточнений. Приложение развёрнуто на Railway.
Как устроено
Форма проходит серверную валидацию Zod, затем применяются строгие фильтры: город и категория, дата, цена, формат, язык, длительность. Смысловая близость формата и пожеланий считается эмбеддингами text-embedding-3-small, после сортировки остаётся максимум три подрядчика. LLM (gpt-5.6-sol) выбирает цитату из анкеты, код проверяет, что она есть в исходном тексте, и формирует фактическое объяснение с источником и причинами исключения. Эмбеддинги и ответы кешируются в Docker-томе, при сбое API явно показывается резервный режим.
Ключевые решения
- строгая фильтрация по ограничениям
- эмбеддинг-ранжирование
- проверка цитат LLM по источнику
- кеширование ответов
- Playwright e2e
Особенности
Подтверждение цитат: модель только выбирает фрагмент анкеты, а код проверяет его наличие в источнике, поэтому объяснения можно сверить с анкетой. Есть публичный деплой для жюри, smoke-скрипт проверки повторяемости и сохранённые свидетельства проверки в docs/evidence.
Стек
TypeScript · Next.js · React · Mantine · Zod · csv-parse · OpenAI Responses API · Docker Compose · Railway · Playwright
Модели
gpt-5.6-sol · text-embedding-3-small
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-875e970e-volga-production.
README
README.mdСобрано — умный подбор event-подрядчиков
Прототип команды Volga Production для кейса «Умный подбор подрядчиков (#79-lite)». Заказчик задаёт условия мероприятия и получает до трёх карточек с проверяемыми объяснениями из предоставленного каталога Казахстана.
Для жюри: приложение уже развёрнуто
- Откройте готовое приложение: sobrano-production.up.railway.app. Установка, регистрация и собственный API-ключ для проверки по этой ссылке не нужны.
- Нажмите «Найти совпадения» с исходными параметрами формы. Ожидаемый результат — три карточки ведущих для корпоратива в Алматы на 15.10.2026 с бюджетом 1 000 000 ₸. В каждой карточке указаны условия и основание выбора; раскройте источник, чтобы сверить цитату с анкетой.
- Проверьте примеры под формой: «Другая дата», «Флористы», «Малый бюджет», «Нет категории». После выбора примера снова нажмите «Найти совпадения». Ожидаются соответственно изменившаяся подборка, два флориста, объяснение несовпадения условий и сообщение об отсутствии категории.
- Для независимого локального запуска выполните инструкцию Docker Compose ниже. Она также подходит, если публичное демо недоступно.
На публичном сайте работает серверный AI-подбор. Повторные запросы могут возвращаться из кеша. При сбое внешнего API приложение явно обозначает резервный режим. Продукт не бронирует подрядчиков и не отправляет заявки; пустая выдача — отдельный объяснённый результат.
Текущая версия опубликована и проверена 23.09.2026: шесть API-сценариев с повтором, AI-ответы по ведущим и 16 браузерных тестов. Историческая проверка сохранения результатов после перезапуска описана отдельно. Подробности и свидетельства проверки.
Чат по ведущим и восстановление страницы доступны в опубликованной версии. Пуш в GitHub сам по себе не запускает деплой Railway; текущий выпуск загружен через CLI.
Локальный запуск через Docker Compose
Этот способ запускает всё приложение одной командой. Node.js и npm на компьютере устанавливать не требуется.
Требования
- Docker Desktop (Windows/macOS) или Docker Engine с Docker Compose v2+ (Linux); Docker запущен.
- Копия репозитория. Для команды клонирования ниже нужны Git и доступ к репозиторию организаторов; можно также скачать и распаковать ZIP через GitHub.
- Свободный порт
3000. - Доступ к интернету: при сборке — Docker Hub и npm; при новых AI-запросах —
api.openai.com. - OpenAI API-ключ с балансом и доступом к
gpt-5.6-solиtext-embedding-3-small. - Исходный файл
data/hackathon_dataset_anonymized.csvвключён в репозиторий; 66 профилей, отдельная БД не нужна. Каталогdata/хранит данные, которые приложение читает во время работы; размещать CSV вpublic/не нужно.
1. Получите проект
git clone https://github.com/BAITC-Hacks/hack-875e970e-volga-production.git
cd hack-875e970e-volga-production
Если проект уже скачан, откройте терминал в его корневой папке — там находятся Dockerfile, compose.yaml и .env.example. Все следующие команды выполняются из этой папки.
2. Настройте окружение
Создайте .env из примера, если .env ещё нет:
cp .env.example .env
В Windows PowerShell можно использовать Copy-Item .env.example .env. Откройте .env в текстовом редакторе и вставьте свой ключ в OPENAI_API_KEY. Не коммитьте ключ. Пример конфигурации без секрета:
OPENAI_API_KEY=вставьте_свой_ключ
OPENAI_MODEL=gpt-5.6-sol
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
CACHE_DIR=.cache/sobrano
Новые AI-запросы используют баланс вашего OpenAI API-аккаунта. Без ключа можно проверить интерфейс и строгую фильтрацию: оставьте OPENAI_API_KEY= пустым. Приложение будет явно показывать резервный режим; это не проверка полноценного AI-сценария.
3. Соберите и запустите приложение
docker compose up --build -d
docker compose ps
Дождитесь окончания сборки и статуса healthy у сервиса app в выводе docker compose ps. Первый запуск включает загрузку образа и npm-зависимостей. Ход работы можно посмотреть командой docker compose logs --tail=50 app.
Откройте http://localhost:3000. Для проверки сервера откройте http://localhost:3000/api/health в браузере или выполните:
curl --fail http://localhost:3000/api/health
Ожидаемый ответ: {"status":"ok","profiles":66}. Health проверяет загрузку каталога; доступность OpenAI проверяется следующим шагом.
4. Проверьте основной сценарий
Нажмите «Найти совпадения» с исходными параметрами формы и пройдите примеры из первого раздела README. Таблица ожидаемых результатов приведена ниже. Повторите одинаковый запрос: состав и порядок карточек должны сохраниться.
Данные уже включены в репозиторий: импортировать CSV, создавать БД или запускать миграции не нужно. При первом AI-запросе эмбеддинги 66 анкет создаются автоматически и сохраняются в Docker-томе selection-cache. Если API недоступен или не уложился в срок, появится явно обозначенный резервный режим. Причины и действия описаны в разделе устранения проблем.
Для категории «Ведущий» после карточек отдельно загружается сравнение и открывается чат для уточнений. После обновления страницы в той же вкладке восстанавливаются форма, карточки, ответы и черновик вопроса через sessionStorage. Изменение условий сбрасывает подборку и диалог. Сохранение зависит от доступности хранилища браузера и ограничено сессией вкладки.
5. Остановите или запустите повторно
Остановка:
docker compose down
Повторный запуск с сохранённым кешем:
docker compose up -d
После изменения кода или .env снова выполните docker compose up --build -d.
Кеш сохраняется после остановки. docker compose down -v удаляет только тома этого Compose-проекта, включая сохранённые результаты; после этого AI-запросы оплачиваются заново. Используйте эту команду только для намеренного сброса/проверки чистого запуска.
Переменные окружения
| Переменная | Назначение |
|---|---|
OPENAI_API_KEY | Серверный ключ OpenAI; без него работает явно обозначенный резервный подбор |
OPENAI_MODEL | Модель выбора цитат и ответа в чате, по умолчанию gpt-5.6-sol |
OPENAI_EMBEDDING_MODEL | Модель смыслового поиска, по умолчанию text-embedding-3-small |
CACHE_DIR | Локально .cache/sobrano; Compose задаёт /app/.cache/sobrano |
Ключ не попадает в клиентский JavaScript, образ Docker или ответы API. .env исключён из Git и Docker-контекста. В OpenAI передаются описания анонимизированных анкет и параметры запроса; не вводите персональные данные в пожелания. Для Responses используется store: false. Локальный кеш содержит параметры запросов и результаты, без ключей.
Разработка без Docker
Node.js 22+, npm; зависимости закреплены package-lock.json.
npm ci
# Подготовьте .env по инструкции выше.
npm run prepare:data
npm run dev
Откройте http://localhost:3000. prepare:data проверяет каталог и создаёт эмбеддинги заранее; это опционально. Для production: npm run build, затем npm start.
| Команда | Что проверяет / делает |
|---|---|
npm test | Фильтры, данные, валидация, смысловое ранжирование, сбои, подтверждение цитат и кеш |
npm run typecheck | Типы TypeScript |
npm run build | Production-сборка Next.js |
npx playwright install chromium | Однократная установка тестового браузера |
npm run test:e2e | Браузерные проверки; приложение должно работать на порту 3000 |
node --import tsx scripts/smoke.ts | Реальные API-запросы, повторяемость; сохраняет результаты в docs/evidence/smoke.json |
node --import tsx scripts/verify-runtime.ts | Сравнивает 24 параллельных ответа с сохранённым smoke-прогоном; запускать после него, в том числе после перезапуска контейнера |
APP_URL позволяет smoke-скрипту и Playwright проверять другой адрес. Тесты npm test используют явно заданные тестовые сервисы и не расходуют API. Smoke и часть браузерных сценариев обращаются к настоящему API приложения; при настроенном ключе новые запросы могут расходовать API. Проверки восстановления вкладки, часть контролов и чата используют явно заданные ответы/перехват запросов и не подтверждают работу модели.
Smoke/runtime и браузерные скриншоты перезаписывают файлы в docs/evidence/. Для нового аудита сохраняйте результаты отдельно, чтобы не заменить исторические AI-свидетельства резервным прогоном. scripts/production-* воспроизводят исторический production-регресс, содержат фиксированный публичный адрес и не учитывают APP_URL.
Устройство решения
Форма → серверная валидация → город + категория
↓
дата + цена + формат + язык + длительность
↓
эмбеддинги: смысловая близость формата и пожеланий
↓
сортировка → максимум 3 подрядчика
↓
AI выбирает цитату → код проверяет её в исходной анкете
↓
фактическое объяснение + источник + причины исключения
↓
Для ведущих: карточки видны сразу → отдельный AI-ответ → уточнения в чате
app/: интерфейс, стили и HTTP-маршруты;lib/: каталог, фильтрация, OpenAI, кеш и подбор.tests/: автоматические проверки;scripts/: подготовка данных и реальные проверочные прогоны.docs/: принятые решения и результаты технической проверки;public/пока содержит только.gitkeep, сохраняющий каталог для Docker-сборки. Иконка приложения —app/icon.svg.- Next.js App Router + React + TypeScript; CSV разбирает
csv-parse, вход и ответ модели проверяет Zod. Отдельной БД, векторного сервера и дообучения нет.
Фильтрация и ранжирование
Город и категория проверяются по структурированным полям. Описание о выездах не отменяет фильтр города. Цена «от» должна быть не выше бюджета. Занятые на дату исключаются всегда. Если язык или часы заданы, они также обязательны. max_hours = null означает «присутствие не применимо»; не ноль и не неизвестную длительность. Список категорий разбирается как массив.
Семантический запрос содержит категорию, формат и пожелания; без пожеланий ищется опыт соответствующего формата. Косинусное сходство округляется до шести знаков, затем равенство разрешается по цене и id. Сходство не показываем как процент качества или вероятность успеха.
AI выбирает конкретную дословную цитату и тип особенности. Сервер проверяет идентификаторы и наличие цитаты в description, затем сам формирует текст с датой, форматом, бюджетом и выбранной особенностью. Свободные обещания модели в карточки не попадают. Под раскрываемым блоком доступен полный источник. Перед выбором цитаты применяется консервативный набор признаков конкретной услуги или способа работы (например, инструменты, состав, репертуар, оборудование, вместимость). Общие рекламные фразы не используются как индивидуальное основание. Если подходящий фрагмент не найден или не отличается от уже выбранных, подрядчик остаётся в выдаче с честным сообщением о нехватке конкретики; полная анкета доступна для проверки. Это эвристика для текущего каталога, а не полная оценка смысла: необычно сформулированные полезные сведения могут быть пропущены. Смысловая релевантность цитаты всё равно требует оценки человеком.
Для категории «Ведущий» модель gpt-5.6-sol с reasoning.effort=low также пишет связный ответ по не более чем трём уже отфильтрованным анкетам. Карточки возвращаются отдельным первым запросом и не ждут генерации текста. Первый вариант выделен как первый по смысловой близости; если смысловой этап недоступен, подпись честно меняется на «первый по начальной цене». Это порядок ранжирования, а не гарантия качества подрядчика. Сервер проверяет принадлежность переданных моделью mentionedIds текущей подборке. Форму нельзя изменить текстом чата; вопросы о другой категории и попытки переопределить правила получают ответ с предложением изменить форму. Ответы чата являются интерпретацией анкет и могут ошибаться, поэтому рядом остаются карточки с исходными сведениями. Инструкция модели требует опираться на анкеты и отделять предположения от сведений каталога. Для других категорий остаётся обычный подбор без чата.
Детерминизм и сбои
Кеш содержит версию алгоритма, хеш CSV, модели и нормализованные параметры. Он хранит эмбеддинги, подборки и ответы чата; одновременные одинаковые запросы внутри одного процесса объединяются. Запись атомарная. Один и тот же запрос при неизменной версии данных сохраняет порядок и текст первого ответа после перезапуска благодаря постоянному тому.
На внешние этапы подбора карточек выделено суммарно 8 секунд, автоматических повторов SDK нет. Генерация ответа чата имеет отдельный лимит 8,5 секунды. Прямой запрос /api/chat без готового кеша сначала выполняет подбор: общего серверного лимита 10 секунд у него нет. Интерфейс показывает карточки до сравнения и ждёт каждый запрос до 10 секунд; сеть и операции с диском не входят в лимит внешних этапов. Если смысловой этап недоступен, остаются строгие фильтры и сортировка по цене/ID. AI-цитаты проверяются на принадлежность анкете, содержательность и повтор между карточками по детерминированным правилам. Если выбор цитат недоступен или не проходит проверку, резервный режим выбирает отличающиеся фрагменты анкет с конкретными сведениями либо явно сообщает, что отличительная особенность не выделена. Это проверено на исходном каталоге по календарю и ценовым порогам; смысловую полезность всех формулировок всё равно нужно оценивать человеку. Резервный режим явно указан и тоже кешируется, чтобы повтор не менял порядок. Для его намеренного пересчёта нужно очистить соответствующий кеш; не делайте этого между проверками детерминизма.
Гарантия относится к одному экземпляру приложения с сохранённым кешем и неизменными данными/версиями. Для нескольких серверов понадобятся общий кеш и распределённая блокировка. Удаление кеша или изменение моделей/данных — новый расчёт.
HTTP API
POST /api/recommendations, Content-Type: application/json:
{
"city": "Алматы",
"date": "2026-10-15",
"format": "корпоратив",
"category": "Ведущий",
"budget": 1000000,
"language": "английский",
"hours": 5,
"wishes": "Спокойная подача для делового вечера"
}
Обязательны первые пять полей. Возвращаются status, cards (0–3), query, total, eligible, excluded, message, ranking, explanationMode и warnings. AI-текст не задерживает этот ответ.
Для вступительного сравнения ведущих отправьте POST /api/chat с JSON вида { "query": { ...поля формы... }, "message": "", "history": [] }. Для уточнения укажите вопрос в message, например «Кто спокойнее и почему?». Маршрут доступен только для категории «Ведущий» и после заполнения всех обязательных полей. Сервер заново проверяет условия формы и подбирает кандидатов; текст вопроса и переданная история не могут менять город, дату, бюджет или категорию. Для контекста используются только три последние реплики пользователя; ответы ассистента из браузера игнорируются как недоверенные данные. При сбое модели возвращается явно обозначенный резервный ответ; карточки и строгие фильтры остаются доступными.
У карточки evidenceStatus равен specific для выбранной цитаты или insufficient, когда конкретная отличительная особенность не выделена. Во втором случае evidence — пустая строка, а explanation объясняет ограничение; полный description сохраняется. explanationMode=ai означает, что AI использован для доступных цитат, и не исключает карточки с insufficient.
matched: хотя бы один подходящий профиль.category_absent: в этом городе нет такой категории.no_match: категория есть, но никто не проходит все ограничения.
В excluded счётчики причин пересекаются: один профиль может быть занят и одновременно дороже бюджета. Ошибочный ввод → 400 с полями; слишком большой запрос → 413; недоступный каталог/кеш → 503. Отсутствие результатов возвращает 200.
Проверка основного сценария
| Пример | Что ожидать до выбора тройки |
|---|---|
| Алматы, ведущий, корпоратив, 15.10.2026, 1 млн ₸ | 6 подходящих из 10; выдача до 3 |
| Те же условия, 16.10.2026 | 4 подходящих; изменившийся календарь меняет выдачу |
| Алматы, флорист, свадьба, 15.10.2026, 500 тыс. ₸ | 2 подходящих, оба показаны |
| Алматы, ведущий, корпоратив, 15.10.2026, 100 тыс. ₸ | no_match, причины видны |
| Астана, декоратор | category_absent |
Убедитесь, что занятых нет; повторите запрос и сравните порядок; раскройте источники. Результаты реальных запросов сохранены в docs/evidence/smoke.json; скриншоты проверки интерфейса — в той же папке. Это технические свидетельства проверок, не подмена работы приложения.
Реализация и история проверок
Реализованы полный подбор, AI-сопоставление пожеланий, проверяемые цитаты, три исхода, чат по ведущим, восстановление результата после обновления страницы и явные резервные режимы.
Повторный аудит кода 8295740 от 23.09.2026: 25/25 модульных и 16/16 браузерных тестов, TypeScript и production-сборка прошли. Текущая версия запущена через Compose с новым пустым томом; после перезапуска совпали 24/24 повторных ответа. Этот свежий прогон выполнен без API-ключа, в явном резервном режиме. После локального аудита текущая версия опубликована и проверена отдельно: результаты production.
Результаты проверок и разбор файлов. Карта реализации требований. Официальное ТЗ получено и сверено; сводка и ссылка на источник.
Исторические результаты: обновление объяснений и production-регресс.
Ниже — исторический прогон локальной ветки с чатом до слияния улучшений конкретности объяснений из main. Приложение было собрано и запущено через Docker Compose с новым пустым томом кеша; эти результаты не заменяют свежую проверку AI текущей версии. Свежий чистый запуск в резервном режиме описан выше.
- 19 автоматических тестов логики и кеша — пройдены, включая ограничения чата и проверку различимости резервных объяснений.
- 12 браузерных проверок Docker-версии — пройдены, включая ширины 375, 414, 768, 1024 и 1440 px, показ карточек до завершения AI-сравнения, диалог, оба пустых исхода, раскрытие источников и повтор после сетевой ошибки.
- TypeScript и production-сборка — пройдены;
.envвнутри образа отсутствует. - 24 параллельных ответа новой версии полностью совпали с сохранёнными ответами того же контейнера. Результат —
docs/evidence/runtime.json. - Ниже фактические измерения последовательного прогона нового контейнера с первоначально пустым томом.
ms— время выдачи карточек;chatMs— отдельное вступительное сравнение. Это не нагрузочный тест и не гарантия задержки на другом оборудовании или сети.
| Запрос | Карточки | Сравнение | Ранжирование / объяснения / ответ |
|---|---|---|---|
| autumn | 5662 мс | 8285 мс | semantic / ai / ai |
| next-date | 5063 мс | 8517 мс | semantic / facts / fallback |
| rare | 5398 мс | — | semantic / ai / — |
| no-match | 7 мс | — | none / none / — |
| absent | 5 мс | — | none / none / — |
| wishes | 3654 мс | 5047 мс | semantic / ai / ai |
Соответствие критериям ТЗ
Таблица подтверждена по официальному заданию и отличается от общей таблицы AGENTS.md; для кейса используем её.
| Критерий | Готовое доказательство | Оставшееся ограничение |
|---|---|---|
| Работоспособность — 25 | Реальные запросы, три исхода, смена даты и повторяемость | Каталог ограничен исходными 66 профилями |
| Техническая реализация — 25 | Разделённые фильтры/AI, проверка источников, тесты, постоянный кеш | Один экземпляр; нет ограничения публичных запросов и мониторинга расходов |
| README и воспроизводимость — 25 | Compose, пример окружения, команды; текущий чистый запуск проверен без ключа | Публичный AI-прогон выполнен; для новых локальных AI-запросов нужны ключ, баланс и сеть |
| Ценность — 15 | До трёх вариантов с различимыми основаниями | Пользовательская польза ещё не измерялась исследованием |
| Развитие и оригинальность — 10 | Выбор с источниками и честным отказом; описан путь к управляемому каталогу | Администрирование каталога и подтверждение календарей/цен пока не реализованы |
Ограничения и дальнейшее развитие
- Каталог — 66 анонимизированных профилей, включая 13 синтетических от организаторов; 18 цен и 8 городов проставлены при подготовке. Это обозначено на карточках.
- Календарь только 23.09–31.12.2026. «Свободен» означает отсутствие занятости в предоставленном календаре, не подтверждение подрядчика.
- Цена «от» не гарантирует итоговую стоимость, пожелания не гарантируют наличие услуги; рекламные заявления не проверены независимо.
- Пользовательских исследований, измерений экономии времени и доказанного превосходства над альтернативами пока нет.
- Следующий этап развития — закрытый интерфейс для администратора каталога: добавление, исправление и снятие с публикации анкет без редактирования файла в коде. Потребуются постоянное хранилище, проверка обязательных полей, разграничение доступа и обновление AI-индекса/кеша при изменении опубликованных данных. Массовый импорт CSV/XLSX можно добавить позже как инструмент администратора; произвольные файлы посетителей не входят в текущий сценарий.
- Для актуальности сведений одного интерфейса недостаточно: понадобится дата последнего подтверждения и процесс проверки цен и занятости с подрядчиками. Пользу следующего этапа следует проверить с организаторами; сравнение подборок с сортировкой по цене пока не проводилось.
- Для публичной эксплуатации затем понадобятся общий кеш, ограничение запросов и мониторинг расходов.
- Публичное демо развёрнуто на Railway в одном экземпляре с постоянным кешем. Для длительной публичной эксплуатации нужны ограничение расходов и запросов. Настройки и повторный деплой.
Типичные проблемы
- Docker daemon недоступен: запустите Docker Desktop; проверьте
docker info. - Не найден
.env: скопируйте.env.exampleв.envв корне проекта. Файл необходим для Compose, даже если ключ оставлен пустым. - Порт 3000 занят: остановите локальный
npm run devлибо измените левый порт в Compose на3001:3000, повторитеdocker compose up -dи откройтеhttp://localhost:3001. - Сайт не открывается после запуска: проверьте
docker compose psиdocker compose logs --tail=50 app. Если сервис ещё запускается, дождитесьhealthy; если он завершился, устраните ошибку из журнала и повторите запуск. - Резервный режим вместо AI: проверьте ключ, баланс, доступ к обеим моделям и сеть. После исправления используйте новый запрос либо намеренно сбросьте кеш; сохранённые резервные ответы не пересчитываются автоматически.
prepare:dataсообщает 401/403/429: проверьте ключ/права/лимиты у провайдера. Секреты в логи не выводятся.- 503 при подборе: проверьте наличие CSV и права записи в каталог кеша;
docker compose logs --tail=50 app. - Не собирается образ: проверьте доступ к npm/Docker Hub, повторите
docker compose build. Для первого запуска нужен интернет.
Авторы коммитов
История коммитов
- 2026-09-23 17:48Record successful production release and verificationkonstantin.volkov
- 2026-09-23 17:41Refresh project documentation and verification recordskonstantin.volkov
- 2026-09-23 17:21Add host selection chat and preserve results on reload (#2)Mikhail Mironov
- 2026-09-23 17:19Merge origin/main into host selection chat branchMikhail Mironov
- 2026-09-23 17:16Add host selection chat and preserve results on reloadMikhail Mironov
- 2026-09-23 17:07chore: remove unused code and consolidate project documentationkonstantin.volkov
- 2026-09-23 16:46Record successful production deployment and verificationkonstantin.volkov
- 2026-09-23 16:42Fix generic contractor explanations and record production regressionkonstantin.volkov
Все коммиты (22)
- 2026-09-23 16:15Add jury deployment guide, Railway evidence and brand faviconkonstantin.volkov
- 2026-09-23 15:48Merge branch 'main' of https://github.com/BAITC-Hacks/hack-875e970e-volga-productionkonstantin.volkov
- 2026-09-23 15:38final checkskonstantin.volkov
- 2026-09-23 15:34Merge pull request #1 from BAITC-Hacks/refactor/unified-form-componentsMikhail Mironov
- 2026-09-23 15:32Update session context for dataset relocationMikhail Mironov
- 2026-09-23 15:30Move catalog dataset into data directoryMikhail Mironov
- 2026-09-23 15:21futurekonstantin.volkov
- 2026-09-23 15:21Unify event form controls with MantineMikhail Mironov
- 2026-09-23 14:52change modelkonstantin.volkov
- 2026-09-23 14:47Merge branch 'main' of https://github.com/BAITC-Hacks/hack-875e970e-volga-productionkonstantin.volkov
- 2026-09-23 14:47Add spec-to-code compliance skillkonstantin.volkov
- 2026-09-23 14:45Fix distinct fallback explanations for contractor recommendationskonstantin.volkov
- 2026-09-23 14:21Edit READMEMikhail Mironov
- 2026-09-23 13:59first iterationkonstantin.volkov
Структура репозитория (238 файлов)
.agents/skills/frontend-design/SKILL.md .agents/skills/frontend-responsive-design-standards/SKILL.md .agents/skills/llm-council/SKILL.md .agents/skills/llm-council/references/architecture.md .agents/skills/llm-council/references/cli-notes.md .agents/skills/llm-council/references/data-contracts.md .agents/skills/llm-council/references/prompts.md .agents/skills/llm-council/references/schemas/council_plan.schema.json .agents/skills/llm-council/references/schemas/final_plan.schema.json .agents/skills/llm-council/references/schemas/judge_input.schema.json .agents/skills/llm-council/references/schemas/judge_output.schema.json .agents/skills/llm-council/references/schemas/task_spec.schema.json .agents/skills/llm-council/references/task-spec.example.json .agents/skills/llm-council/references/templates/judge.md .agents/skills/llm-council/references/templates/plan.md .agents/skills/llm-council/scripts/llm_council.py .agents/skills/llm-council/scripts/ui/app.js .agents/skills/llm-council/scripts/ui/index.html .agents/skills/llm-council/scripts/ui/styles.css .agents/skills/llm-council/scripts/ui_server.py .agents/skills/llm-council/scripts/ui_state.py .agents/skills/llm-council/setup.bat .agents/skills/llm-council/setup.ps1 .agents/skills/llm-council/setup.sh .agents/skills/markdown-url/SKILL.md .agents/skills/markdown-url/scripts/markdown-url.js .agents/skills/openai-docs-skill/SKILL.md .agents/skills/openai-docs-skill/scripts/openai-docs-mcp.sh .agents/skills/planner/SKILL.md .agents/skills/read-github/SKILL.md .agents/skills/read-github/scripts/gitmcp.py .agents/skills/spec-to-code-compliance/SKILL.md .agents/skills/spec-to-code-compliance/agents/openai.yaml .agents/skills/spec-to-code-compliance/assets/trail-of-bits-mark.svg .agents/skills/spec-to-code-compliance/resources/ANALYSIS_FORMAT.md .agents/skills/spec-to-code-compliance/resources/DIVERGENCE_RUBRIC.md .agents/skills/spec-to-code-compliance/resources/DOMAIN_NOTES.md .agents/skills/spec-to-code-compliance/resources/WORKED_EXAMPLE.md .agents/skills/ui-ux-pro-max/SKILL.md .agents/skills/ui-ux-pro-max/data/app-interface.csv .agents/skills/ui-ux-pro-max/data/catalog-summary.json .agents/skills/ui-ux-pro-max/data/charts.csv .agents/skills/ui-ux-pro-max/data/colors.csv .agents/skills/ui-ux-pro-max/data/data-provenance.json .agents/skills/ui-ux-pro-max/data/google-font-licenses.json .agents/skills/ui-ux-pro-max/data/google-fonts.csv .agents/skills/ui-ux-pro-max/data/icons.csv .agents/skills/ui-ux-pro-max/data/landing.csv .agents/skills/ui-ux-pro-max/data/motion.csv .agents/skills/ui-ux-pro-max/data/phosphor-icons-upstream.json .agents/skills/ui-ux-pro-max/data/products.csv .agents/skills/ui-ux-pro-max/data/react-performance.csv .agents/skills/ui-ux-pro-max/data/stacks/angular.csv .agents/skills/ui-ux-pro-max/data/stacks/astro.csv .agents/skills/ui-ux-pro-max/data/stacks/avalonia.csv .agents/skills/ui-ux-pro-max/data/stacks/flutter.csv .agents/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv .agents/skills/ui-ux-pro-max/data/stacks/javafx.csv .agents/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv .agents/skills/ui-ux-pro-max/data/stacks/laravel.csv .agents/skills/ui-ux-pro-max/data/stacks/nextjs.csv .agents/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv .agents/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv .agents/skills/ui-ux-pro-max/data/stacks/react-native.csv .agents/skills/ui-ux-pro-max/data/stacks/react.csv .agents/skills/ui-ux-pro-max/data/stacks/shadcn.csv .agents/skills/ui-ux-pro-max/data/stacks/svelte.csv .agents/skills/ui-ux-pro-max/data/stacks/swiftui.csv .agents/skills/ui-ux-pro-max/data/stacks/threejs.csv .agents/skills/ui-ux-pro-max/data/stacks/uno.csv .agents/skills/ui-ux-pro-max/data/stacks/uwp.csv .agents/skills/ui-ux-pro-max/data/stacks/vue.csv .agents/skills/ui-ux-pro-max/data/stacks/winui.csv .agents/skills/ui-ux-pro-max/data/stacks/wpf.csv .agents/skills/ui-ux-pro-max/data/styles.csv .agents/skills/ui-ux-pro-max/data/typography.csv .agents/skills/ui-ux-pro-max/data/ui-reasoning.csv .agents/skills/ui-ux-pro-max/data/ux-guidelines.csv .agents/skills/ui-ux-pro-max/references/pro-rules.md .agents/skills/ui-ux-pro-max/references/quick-reference.md .agents/skills/ui-ux-pro-max/scripts/core.py .agents/skills/ui-ux-pro-max/scripts/design_system.py .agents/skills/ui-ux-pro-max/scripts/reasoning_contract.py .agents/skills/ui-ux-pro-max/scripts/search.py .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-api.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-catalog.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-existing.csv .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-metadata.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-overrides.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/icons-curated.csv .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-core.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-package.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-react-exports.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-react-package.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-baseline.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-cases.json .agents/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-thresholds.json .agents/skills/ui-ux-pro-max/scripts/tests/test_catalog_refresh.py .agents/skills/ui-ux-pro-max/scripts/tests/test_catalog_summary_line_endings.py .agents/skills/ui-ux-pro-max/scripts/tests/test_core.py .agents/skills/ui-ux-pro-max/scripts/tests/test_core_data_quality.py .agents/skills/ui-ux-pro-max/scripts/tests/test_data_contracts.py .agents/skills/ui-ux-pro-max/scripts/tests/test_design_system_mode.py .agents/skills/ui-ux-pro-max/scripts/tests/test_design_system_stack.py .agents/skills/ui-ux-pro-max/scripts/tests/test_native_desktop_stack_freshness.py .agents/skills/ui-ux-pro-max/scripts/tests/test_relevance_evaluator.py .agents/skills/ui-ux-pro-max/scripts/tests/test_skill_script_paths.py .agents/skills/ui-ux-pro-max/scripts/tests/test_style_taxonomy.py .agents/skills/ui-ux-pro-max/scripts/tests/test_text_layout_resilience.py .agents/skills/ui-ux-pro-max/scripts/tests/test_web_stack_freshness.py .agents/skills/ui-ux-pro-max/scripts/validate_data.py .agents/skills/vercel-react-best-practices/AGENTS.md .agents/skills/vercel-react-best-practices/README.md .agents/skills/vercel-react-best-practices/SKILL.md .agents/skills/vercel-react-best-practices/rules/_sections.md .agents/skills/vercel-react-best-practices/rules/_template.md .agents/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md .agents/skills/vercel-react-best-practices/rules/advanced-use-latest.md .agents/skills/vercel-react-best-practices/rules/async-api-routes.md .agents/skills/vercel-react-best-practices/rules/async-defer-await.md .agents/skills/vercel-react-best-practices/rules/async-dependencies.md .agents/skills/vercel-react-best-practices/rules/async-parallel.md .agents/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md .agents/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md .agents/skills/vercel-react-best-practices/rules/bundle-conditional.md .agents/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md .agents/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md .agents/skills/vercel-react-best-practices/rules/bundle-preload.md .agents/skills/vercel-react-best-practices/rules/client-event-listeners.md .agents/skills/vercel-react-best-practices/rules/client-swr-dedup.md .agents/skills/vercel-react-best-practices/rules/js-batch-dom-css.md .agents/skills/vercel-react-best-practices/rules/js-cache-function-results.md .agents/skills/vercel-react-best-practices/rules/js-cache-property-access.md .agents/skills/vercel-react-best-practices/rules/js-cache-storage.md .agents/skills/vercel-react-best-practices/rules/js-combine-iterations.md .agents/skills/vercel-react-best-practices/rules/js-early-exit.md .agents/skills/vercel-react-best-practices/rules/js-hoist-regexp.md .agents/skills/vercel-react-best-practices/rules/js-index-maps.md .agents/skills/vercel-react-best-practices/rules/js-length-check-first.md .agents/skills/vercel-react-best-practices/rules/js-min-max-loop.md .agents/skills/vercel-react-best-practices/rules/js-set-map-lookups.md .agents/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md .agents/skills/vercel-react-best-practices/rules/rendering-activity.md .agents/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md .agents/skills/vercel-react-best-practices/rules/rendering-conditional-render.md .agents/skills/vercel-react-best-practices/rules/rendering-content-visibility.md .agents/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md .agents/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md .agents/skills/vercel-react-best-practices/rules/rendering-svg-precision.md .agents/skills/vercel-react-best-practices/rules/rerender-defer-reads.md .agents/skills/vercel-react-best-practices/rules/rerender-dependencies.md .agents/skills/vercel-react-best-practices/rules/rerender-derived-state.md .agents/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md .agents/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md .agents/skills/vercel-react-best-practices/rules/rerender-memo.md .agents/skills/vercel-react-best-practices/rules/rerender-transitions.md .agents/skills/vercel-react-best-practices/rules/server-after-nonblocking.md .agents/skills/vercel-react-best-practices/rules/server-cache-lru.md .agents/skills/vercel-react-best-practices/rules/server-cache-react.md .agents/skills/vercel-react-best-practices/rules/server-parallel-fetching.md .agents/skills/vercel-react-best-practices/rules/server-serialization.md .dockerignore .env.example .gitignore .railwayignore AGENTS.md Dockerfile README.md app/api/chat/route.ts app/api/health/route.ts app/api/recommendations/route.ts app/finder.tsx app/globals.css app/icon.svg app/layout.tsx app/page.tsx compose.yaml data/hackathon_dataset_anonymized.csv docs/audit-2026-09-23.md docs/case-requirements.md docs/concrete-explanations-fix.md docs/evidence/audit-2026-09-23/playwright.json docs/evidence/audit-2026-09-23/runtime.json docs/evidence/audit-2026-09-23/smoke.json docs/evidence/concrete-explanations-fix.json docs/evidence/concrete-explanations-production.json docs/evidence/railway-runtime.json docs/evidence/railway-smoke.json docs/evidence/regression-2026-09-23/api.json docs/evidence/regression-2026-09-23/chromium-mobile.png docs/evidence/regression-2026-09-23/existing-suite-375.png docs/evidence/regression-2026-09-23/exploration.json docs/evidence/regression-2026-09-23/firefox-mobile.png docs/evidence/regression-2026-09-23/webkit-keyboard.json docs/evidence/regression-2026-09-23/webkit-mobile.png docs/evidence/release-2026-09-23/deployment.json docs/evidence/release-2026-09-23/playwright.json docs/evidence/release-2026-09-23/smoke.json docs/evidence/runtime.json docs/evidence/selection-1440.png docs/evidence/selection-375.png docs/evidence/selection-main-1440.png docs/evidence/selection-main-375.png docs/evidence/smoke.json docs/frontend-components-refactor-session.md docs/hackathon-plan.md docs/host-selection-ai-chat-context.md docs/production-regression-2026-09-23.md docs/railway-deployment.md lib/ai.ts lib/cache.ts lib/catalog.ts lib/chat.ts lib/filter.ts lib/finder-session.ts lib/recommend.ts lib/types.ts next-env.d.ts next.config.ts package-lock.json package.json playwright.config.ts public/.gitkeep scripts/prepare.ts scripts/production-browser-regression.mjs scripts/production-exploration.mjs scripts/production-regression.ts scripts/smoke.ts scripts/verify-runtime.ts skills-lock.json spec-compliance/REPORT.md tests/browser/controls.spec.ts tests/browser/finder.spec.ts tests/browser/persistence.spec.ts tests/cache.test.ts tests/chat.test.ts tests/core.test.ts tsconfig.json
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.