NaviQ
Web и Android-приложение на Flutter, где бизнес превращает идею в карточку задачи с помощью уточняющих вопросов AI, публикует её, а студенческие…
О проекте
Команда: NavIQ
Кейс HackAlem.ai: Образование — AI Sana
Стадия: Рабочий MVP
Задача кейса: Challenge Hub: превратить задачу бизнеса в задание для студенческих команд
Суть
Web и Android-приложение на Flutter, где бизнес превращает идею в карточку задачи с помощью уточняющих вопросов AI, публикует её, а студенческие команды откликаются, и бизнес выбирает исполнителей.
Как устроено
Node.js/Express API с SQLite хранит задачи и отклики. По идее бизнеса OpenAI Responses API (gpt-4.1-mini) генерирует 3–5 уточняющих вопросов и структурированный черновик полей; предложенные факты сохраняются только при наличии соответствующего фрагмента в исходной идее, без ключа используются шаблонные вопросы. Эвристический рейтинг полноты карточки (100 баллов по 7 составляющим) определяет уровень и сортировку каталога. Команды ищут задачи и отправляют отклик, бизнес ставит selected/rejected.
Ключевые решения
- генерация уточняющих вопросов
- структурированный вывод LLM
- проверка фактов по исходному тексту
- эвристический рейтинг полноты карточки
- шаблонный fallback
Особенности
Одна кодовая база Flutter для Web и Android (в репозитории собранный APK); прозрачный рейтинг готовности карточки с объяснением баллов, AI не выставляет баллы и не выбирает команды.
Стек
Flutter · Dart · Android · Node.js · Express 5 · SQLite (better-sqlite3) · OpenAI Responses API
Модели
gpt-4.1-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-b0c2414c-naviq.
README
README.mdNaviQ — от идеи бизнеса до выбора студенческой команды
NaviQ помогает бизнесу превратить короткую идею в понятную задачу, а студенческим командам — найти проект и предложить решение. AI задаёт уточняющие вопросы, прозрачный рейтинг показывает готовность карточки, а бизнес самостоятельно публикует задачу и выбирает исполнителей.
Основной сценарий: идея → черновик → вопросы AI → редактируемая карточка → рейтинг → публикация → отклик команды → решение бизнеса.
Проект доступен в двух форматах: Web-версия и Android-приложение на общей кодовой базе Flutter. Оба клиента используют API на Node.js и общую базу SQLite.
Возможности
- Бизнес: создаёт задачи, отвечает на уточняющие вопросы, редактирует карточки, публикует их и принимает решения по откликам.
- Команда: просматривает каталог, ищет задачи по теме и уровню, отправляет идею решения, план и срок, отслеживает решение бизнеса.
- Рейтинг: показывает полноту карточки, объясняет начисленные баллы и определяет порядок задач в каталоге.
- Общие данные: Web и Android работают с одним API; задачи и отклики сохраняются между перезапусками.
Техническая спецификация
| Компонент | Реализация |
|---|---|
| Клиенты | Flutter / Dart, Web и Android |
| Версия приложения | 1.0.0+1 |
| Dart SDK | ^3.13.3 |
| HTTP-клиент | http ^1.6.0 |
| Сервер | Node.js, Express ^5.2.1 |
| Хранение | SQLite через better-sqlite3 ^13.0.3, режим WAL |
| AI | OpenAI Responses API, SDK openai ^7.23.0, модель по умолчанию gpt-4.1-mini |
| Обмен данными | HTTP API, JSON; ограничение тела запроса — 64 КБ |
| Android | Java / JVM 17; значения minSdk, targetSdk и compileSdk берутся из Flutter SDK |
| Проверки | node:test, flutter_test, Flutter analyzer |
Версии зависимостей указаны по манифестам проекта; точные разрешённые версии зафиксированы в pubspec.lock и server/package-lock.json.
Быстрый запуск
Нужны Node.js 20+ с npm, Flutter с Dart, совместимым с ^3.13.3, и Chrome. Исходный проект ориентирован на Flutter 3.47+.
1. Запустите сервер из корня проекта:
cd server
npm ci
Скопируйте server/.env.example в server/.env и задайте ключ:
PORT=3000
OPENAI_API_KEY=ваш_ключ
OPENAI_MODEL=gpt-4.1-mini
В том же терминале:
npm start
2. Запустите интерфейс в отдельном терминале из корня проекта:
flutter pub get
flutter run -d chrome --dart-define=API_BASE_URL=http://localhost:3000
Проверка API: http://localhost:3000/api/health. Поле ai.configured показывает наличие ключа, а не успешность обращения к AI.
Android-приложение
Подключите Android-устройство с включённой USB-отладкой или запустите Android Emulator. Сервер должен быть запущен и доступен устройству.
Для стандартного Android Emulator на компьютере с сервером:
flutter run -d <device-id> --dart-define=API_BASE_URL=http://10.0.2.2:3000
Идентификатор устройства можно узнать командой flutter devices. Для физического телефона укажите вместо 10.0.2.2 доступный телефону адрес компьютера с API, например его IP в общей Wi-Fi-сети. localhost на телефоне указывает на сам телефон.
Бизнес может работать в браузере, а команда — в Android-приложении, если они подключены к одному серверу. После действий на другом устройстве повторно откройте соответствующий раздел, чтобы загрузить актуальные данные: автоматическая синхронизация в реальном времени не реализована
Без ключа или при ошибке AI приложение использует резервные шаблонные вопросы и сообщает об этом в интерфейсе. Остальные функции доступны. Ключ хранится только на сервере; файл .env не нужно добавлять в репозиторий
Конфигурация
| Параметр | Где задаётся | Назначение / значение по умолчанию |
|---|---|---|
PORT | server/.env | Порт API, 3000 |
OPENAI_API_KEY | server/.env | Ключ для генерации вопросов; без него используются шаблоны |
OPENAI_MODEL | server/.env | Модель, gpt-4.1-mini |
OPENAI_BASE_URL | server/.env | Необязательный адрес API, например локального сервера для тестов |
API_BASE_URL | Flutter --dart-define | Адрес сервера, http://localhost:3000; задаётся при запуске или сборке |
Данные и правила работы
Карточка задачи
Задача хранит id, идентификатор владельца owner, исходную идею idea, статус, вопросы, ответы и даты создания и публикации. Редактируемое содержимое находится в объекте fields:
| Поле | Содержание |
|---|---|
title | Название задачи |
topic | Тема |
context | Текущая ситуация |
need | Потребность бизнеса |
users | Пользователи результата |
data | Доступные данные и материалы |
constraints | Сроки и ограничения |
outcome | Ожидаемый результат |
success | Критерии успеха |
contact | Контакт со стороны бизнеса |
format | Формат взаимодействия |
Все поля — строки. Сервер обрезает пробелы по краям и ограничивает каждое значение 3000 символами. При создании идея должна содержать минимум 10 символов; она записывается в context.
Статусы задачи: draft → published. Для публикации нужны непустые title и need, совпадающий owner и явное confirm: true. Изменение опубликованной карточки также требует подтверждения. Возврат в черновик и удаление через API не реализованы.
Ответы связаны с полями через question_fields. Рейтинг вычисляется из текущих полей при формировании ответа API, а не хранится отдельным значением в базе.
Отклик команды
Отклик содержит task_id, team_id, идею решения idea, план plan, срок timeline и необязательную ссылку prototype. Идея, план и срок проходят проверку на заполненность; ссылка должна начинаться с http:// или https://.
Одна команда может отправить один отклик на одну опубликованную задачу. Начальный статус решения — pending; бизнес меняет его на selected или rejected. Решение можно изменить позже, число выбранных команд не ограничено.
Каталог
Общий каталог возвращает только опубликованные задачи, включая задачи с низким баллом. Доступны фильтры по теме и уровню, поиск по названию, контексту и потребности. Сортировка — по убыванию рейтинга, при равенстве баллов — по убыванию id. Пагинация не реализована.
HTTP API
Все маршруты используют префикс /api. Тела запросов и ответы передаются в JSON; для POST и PUT нужен Content-Type: application/json.
| Метод | Маршрут | Назначение и параметры |
|---|---|---|
| GET | /health | Состояние API и конфигурация AI |
| GET | /profiles | Список бизнес-профилей и команд |
| GET | /tasks | Каталог; query: topic, level, search. С owner возвращает задачи владельца, включая черновики, вместо общего каталога |
| GET | /tasks/:id | Карточка с рейтингом и количеством откликов |
| POST | /tasks | Создание черновика: owner, idea |
| POST | /tasks/:id/questions | Генерация вопросов для черновика; ответ: {task, notice} |
| PUT | /tasks/:id | Сохранение: owner, fields, answers; для опубликованной задачи — confirm: true |
| POST | /tasks/:id/publish | Публикация: owner, confirm: true |
| GET | /tasks/:id/proposals | Отклики на задачу; query: owner |
| POST | /tasks/:id/proposals | Отправка отклика: team_id, idea, plan, timeline, необязательный prototype |
| GET | /teams/:id/proposals | Отклики команды с названиями задач |
| POST | /proposals/:id/decision | Решение бизнеса: owner, decision (selected или rejected) |
PUT /tasks/:id заменяет объект полей: передавайте весь fields, иначе пропущенные поля станут пустыми. Пропущенный массив answers сохраняется как пустой.
Успешное создание задачи или отклика возвращает 201; остальные успешные операции — 200. При ошибках бизнес-валидации API возвращает { "error": "описание" }: 400 — неверные данные или нет подтверждения, 403 — не совпадает владелец, 404 — объект не найден, 409 — конфликт состояния или повторный отклик. Необработанные ошибки возвращают 500.
Параметр owner служит проверкой выбранного профиля в MVP, а не механизмом аутентификации.
Как работает рейтинг
Рейтинг оценивает заполненность карточки. Он пересчитывается на сервере; AI не начисляет баллы и не выбирает команды.
| Составляющая | Баллы |
|---|---|
| Контекст и потребность | 20 |
| Данные и материалы | 20 |
| Ожидаемый результат | 15 |
| Измеримые критерии успеха | 15 |
| Ограничения | 10 |
| Пользователи | 10 |
| Контакт и формат взаимодействия | 10 |
| Всего | 100 |
Уровни: 0–39 — «Черновик», 40–69 — «Рабочая», 70–89 — «Готовая», 90–100 — «Приоритетная». Уровень «Черновик» обозначает полноту карточки и не равен статусу публикации: опубликованная задача с таким уровнем видна в каталоге.
Каждая составляющая даёт полный вес или 0. Пустые поля, слишком короткие ответы и ряд заполнителей вроде «не знаю» не учитываются. Критерий успеха дополнительно проверяется на признаки измеримости. Проверки эвристические: высокий балл не гарантирует содержательность текста или качество бизнес-идеи.
После сохранения рейтинг обновляется. Каталог сортируется по убыванию балла; низкий рейтинг не блокирует публикацию и отклики.
AI и контроль пользователя
- AI получает исходную идею и известные поля, возвращает 3–5 вопросов, привязку вопросов к полям и структурированный черновик через OpenAI Responses API.
- Непустые факты, предложенные AI для карточки, сохраняются только при наличии соответствующего фрагмента в исходной идее. Уже заполненные пользователем поля сохраняются
- Все поля доступны для ручного редактирования. Публикация и изменение опубликованной карточки требуют подтверждения.
- Бизнес может выбрать одну, несколько команд или не выбирать ни одной. Автоматического назначения нет.
Архитектура и проверки
| Файл | Назначение |
|---|---|
lib/main.dart | Интерфейс, роли, каталог, карточки и отклики |
lib/design.dart | Общие визуальные компоненты |
lib/api.dart | HTTP-клиент |
server/index.js | API, SQLite, AI и демоданные |
server/rating.js | Формула рейтинга |
server/flow.test.js | Проверки API-сценария и AI-контракта с имитацией ответа |
server/rating.test.js | Проверка расчёта баллов |
test/design_test.dart | Проверки визуальных компонентов |
Проверки сервера из папки server:
npm test
Проверки и сборка интерфейса из корня проекта:
flutter analyze
flutter test
flutter build web --dart-define=API_BASE_URL=http://localhost:3000
Для размещения Web-сборки замените API_BASE_URL на доступный браузеру HTTPS-адрес сервера. Сборка интерфейса сама по себе не размещает API.
SQLite создаётся автоматически в server/data/passport.sqlite. При первом запуске добавляются пять опубликованных задач, пять черновиков, пять команд и пять откликов. Данные сохраняются между перезапусками; демо-контакты вымышлены.
Границы MVP
- Профили и роли переключаются без регистрации. Это деморежим, а не полноценная авторизация; идентификатор владельца в запросе не подтверждает личность пользователя.
- Валидация рейтинга проверяет признаки заполненности, а не смысл каждого ответа.
- AI-тест использует имитацию ответа. Качество реальных вопросов и доступность модели проверяются отдельно с рабочим ключом.
- Загрузка файлов и чат не реализованы. Каталог содержит опубликованные задачи; неопубликованные черновики находятся в разделе задач бизнеса.
- Для работы между устройствами нужен общий доступный API; облачное размещение не входит в описанный локальный запуск.
Авторы коммитов
История коммитов
- 2026-09-23 17:59Update README.mdIgnis76
- 2026-09-23 17:59Update README.mdmask
- 2026-09-23 17:50Add files via uploadreoverall
- 2026-09-23 17:49Delete чат-джбт-работй.jpegreoverall
- 2026-09-23 17:48Add files via uploadreoverall
- 2026-09-23 17:43Update README.mdreoverall
- 2026-09-23 17:38Update README.mdmask
- 2026-09-23 16:50Add files via uploadmask
Все коммиты (20)
- 2026-09-23 16:49Build lightweight ARM64 Android APK and remove unused iconsCodex
- 2026-09-23 16:27Make NaviQ logo navigate home and rebuild Android demoCodex
- 2026-09-23 16:18Prepare signed NaviQ Android demo APK and build workflowCodex
- 2026-09-23 16:03Refine NaviQ with layered liquid glass designCodex
- 2026-09-23 15:48Connect task assistant to structured OpenAI responsesCodex
- 2026-09-23 15:36Rename product to NaviQCodex
- 2026-09-23 15:26Add colorful liquid glass visual system and design testsCodex
- 2026-09-23 15:06Redesign web experience with polished workspace UICodex
- 2026-09-23 14:48Update README.mdmask
- 2026-09-23 14:44Complete web MVP with catalog rating and proposalsCodex
- 2026-09-23 14:39Update README.mdIgnis76
- 2026-09-23 14:22Build stage-one task passport MVPCodex
Структура репозитория (54 файлов)
.gitignore .metadata NaviQ-1.0.2-arm64.apk README.md analysis_options.yaml android/.gitignore android/app/build.gradle.kts android/app/src/debug/AndroidManifest.xml android/app/src/main/AndroidManifest.xml android/app/src/main/kotlin/kz/naviq/app/MainActivity.kt android/app/src/main/res/drawable-v21/launch_background.xml android/app/src/main/res/drawable/launch_background.xml android/app/src/main/res/drawable/naviq_launcher.xml android/app/src/main/res/drawable/naviq_launcher_background.xml android/app/src/main/res/drawable/naviq_launcher_foreground.xml android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml android/app/src/main/res/mipmap-anydpi/ic_launcher.xml android/app/src/main/res/mipmap-hdpi/ic_launcher.png android/app/src/main/res/mipmap-mdpi/ic_launcher.png android/app/src/main/res/mipmap-xhdpi/ic_launcher.png android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png android/app/src/main/res/values-night/styles.xml android/app/src/main/res/values/styles.xml android/app/src/profile/AndroidManifest.xml android/build.gradle.kts android/gradle.properties android/gradle/wrapper/gradle-wrapper.properties android/settings.gradle.kts lib/api.dart lib/design.dart lib/main.dart pubspec.lock pubspec.yaml scripts/build-android.ps1 server/.env.example server/flow.test.js server/index.js server/package-lock.json server/package.json server/prompt.md server/rating.js server/rating.test.js test/design_test.dart test/home_navigation_test.dart web/favicon.png web/favicon.svg web/icons/Icon-192.png web/icons/Icon-512.png web/icons/Icon-maskable-192.png web/icons/Icon-maskable-512.png web/index.html web/manifest.json чат-джбт-работай.jpeg
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.