AAYMA
RU
Войти

Аким на 5 часов

Браузерный городской симулятор на Next.js: игрок выбирает район и мероприятия по 5 направлениям в пределах бюджета 100, детерминированная модель…

Рабочий MVP
Команда «VIP POLO» 6💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: 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-проверкой.

Демонстрация

  1. Выберите Северный район и по basic-мероприятию во всех пяти направлениях: расход 50, остаток 50, Score 51.67.
  2. Замените транспорт на premium: расход 70, Score 52.53. Верните basic и проверьте восстановление результата.
  3. Отмените мероприятие: завершение неполного плана недоступно. Верните решение.
  4. Завершите сценарий. Серверный результат показывается до окончания анализа. Просмотрите факты, городские показатели и раскрываемый trace.
  5. Без настройки AI увидите маркированный fallback. Повторите анализ, скачайте JSON, отредактируйте решения и начните новую игру.

Клавиатурный выбор района: Tab, затем Enter или пробел.

Учебная модель и контрольные примеры

Бюджет 100; три района; model-v1/synthetic-v1. Пять индексов 0..100, больше — лучше. Score — среднее 15 конечных показателей, только итог округляется до двух знаков. Начальный Score 50. Правила и исходные числа: контракт и src/data.

СценарийВыбор в northРасходРезультат
AВсе basic50Score 51.67
BКак A, transport-premium70Score 52.53
CВсе standard100Score 53.33
DВсе premium150BUDGET_EXCEEDED, HTTP 422
EA без service40Score 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, карта, общая страница и интеграцияРайон, замена/отмена и защита от старых ответов
2data, lib/simulation, api/simulateБюджет, воспроизводимый Score и trace
3lib/ai, features/results, api/analysisНастоящее объяснение, fallback, повтор и экспорт

Правила: AGENTS.md, владение, архитектура, среда, интеграция.

Исходные ветки участников сохраняются. Координатор соединяет конкретные SHA, обновляет общие проверки и документирует разрешение конфликтов. Для текущей интеграции Талгат разрешил merge через PR №6; без push прямо в main и force push. Инфраструктурный отказ GitHub Actions не заменяет результат проверок кода. Без успешного live-AI полная готовность не подтверждается.

Звёзды
⭐ 1
Форки
0
Язык
TypeScript
Последний push
в прошлом месяце
Коммиты
21
Авторы
4
Файлы
89
Ветки
7

Авторы коммитов

Talgat Gabituly 12suimentay 5Talgat 2kumchik666 2

История коммитов

  • 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
Ветки (7)

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.