О проекте
Команда: VIP POLO
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Рабочий MVP
Задача кейса: «Аким на 5 часов»: городской симулятор, распределяющий бюджет по 5 направлениям и 5 районам
Суть
Браузерный городской симулятор на Next.js: игрок выбирает район и мероприятия по 5 направлениям в пределах бюджета 100, детерминированная модель считает Quality of Life Score с trace, AI объясняет готовый расчёт; есть SVG-карта условного города.
Как устроено
Синтетические данные (config, districts, initiatives JSON) задают мероприятия уровней basic/standard/premium со стоимостью и влиянием на 5 индексов. Детерминированная модель v1 в /api/simulate считает Score как среднее 15 конечных показателей и проверяет бюджет (BUDGET_EXCEEDED, 422) и полноту сценария; финальный расчёт повторяется на сервере, клиентские значения не принимаются. /api/analysis передаёт факты расчёта в OpenAI Responses API (модель задаётся AI_MODEL), при отсутствии ключа, таймауте или невалидном ответе возвращается маркированный fallback. Результаты с фактами и trace экспортируются в JSON.
Ключевые решения
- детерминированная симуляционная модель
- серверная ревалидация сценария
- контрольные сценарии A–E
- AI-объяснение по фактам с fallback
Особенности
Контрактная разработка втроём: общий scaffold, раздельное владение модулями (симуляция / игра / AI), интеграция через PR с аудитом SHA; эталонные сценарии A–E с точными Score как фикстуры, 299 тестов и отдельный live-AI тест, который падает при fallback вместо фиктивного успеха.
Стек
TypeScript · Next.js · React · pnpm · Vitest · Playwright · GitHub Actions
Модели
OpenAI Responses API (модель не зафиксирована)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-12254b16-vip-polo.
README
README.mdАким на 5 часов
Браузерная учебная модель управления условным городом команды VIP POLO. Пять решений при бюджете 100 меняют Astana Quality of Life Score; AI объясняет готовый расчёт. Данные синтетические, районы условные, результат не является официальной оценкой Астаны или рекомендацией акимату.
Текущее состояние
Интеграционный кандидат feat/integration-audit, опубликованный в PR №6, соединяет расчётную модель PR №2, игровой интерфейс PR №3, AI и результаты PR №4, улучшения интерфейса и карты PR №5. Талгат разрешил объединение в main после проверки. Само наличие PR не подтверждает завершённый merge; фактический статус и SHA фиксируются в docs/integration.md.
Реализованы выбор, замена и отмена мероприятий, предварительный расчёт, серверная финальная проверка, результаты с фактами/trace, AI-адаптер, честный fallback, повтор анализа и JSON-экспорт. Оба API работают по контракту и не являются стартовыми заглушками 501.
Включена подробная SVG-карта из PR №5, коммит a29ff8c: кварталы, дороги, парки, река, набережная, мосты и условные ориентиры. Выбор трёх районов работает мышью и клавиатурой. Улицы и ориентиры придуманы; это схема без масштаба, а не географическая карта Астаны.
На общей версии с новой картой прошли lint, typecheck, 299 тестов и build. Полный Chromium-прогон ограничен песочницей macOS; настоящий AI ещё не подтверждён. Актуальные SHA, выполненные проверки и оставшиеся ограничения — в docs/integration.md. Исторические отчёты отдельных модулей не подтверждают готовность общей версии.
Установка и запуск
Нужны Node.js 24.19.0, pnpm 11.19.0, доступ к приватному репозиторию и npm. Версия Node закреплена в .node-version, pnpm — в packageManager. Установите их своим менеджером среды; пути компьютера автора не требуются.
После подтверждённого объединения PR №6 обычный запуск из main:
git clone https://github.com/BAITC-Hacks/hack-12254b16-vip-polo.git
cd hack-12254b16-vip-polo
git switch main
node --version
pnpm --version
pnpm install --frozen-lockfile
pnpm dev
Откройте http://localhost:3000. Для другого порта: pnpm dev --port 3001. Для проверки кандидата до merge в новом клоне вместо git switch main выполните git switch --track origin/feat/integration-audit. Существующую рабочую папку другой сессии не переключайте; каждый участник работает в своей копии.
Production-запуск:
pnpm build
pnpm start
Сборка не загружает внешние шрифты и не требует AI-ключа.
Проверки
pnpm lint
pnpm typecheck
pnpm test
pnpm build
pnpm exec playwright install chromium
pnpm test:e2e
На Linux для браузера может понадобиться pnpm exec playwright install --with-deps chromium. E2E сам запускает production-сервер на 127.0.0.1:3100; порт должен быть свободен. Не останавливайте чужой сервер. Конфигурация e2e очищает AI_PROVIDER, AI_MODEL и AI_API_KEY для своего сервера: обычный прогон проверяет честный fallback без обращения к платному провайдеру.
Обычные тесты проверяют схемы, данные, A–E, ID, модель, API, UI, состояния анализа и экспорт. Подстановки провайдера используются только в тестах и не доказывают доступность настоящего AI.
Отдельно, после настройки серверного окружения:
pnpm test:ai-live
Команда запускает tests/live-ai/vitest.config.ts. Требуется реальный ответ source=ai, status=ready; отсутствие настроек или fallback приводят к неуспешному live-тесту, а не к фиктивному успеху. Он не входит в обычный CI. Структурная проверка дополняется просмотром смысла реального ответа.
AI и секреты
Реализован серверный адаптер OpenAI Responses API. Конкретная модель задаётся через AI_MODEL: её доступность для ключа команды необходимо проверить, подтверждённая модель пока не заявлена.
Создайте локальный файл настроек, сохранив существующий, если он уже есть:
test -f .env.local || cp .env.example .env.local
В редакторе задайте AI_PROVIDER=openai, доступную AI_MODEL, AI_API_KEY и при необходимости AI_TIMEOUT_MS (по умолчанию 15000). .env.local игнорируется Git; live-конфигурация читает его автоматически. Не отправляйте секрет в чат, не выводите его в логи и не используйте NEXT_PUBLIC.
Без ключа или при ошибке настройки/провайдера приложение сохраняет расчёт и возвращает source=fallback, status=unavailable. Таймаут и неподходящий ответ имеют отдельные статусы timeout и invalid_response. Fallback явно обозначен в интерфейсе и не считается успешной live-проверкой.
Демонстрация
- Выберите Северный район и по basic-мероприятию во всех пяти направлениях: расход 50, остаток 50, Score 51.67.
- Замените транспорт на premium: расход 70, Score 52.53. Верните basic и проверьте восстановление результата.
- Отмените мероприятие: завершение неполного плана недоступно. Верните решение.
- Завершите сценарий. Серверный результат показывается до окончания анализа. Просмотрите факты, городские показатели и раскрываемый trace.
- Без настройки AI увидите маркированный fallback. Повторите анализ, скачайте JSON, отредактируйте решения и начните новую игру.
Клавиатурный выбор района: Tab, затем Enter или пробел.
Учебная модель и контрольные примеры
Бюджет 100; три района; model-v1/synthetic-v1. Пять индексов 0..100, больше — лучше. Score — среднее 15 конечных показателей, только итог округляется до двух знаков. Начальный Score 50. Правила и исходные числа: контракт и src/data.
| Сценарий | Выбор в north | Расход | Результат |
|---|---|---|---|
| A | Все basic | 50 | Score 51.67 |
| B | Как A, transport-premium | 70 | Score 52.53 |
| C | Все standard | 100 | Score 53.33 |
| D | Все premium | 150 | BUDGET_EXCEEDED, HTTP 422 |
| E | A без service | 40 | Score 51.33 в draft; final — INCOMPLETE_SCENARIO |
Fixtures используются только в тестах. Прямой проверочный запрос A к production-серверу:
node -e 'const fs = require("node:fs"); process.stdout.write(JSON.stringify(JSON.parse(fs.readFileSync("tests/fixtures/scenario-A.json", "utf8")).request))' |
curl -i http://localhost:3000/api/simulate -H 'Content-Type: application/json' --data-binary @-
Ожидается HTTP 200 и результат A. С тем же запросом /api/analysis возвращает HTTP 200 с серверным расчётом и AI либо маркированным fallback. Пустой объект у обоих маршрутов отклоняется с HTTP 400. Клиентские Score, стоимость и факты не принимаются; финальные сценарии проверяются сервером повторно.
Совместная работа
| Участник | Область | Собственная демонстрация |
|---|---|---|
| 1 — Талгат | features/game, карта, общая страница и интеграция | Район, замена/отмена и защита от старых ответов |
| 2 | data, lib/simulation, api/simulate | Бюджет, воспроизводимый Score и trace |
| 3 | lib/ai, features/results, api/analysis | Настоящее объяснение, fallback, повтор и экспорт |
Правила: AGENTS.md, владение, архитектура, среда, интеграция.
Исходные ветки участников сохраняются. Координатор соединяет конкретные SHA, обновляет общие проверки и документирует разрешение конфликтов. Для текущей интеграции Талгат разрешил merge через PR №6; без push прямо в main и force push. Инфраструктурный отказ GitHub Actions не заменяет результат проверок кода. Без успешного live-AI полная готовность не подтверждается.
Авторы коммитов
История коммитов
- 2026-09-23 17:07Merge pull request #6 from BAITC-Hacks/feat/integration-auditTalgat
- 2026-09-23 17:05docs: record verified release with detailed mapTalgat Gabituly
- 2026-09-23 17:04merge: include detailed city map and verify releaseTalgat Gabituly
- 2026-09-23 16:53docs: update final audit for current UI polishTalgat Gabituly
- 2026-09-23 16:52merge: include current UI polish and preserve results integrationTalgat Gabituly
- 2026-09-23 16:49feat(ui): add detailed districts, streets, parks and river landmarkssuimentay
- 2026-09-23 16:47docs: record integration audit evidence and remaining blockersTalgat Gabituly
- 2026-09-23 16:45merge: integrate UI polish and verify real module contractsTalgat Gabituly
Все коммиты (21)
- 2026-09-23 16:42fix(ui): preserve PR4 results and add accessible scenario tracesuimentay
- 2026-09-23 16:36merge: include simulation PR 2 for auditTalgat Gabituly
- 2026-09-23 16:36merge: include game UI PR 3 for auditTalgat Gabituly
- 2026-09-23 16:36merge: include AI PR 4 for auditTalgat Gabituly
- 2026-09-23 16:30fix(ai): support Next dev route types and announce loadingkumchik666
- 2026-09-23 16:24feat(ui): preview affordable choices and explain simulation resultssuimentay
- 2026-09-23 16:24fix(simulation): satisfy Next route request type checks after devsuimentay
- 2026-09-23 16:16feat(ai): verify scenario explanations and add results panelkumchik666
- 2026-09-23 15:37feat(game): add city planning interface and guarded scenario requestsTalgat Gabituly
- 2026-09-23 15:27feat(simulation): implement deterministic v1 model and validated APIsuimentay
- 2026-09-23 15:15Merge pull request #1 from BAITC-Hacks/chore/scaffoldTalgat
- 2026-09-23 14:57docs: record GitHub Actions billing blockerTalgat Gabituly
- 2026-09-23 14:54chore: add shared Next.js scaffold and team contractsTalgat Gabituly
Структура репозитория (89 файлов)
.env.example .github/workflows/ci.yml .gitignore .node-version AGENTS.md README.md docs/ai-analysis.md docs/architecture.md docs/contract.md docs/game-ui.md docs/integration.md docs/ownership.md docs/requirements.md docs/simulation.md docs/toolchain.md docs/ui-polish.md eslint.config.mjs next-env.d.ts next.config.ts package.json playwright.config.ts pnpm-lock.yaml pnpm-workspace.yaml scripts/ai-live.mjs src/app/api/analysis/route.ts src/app/api/simulate/route.ts src/app/globals.css src/app/layout.tsx src/app/page.tsx src/data/config.json src/data/districts.json src/data/initiatives.json src/features/game/CityMap.tsx src/features/game/GameShell.tsx src/features/game/InitiativePicker.tsx src/features/game/ScenarioTrace.tsx src/features/game/city-map.module.css src/features/game/game.module.css src/features/game/index.ts src/features/game/labels.ts src/features/game/trace.module.css src/features/game/useGame.ts src/features/results/ResultsPanel.tsx src/features/results/export.ts src/features/results/index.ts src/features/results/results.module.css src/lib/ai/explanation.ts src/lib/ai/facts.ts src/lib/ai/fallback.ts src/lib/ai/index.ts src/lib/ai/provider.ts src/lib/simulation/index.ts src/shared/constants.ts src/shared/not-implemented.ts src/shared/ports.ts src/shared/scenario-id.ts src/shared/schema.ts src/shared/types.ts tests/ai/analysis.test.ts tests/ai/route.test.ts tests/contracts/data-and-fixtures.test.ts tests/contracts/integrated-flow.test.ts tests/contracts/page.test.tsx tests/contracts/scaffold.test.ts tests/contracts/scenario-id.test.ts tests/contracts/schema.test.ts tests/e2e/scaffold.spec.ts tests/fixtures/index.ts tests/fixtures/scenario-A.json tests/fixtures/scenario-B.json tests/fixtures/scenario-C.json tests/fixtures/scenario-D.json tests/fixtures/scenario-E.json tests/game/city-map.test.tsx tests/game/interface.test.tsx tests/game/trace.test.tsx tests/game/useGame.test.tsx tests/live-ai/analysis.live.test.ts tests/live-ai/vitest.config.ts tests/results/ResultsPanel.test.tsx tests/results/panel.test.tsx tests/setup.ts tests/simulation/browser.test.ts tests/simulation/http-smoke.mjs tests/simulation/model.test.ts tests/simulation/route.test.ts tests/support/server-only.ts tsconfig.json vitest.config.ts
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.