AI Sana Challenge Hub
Платформа Challenge Hub на Next.js: бизнес в трёхшаговом редакторе превращает описание проблемы в структурированную задачу с баллом полноты, команды…
О проекте
Команда: Jarvis Team
Кейс HackAlem.ai: Образование — AI Sana
Стадия: Рабочий MVP
Задача кейса: Challenge Hub: превратить задачу бизнеса в задание для студенческих команд
Суть
Платформа Challenge Hub на Next.js: бизнес в трёхшаговом редакторе превращает описание проблемы в структурированную задачу с баллом полноты, команды подают отклики, владелец выбирает исполнителя, после закрытия задачи ставит отзыв.
Как устроено
Бизнес вводит свободный текст. Серверный адаптер OpenAI со структурированным ответом и Zod-проверкой (или детерминированный демо-режим без ключа) задаёт уточняющие вопросы по одному и заполняет поля брифа. lib/readiness.ts считает полноту по явным правилам: проблема 20, результат 20, критерии успеха 20, данные 15, ограничения 10, сроки 10, навыки 5. Публикация возможна от 60/100 и при заполненных обязательных полях. Данные в Prisma/SQLite, сессии серверные, bcrypt, версионная защита от конфликтов (HTTP 409), транзакционный выбор одного исполнителя.
Ключевые решения
- structured output + Zod validation
- rule-based readiness scoring
- optimistic concurrency (version check)
- deterministic demo fallback
Особенности
Балл готовности не растёт от длины текста, а ответы вроде «не знаю» не засчитываются. Предположения AI показываются отдельно от сведений пользователя, ручные правки не перезаписываются при повторном анализе. При ошибке API демо-ответ не подставляется молча. Фото проверяются по содержимому и перекодируются в WebP без метаданных.
Стек
Next.js App Router · React · TypeScript · Tailwind CSS · shadcn/ui · Radix · Prisma · SQLite · Zod · OpenAI SDK · Vitest · Playwright
Модели
gpt-4.1-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-3a30acd2-jarvis-team.
README
README.mdAI Sana Challenge Hub
Задачи бизнеса. Решения команд.
Локальная платформа для бизнеса и студенческих команд. Бизнес описывает проблему, отвечает на несколько вопросов и публикует задачу. Команды предлагают решения, а владелец выбирает исполнителя. Основной язык — русский.
Что реализовано
- Простая верхняя навигация, крупный текст и адаптивная вёрстка. В каталоге сразу доступны поиск и отрасль; навыки и полнота описания находятся в дополнительных фильтрах. Фильтры сохраняются в URL.
- Регистрация, вход, выход, роли бизнеса и команды; серверные сессии в SQLite и пароли с bcrypt.
- Редактор из трёх шагов: «Опишите задачу» → «Уточните детали» → «Проверьте и опубликуйте». Вопросы показываются по одному; на последнем шаге обязательные поля сразу открыты для редактирования.
- Автосохранение, сохранение перед переходом по внутренней ссылке и защита от перезаписи изменений из другой вкладки. Ошибка публикации называет конкретное поле и переводит в него фокус.
- Сравнение с исходным текстом в раскрываемом блоке и объяснение оценки полноты описания.
- Локальный демонстрационный сценарий без ключа и отдельный серверный адаптер OpenAI со структурированным ответом и проверкой Zod.
- Кабинет бизнеса, профиль команды с участниками и портфолио, подача отклика, транзакционный выбор одного исполнителя и закрытие задачи.
- Публичный профиль команды со специализацией, опытом, участниками, фотографиями и примерами проектов; переход в него из отклика.
- Отзывы заказчиков с оценкой от 1 до 5. Оценить можно только выбранную команду после закрытия своей задачи; повторное сохранение обновляет отзыв, средняя оценка рассчитывается сервером.
- Серверные проверки роли и владельца, приватные черновики и отклики, уникальный отклик команды на задачу, ограничение запросов и защита мутаций по Origin.
Окружение
- Node.js 22 LTS и npm.
- Windows PowerShell, macOS или Linux; SQLite не требует отдельного сервера.
- Для браузерных проверок — Chromium, установленный Playwright.
Стек: Next.js App Router, React, TypeScript, Tailwind CSS, компоненты на основе shadcn/ui / Radix, Lucide, Prisma и SQLite, Zod, OpenAI SDK, Vitest и Playwright. Точные версии закреплены в package-lock.json.
Локальный запуск
Все команды выполняются из корня проекта.
npm ci
if (!(Test-Path .env)) { Copy-Item .env.example .env }
npm run db:generate
npm run db:push
npm run dev
В macOS/Linux вместо строки с Copy-Item используйте test -f .env || cp .env.example .env. Если .env уже существует, сохраните свои значения и не перезаписывайте файл.
Откройте http://127.0.0.1:3000. Адрес в браузере должен совпадать с APP_URL: значение используется для проверки Origin запросов. При смене порта обновите APP_URL и запустите, например, npm run dev -- --port 3001.
DATABASE_URL="file:./dev.db"
APP_URL="http://127.0.0.1:3000"
OPENAI_API_KEY=""
OPENAI_MODEL="gpt-4.1-mini"
База создаётся в prisma/dev.db. .env, файлы БД и артефакты тестов исключены из Git. Приложение сохраняет данные на сервере; localStorage не является хранилищем задач или сессий.
Для начала работы зарегистрируйте аккаунт бизнеса или команды. Если нужны готовые примеры и демоаккаунты, отдельно выполните npm run db:seed — особенности этой команды описаны ниже. Для обычной работы и автоматических проверок seed не требуется.
Для локального запуска собранного приложения:
npm run build
npm start
Демоданные и аккаунты
npm run db:seed — явное действие для локальной демонстрации. Команда создаёт 4 вымышленные компании, 4 команды с участниками, 8 опубликованных задач, 2 приватных черновика и 4 отклика. Демонстрационные организации и записи помечены соответствующим признаком в интерфейсе. Никакие партнёрства или реальные результаты использования не подразумеваются.
| Роль | Локальный демопароль | |
|---|---|---|
| Бизнес | [email protected] | SanaDemo2026! |
| Команда | [email protected] | SanaDemo2026! |
На странице входа кнопки «Демо: бизнес» и «Демо: команда» заполняют email и пароль. Затем нажмите «Войти». Эти аккаунты доступны после seed; кнопки сами их не создают.
Повторный seed использует фиксированные demo-ID, обновляет исходные примеры и не добавляет их дубликаты. Пользователей, зарегистрированных через приложение, он не удаляет. Повторный запуск сбрасывает статусы исходных демозадач и демооткликов; для повторяемой презентации используйте новые задачи. Не запускайте seed одновременно с демонстрацией.
В NODE_ENV=production или APP_ENV=production seed завершится ошибкой. Он не запускается автоматически при установке, сборке или старте приложения. Публично известный демопароль предназначен только для локальной демонстрации, не для развёрнутого сервиса.
Подключение настоящего ИИ
- Укажите свой
OPENAI_API_KEYв.env. - При необходимости измените
OPENAI_MODELна доступную вашему проекту модель с поддержкой структурированного ответа. - Перезапустите сервер. Редактор покажет режим OpenAI.
Ключ используется только на сервере. Не добавляйте префикс NEXT_PUBLIC_ и не коммитьте .env. Запросы к OpenAI могут тарифицироваться; для локальной бесплатной демонстрации оставьте ключ пустым.
Без ключа редактор явно показывает «Демонстрационный режим»: уточнения формируются локально по детерминированным правилам. Этот режим не является ответом внешней модели. Существующие ручные правки защищены от перезаписи при повторном анализе. Предположения и рекомендации показаны отдельно от сведений пользователя.
При ошибке реального API демонстрационный ответ не подставляется автоматически: интерфейс сообщает об ошибке, черновик остаётся в БД, доступны повторный запрос и ручное редактирование. В адаптере есть ограничение размера входа, тайм-аут и проверка схемы ответа; содержание задачи передаётся как пользовательские данные, а не системные инструкции.
Профили команд, фотографии и отзывы
Команда открывает «Моя команда» → «Профиль команды». Здесь можно описать специализацию и опыт, добавить участников, ссылки и до восьми проектов: название, кому помогли, выполненная работа и результат. Кнопка «Открыть профиль» показывает публичную страницу, которую заказчик увидит из отклика.
В разделе «Фото команды и проектов» можно загрузить до шести фотографий JPG, PNG или WebP по 4 МБ. Первое фото становится обложкой. Фото сохраняются после нажатия «Загрузить фото», текст — кнопкой «Сохранить профиль». Перед переходом или выходом изменения текста также сохраняются.
Изображения проверяются по содержимому, уменьшаются до 1800 px и преобразуются в WebP без исходных метаданных. Они хранятся в SQLite вместе с остальными данными. Резервная копия базы включает фотографии; каталог для внешних загрузок не нужен. Лимит исходного изображения — 16 мегапикселей.
Заказчик открывает «Посмотреть профиль» в отклике. После выбора команды и закрытия задачи появляется «Оценить работу команды». Отзыв виден всем; автор может изменить его, но не создать несколько оценок одной задачи. Чужие заказчики и сама команда не могут поставить оценку. До первого отзыва отображается «Пока нет оценок».
При обновлении существующей установки остановите сервер, сохраните резервную копию базы и выполните npm run db:push — новые поля и таблицы добавляются без seed и сброса задач.
Правила готовности
Серверная функция lib/readiness.ts рассчитывает балл по явным правилам. Длина текста сама по себе не добавляет баллы; заглушки вроде «не знаю» не засчитываются. Каждый раздел показывает вклад, правило и следующий шаг.
| Раздел | Полный балл | Частичный балл |
|---|---|---|
| Проблема | 20: процесс / участники и конкретная трудность | 10: только процесс или трудность |
| Ожидаемый результат | 20: действие и назначение результата | 10: направление без назначения |
| Критерии успеха | 20: метрика, число и метод / период проверки | 10: метрика без цели или проверки |
| Данные | 15: источник / состав и доступ, объём или период; либо отсутствие и план «кто, что, когда соберёт» | 7: источник или отсутствие без деталей |
| Ограничения | 10: конкретная граница; либо явно описано отсутствие ограничений | 5: область без границы |
| Сроки | 10: конкретная дата или длительность | 5: период / этап без длительности |
| Навыки | 5: минимум две компетенции из словаря MVP | 2: одна компетенция |
Отсутствие содержательных сведений даёт 0. Публикация требует не менее 60/100 и четырёх заполненных полей: «Название задачи», «Что нужно решить?», «Какое решение вы хотите получить?», «Что команда должна передать вам?». Эти поля всегда видны на шаге проверки. Блок перед публикацией перечисляет недостающие сведения; при попытке публикации редактор показывает конкретную ошибку и выделяет нужное поле. Публикация выполняется только кнопкой «Опубликовать задачу».
Рейтинг оценивает полноту брифа, не гарантирует качество или реализуемость проекта. Веса и порог — продуктовые настройки MVP, а не официальные правила конкурса. Правила используют ограниченный словарь и эвристики; сформулированный необычными словами содержательный ответ может потребовать уточнения.
Сохранение и работа в нескольких вкладках
После создания черновика изменения сохраняются автоматически после короткой паузы. Состояние видно над редактором: «Есть несохранённые изменения», «Сохраняется…», «Сохранено» или «Не удалось сохранить». На шаге проверки есть и кнопка «Сохранить».
Переход между шагами, по внутренней ссылке из редактора и выход из аккаунта дожидаются сохранения. Если запрос завершился ошибкой, редактор остаётся на странице, чтобы можно было повторить действие. При закрытии или перезагрузке вкладки с несохранёнными изменениями браузер предупреждает об уходе.
Сервер проверяет версию задачи: устаревшее сохранение отклоняется с HTTP 409 и кодом conflict. Интерфейс показывает «Задача уже изменилась», сохраняет локальный текст в полях и останавливает автосохранение и публикацию. Кнопка «Сохранить отдельным черновиком» создаёт новую задачу с вашими правками; актуальная версия исходной задачи остаётся нетронутой. Автоматического слияния изменений между вкладками нет.
Проверки
npm run typecheck
npm run lint
npm test
npm run build
npx playwright install chromium
npm run test:e2e
Если загрузка Chromium недоступна, можно использовать установленный Google Chrome. В PowerShell задайте $env:PLAYWRIGHT_CHANNEL="chrome" перед запуском тестов; в macOS/Linux — PLAYWRIGHT_CHANNEL=chrome npm run test:e2e.
Перед интеграционными тестами выполните db:generate и db:push. Playwright запускает dev-сервер или использует уже работающий по http://127.0.0.1:3000. Для тестов нужен демонстрационный режим с пустым OPENAI_API_KEY; управляемый Playwright сервер задаёт его сам. Если используете существующий сервер, проверьте его настройку. Другой локальный адрес задаётся переменной PLAYWRIGHT_BASE_URL и должен совпадать с APP_URL сервера.
API- и браузерные тесты создают собственные уникальные аккаунты и задачи и удаляют только данные своего запуска. Seed и вход в демоаккаунты им не нужны. Проверяются основной путь, сохранение описания и ручных изменений, точная ошибка обязательного поля, переход и выход из аккаунта сразу после ввода, конфликт двух вкладок, приватность, авторизация, CSRF, дубликаты откликов, закрытие задачи и конкурентный выбор исполнителя. Не направляйте тесты на production или общую базу с реальными данными.
После аварийного завершения процесса могут остаться аккаунты с адресами e2e-…@example.test или ui-…@example.test; штатное завершение очищает их. Отчёт Playwright находится в playwright-report/, трассы ошибок — в test-results/.
Для автоматической проверки восьми экранов на ширинах 1440, 1024 и 390 px при работающем локальном сервере выполните:
node scripts/visual-qa.mjs
Скрипт проверяет каталог, вход, страницу «Как это работает», создание задачи, вопрос, проверку описания, опубликованную задачу и кабинет. Он создаёт временный аккаунт и задачу, проходит редактор и удаляет только созданные им данные. Демозадачи не изменяются, seed не нужен. При аварийном завершении может остаться аккаунт visual-…@example.test. Локальный адрес можно передать аргументом: node scripts/visual-qa.mjs http://127.0.0.1:3000.
Результаты сохраняются в artifacts/screenshots/: 8 экранов × 3 ширины = 24 состояния, по обычному и полному снимку на каждое — 48 PNG, плюс report.json с измерением переполнения и ошибками браузера. На узком экране вкладки кабинета прокручиваются внутри своей строки, не расширяя страницу.
После обновления интерфейса прошли 37 модульных тестов, 8 API-тестов, 5 браузерных UI-тестов, проверка типов и lint без предупреждений. Браузерные тесты проверяют сохранение перед выходом из аккаунта, редактирование профиля команды, загрузку фото, переход из отклика и публикацию/редактирование отзыва. Профиль и его редактор дополнительно проверяются на трёх ширинах, снимки сохраняются как team-profile-* и team-editor-*. Автоматическая визуальная проверка всех 24 состояний не обнаружила горизонтального переполнения страницы или ошибок JavaScript. Production-сборка npm run build также прошла успешно; готовое приложение запускается командой npm start. Реальный OpenAI API не вызывался; ключ для локального запуска не нужен.
Сценарий выступления на 3–5 минут: DEMO.md.
Границы MVP
- Один владелец у компании и команды; участников редактирует владелец, приглашений и отдельных аккаунтов участников нет.
- Один выбранный исполнитель на задачу. После выбора или закрытия новые отклики запрещены. Закрытие не запускает платежи и не оформляет договор.
- Нет email-подтверждения, восстановления пароля, загрузки произвольных документов, чата, модерации и оповещений по почте. Загрузка фотографий команды поддерживается.
- SQLite и
prisma db pushвыбраны для воспроизводимого локального запуска. Для нескольких экземпляров сервера потребуется отдельная БД, миграции и соответствующая эксплуатационная настройка. - Сессии действуют 7 дней, cookie — HttpOnly / SameSite=Lax; Secure включается при HTTPS в
APP_URL. Для размещения в интернете необходим HTTPS и корректныйAPP_URL. - Ограничители запросов хранятся в БД: вход — 10 попыток на email и 100 общих за 15 минут; анализ — 15 на пользователя за 15 минут. Это базовая защита MVP.
- Внешний OpenAI без ключа не вызывается; качество реальных ответов зависит от выбранной модели. Детерминированные тесты используют локальный режим.
- Конфликты нескольких вкладок обнаруживаются по версии задачи; свои правки можно сохранить отдельным черновиком. Совместного редактирования в реальном времени и автоматического слияния нет.
- Демоорганизации, команды, данные и описанные показатели полностью вымышлены.
Авторы коммитов
История коммитов
- 2026-09-23 17:32Merge branch 'main' of https://github.com/BAITC-Hacks/hack-3a30acd2-jarvis-teamdaikipeek
- 2026-09-23 17:31Добавлен сайт AI Sanadaikipeek
- 2026-09-23 17:26Удалить файлы из репозиторияkantayevr
- 2026-09-23 16:12feat: third commitkantayevr
- 2026-09-23 15:06feat: second commitkantayevr
- 2026-09-23 14:19First commit: add project from Dekstopkantayevr
Структура репозитория (76 файлов)
.env.example .gitignore AGENTS.md CLAUDE.md DEMO.md README.md app/api/_shared.ts app/api/auth/route.ts app/api/challenges/[id]/analyze/route.ts app/api/challenges/[id]/applications/route.ts app/api/challenges/[id]/close/route.ts app/api/challenges/[id]/publish/route.ts app/api/challenges/[id]/route.ts app/api/challenges/[id]/select/route.ts app/api/challenges/route.ts app/api/dashboard/route.ts app/api/team/photos/[id]/route.ts app/api/team/photos/route.ts app/api/team/route.ts app/api/teams/[id]/reviews/route.ts app/api/teams/[id]/route.ts app/challenges/[id]/edit/page.tsx app/challenges/[id]/page.tsx app/challenges/new/page.tsx app/dashboard/page.tsx app/error.tsx app/globals.css app/how-it-works/page.tsx app/icon.svg app/layout.tsx app/login/page.tsx app/not-found.tsx app/page.tsx app/teams/[id]/page.tsx components.json components/auth-form.tsx components/catalog.tsx components/challenge-detail.tsx components/dashboard.tsx components/editor.tsx components/readiness-panel.tsx components/shell.tsx components/team-profile-editor.tsx components/team-profile.tsx components/ui/button.tsx eslint.config.mjs lib/ai.ts lib/auth.ts lib/brief.ts lib/client.ts lib/db.ts lib/editor-copy.ts lib/http.ts lib/publication.ts lib/readiness.ts lib/team-profile.ts lib/team-server.ts lib/utils.ts next-env.d.ts next.config.ts package-lock.json package.json playwright.config.ts postcss.config.mjs prisma/schema.prisma prisma/seed.ts scripts/visual-qa.mjs tests/ai.test.ts tests/e2e/api.spec.ts tests/e2e/team-api.spec.ts tests/e2e/team-ui.spec.ts tests/e2e/ui.spec.ts tests/publication.test.ts tests/readiness.test.ts tsconfig.json vitest.config.ts
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.