О проекте
Команда: that-day-in
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Доведённый продукт
Задача кейса: «Аким на 5 часов»: городской симулятор, распределяющий бюджет по 5 направлениям и 5 районам
Суть
Игровой симулятор «Аким на 5 часов» на Next.js. Интерактивная SVG-карта Астаны, 14 мер и бюджет 100, серверный расчёт Score, AI-объяснение через Structured Outputs, рекомендации, события на карте, общий рейтинг в Redis и генерация презентации.
Как устроено
Районы, показатели, меры и правила загружаются из синтетического dataset.json. Общий расчётный модуль считает лаги, синергии, критические значения и Score = 0.7×среднее (по населению) + 0.3×минимум − число критических. Клиент передаёт только ID мер и районов, сервер проверяет всё через Zod и пересчитывает сам. Готовые факты уходят в OpenAI Responses API со Structured Outputs за объяснением и обоснованием рекомендаций (замена одной меры). Рейтинг хранится в Upstash Redis, участник определяется подписанной cookie.
Ключевые решения
- детерминированная модель Score
- OpenAI Structured Outputs
- Zod-контракты клиент/сервер
- замена одной меры
- события на карте с резервом бюджета
- лидерборд в Redis
- Markdown-презентация
- экспериментальный анализ отзывов
Особенности
Задеплоено на Vercel, есть общий рейтинг участников на Redis. SVG-карта Астаны собрана из сохранённой географии OSM. Интерфейс и сервер делят один расчётный модуль. В README заявлено 143 unit/API и 16 e2e-тестов без трат AI-токенов. Первый коммит сделан 22.09 вечером, это подготовка датасета.
Стек
TypeScript · Next.js 16 · React 19 · Node.js 22 · Tailwind CSS 4 · Zod 4 · OpenAI SDK · Upstash Redis · Vercel · Vitest · Playwright · Python · OpenStreetMap
Модели
gpt-5.4-mini-2026-03-17
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-e54d9694-that-day-in.
README
README.mdthat day
AI-симулятор городского управления «Аким на 5 часов». Проект помогает оценить, как решения при ограниченном бюджете влияют на районы Астаны и качество жизни жителей.
Открыть работающий сайт · Документация · Ветки и PR
Проблема и пользователи
Развитие города требует учитывать транспорт, экологию, социальную инфраструктуру, безопасность и сервисы при ограниченном бюджете. Приоритет одного направления может оставить без поддержки другой район.
Симулятор предназначен для городских управленцев, аналитиков и участников хакатона. Он позволяет сравнить варианты на синтетических данных и обосновать выбор. Игровая эстетика используется в интерфейсе; логика решений определяется датасетом.
Что реализовано
| Возможность | Как работает |
|---|---|
| Единый стартовый бюджет | Каждому участнику доступны собственные 100 виртуальных единиц. Расходы участников независимы |
| Решения по пяти направлениям | Каталог из 14 мероприятий: транспорт, экология, соцсфера, безопасность и сервисы. Можно выбрать район или городское мероприятие, изменить и удалить решение |
| Контроль допустимости | Проверяются бюджет, количество и уникальность мер, ограничения направлений и несовместимости. Сервер повторно проверяет отправленный сценарий |
| Интерактивная карта | Пять районов, достопримечательности, перемещение и масштаб. Выбор района приближает и выделяет его; «Весь город» возвращает общий вид |
| Изменения показателей | Справа от карты показаны 10 показателей района и его индекс до/после решений. Изменения сопровождаются короткими анимациями; в аналитике доступны диаграммы районов |
| Astana Quality of Life Score | Расчёт учитывает эффекты мер, задержки, синергии, доли населения и критические значения. AI не назначает баллы |
| AI-анализ | Структурированное объяснение сильных сторон, рисков и последствий со ссылками на факты расчёта |
| Рекомендации | До трёх допустимых вариантов замены одного мероприятия с приростом Score, расходами и AI-обоснованием. Вариант можно применить к плану |
| События на карте | Осадки, жара, сбой сервисов и ремонт улиц размещаются на районе или всём городе перетаскиванием либо кликом. До трёх событий одновременно; резерв уменьшает доступный бюджет, удаление возвращает средства |
| Перераспределение бюджета | Отдельный редактор сценария события позволяет заменить мероприятия и пересчитать план с учётом резерва. Есть случайный выбор события |
| Сравнение участников | Общий рейтинг через Redis: явная публикация с именем, личный лучший результат, равные места, выделение своей записи и страницы результатов |
| Краткая презентация | Просмотр и скачивание Markdown: 9 слайдов с AI, 6 расчётных/служебных слайдов при его недоступности |
| Сохранение и доступность | Черновик и последние отчёты сохраняются в браузере. Есть мобильная компоновка, управление картой/событиями с клавиатуры и поддержка уменьшенного движения |
Правила исходного датасета: ровно пять разных мероприятий, максимум два из одного направления, сумма не более 100. Покрытие всех пяти направлений не обязательно. Доступны пять районов и горизонт моделирования восемь кварталов.
Также реализован экспериментальный API анализа отзывов: сигналы с цитатами и ограниченный пересчёт показателей. Он не имеет отдельного экрана и исключён из рейтинга.
Как работает решение
- Приложение загружает районы, показатели, мероприятия и правила из синтетического JSON.
- На экране «Карта и решения» пользователь выбирает район и составляет план. Слева видны мероприятия и бюджет, в центре — карта, справа — показатели до/после.
- По желанию пользователь размещает учебные события и исследует их влияние. События карты учитываются в отдельном предварительном расчёте.
- «Рассчитать сценарий» открывает аналитику: сервер проверяет данные, пересчитывает основной план и передаёт готовые факты AI.
- Пользователь получает Score и объяснение, сравнивает районы, применяет рекомендацию, публикует результат или формирует презентацию.
События карты не включаются в AI-анализ и рейтинг основного плана. Это отдельный эксперимент; различие обозначено в интерфейсе.
Технологии
| Область | Используется в проекте |
|---|---|
| Приложение | TypeScript, Next.js 16, React 19, Node.js 22 |
| Интерфейс | CSS, Tailwind CSS 4, SVG-карта, Lucide React, шрифт Manrope |
| Контракты и валидация | Zod 4, общие схемы для клиента и сервера |
| AI | OpenAI SDK 6, Responses API, Structured Outputs. Модель по умолчанию — gpt-5.4-mini-2026-03-17; переопределяется через OPENAI_MODEL |
| Хранение | JSON в репозитории, браузерный localStorage, Upstash-совместимый Redis REST для рейтинга |
| Проверки | Vitest, Playwright, TypeScript, ESLint |
| Подготовка данных и карты | Скрипты Python, сохранённая география OpenStreetMap |
| Размещение | Vercel; публикация через CLI |
NVIDIA API в текущей реализации не используется.
Архитектура
JSON-датасет → общая расчётная модель → показатели, бюджет и Score
↑ ↓
Карта и план → API Next.js + проверка Zod → OpenAI → объяснение
↓
Redis → общий рейтинг
Клиент передаёт идентификаторы мер и районов, а не готовые цены или Score. Сервер проверяет версию каталога и рассчитывает результат самостоятельно. Для быстрого предварительного отображения интерфейс использует тот же расчётный модуль. Ключи OpenAI и Redis остаются на сервере.
Основные компоненты: src/components и src/features — интерфейс и состояние; src/app/api — серверные обработчики; src/lib — расчёты, AI и рейтинг; src/shared — контракты; dataset — входные данные.
Формула: Score = 0.7 × средний индекс города + 0.3 × минимальный индекс района − число критических значений. Средний индекс взвешен по населению; критическими считаются показатели строго ниже 40. Подробнее — модель расчёта.
Установка и запуск
Нужны Node.js 22 и npm. Репозиторий приватный: для клонирования требуется доступ к GitHub команды.
git clone https://github.com/BAITC-Hacks/hack-e54d9694-that-day-in.git
cd hack-e54d9694-that-day-in
git switch main
npm ci
npm run dev
Приложение откроется на http://localhost:3000. Карта, бюджет, Score и события работают без внешних ключей.
Для AI и общего рейтинга скопируйте .env.example в .env.local, если такого файла ещё нет, и заполните серверные переменные:
| Переменная | Для чего нужна |
|---|---|
OPENAI_API_KEY | AI-анализ, объяснения рекомендаций и презентации |
OPENAI_MODEL | Необязательный выбор модели |
UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN | Общее хранилище рейтинга |
PARTICIPANT_SECRET | Подпись cookie участника; не менее 32 случайных символов |
Вместо Upstash-пары поддерживается пара KV_REST_API_URL / KV_REST_API_TOKEN от Vercel Marketplace. Пары нельзя смешивать. Секреты не добавляются в Git и не используют префикс NEXT_PUBLIC_. После настройки перезапустите сервер.
Production-сборка: npm run build, затем npm run start.
Как проверить решение
Сценарий для жюри
- Откройте сайт без активных событий карты.
- Нажмите значок помощи в шапке → «Загрузить контрольный пример · 95 ед.».
- В плане появятся M7, M8, M10 в Нуре, M12 для всего города и M5 в Сарыарке. Посмотрите показатели выбранного района до/после.
- Нажмите «Рассчитать сценарий» и проверьте результат:
| Показатель | Ожидаемое значение |
|---|---|
| Расходы / остаток | 95 / 5 |
| Исходный Score | 52,55768 |
| Итоговый Score | 56,54307 — в интерфейсе 56,54 |
| Критических значений после мер | 0 |
- При доступном OpenAI появится объяснение сильных сторон, рисков и последствий. Затем можно открыть рекомендации, сформировать презентацию или явно опубликовать результат в рейтинге.
- Для проверки карты очистите план и удалите активные события. Разместите «Сильные осадки» на Нуре: резерв составит 10, показатель «Разгрузка дорог» изменится 55 → 51. Удалите событие — бюджет и показатели восстановятся.
Расширенный сценарий, включая перераспределение бюджета, — в инструкции демо.
Автоматические проверки
npm run typecheck
npm run lint
npm test
npx playwright install chromium
npm run test:e2e
npm run build
На интегрированной версии от 23.09.2026 проходят 143 unit/API-теста и 16 браузерных сценариев. Автотесты не расходуют AI-токены: платные AI-вызовы и внешний Redis подменяются в тестах; симуляция и события проверяются отдельно. Результаты настоящих проверок внешних сервисов зафиксированы в журнале публикации.
Данные и интеграции
- dataset/dataset.json — заранее подготовленные синтетические данные без реальных персональных данных. Районы, показатели, цены, задержки, синергии и ограничения описаны в датасете.
- OpenStreetMap — сохранённая география для карты. Внешний картографический API при использовании сайта не требуется. Источники и атрибуция ODbL — в документации карты.
- OpenAI — текстовое объяснение рассчитанных фактов через структурированные ответы. Версия датасета и ссылки на факты проверяются сервером.
- Redis — общее хранилище лучших результатов. Участник определяется подписанной cookie браузера.
- Vercel — размещение приложения и серверного API.
Ограничения
- Данные и эффекты событий синтетические; пять зон карты условные и не являются официальными административными границами. Результат не является прогнозом реального развития Астаны.
- Недоступность AI сохраняет численный результат, но текстовое объяснение отсутствует. Проверка структуры и ссылок на факты не гарантирует корректность каждой формулировки модели.
- Рекомендации ищут улучшения заменой одной меры и не гарантируют глобально лучший сценарий.
- События карты хранятся только в текущем сеансе страницы и исключены из стандартного AI-отчёта и рейтинга. Мероприятия считаются запланированными: частично выполненные проекты не моделируются.
- Полноценной авторизации нет. Другой браузер или очистка cookie создают нового участника; локальные черновики и отчёты не синхронизируются между устройствами. Без настроенного Redis общий рейтинг недоступен.
- Презентация экспортируется в Markdown; PPTX/PDF не реализованы. Для экспериментального API отзывов нет отдельного экрана.
Опубликованная версия и ветки
Демо: akim-five-hours.vercel.app. Код опубликованной сборки и выполненные проверки указаны в docs/deployment.md. Автодеплой GitHub → Vercel пока не подключён: push сам по себе сайт не обновляет.
main — основная версия для запуска и оценки. codex/ui и codex/map-studio — ветки интерфейса и карты; остальные codex/* сохраняют этапы backend и публикации. Названия и история сохранены. Точный статус включения каждой ветки и соответствующие PR — в карте репозитория.
Авторы коммитов
История коммитов
- 2026-09-23 17:50Restore colorful README banner with that day brandingaltynbek
- 2026-09-23 17:49Restore colorful README banner with that day brandingaltynbek
- 2026-09-23 17:46Improve readable typography, unify navigation and style presentation slidesBekzat Daulen
- 2026-09-23 17:44Rewrite that day README for hackathon judging and current featuresaltynbek
- 2026-09-23 17:41Merge pull request #7 from BAITC-Hacks/codex/map-studioAltynbek
- 2026-09-23 17:23Document deployed map studio and production checksBekzat Daulen
- 2026-09-23 17:23Merge remote-tracking branch 'origin/main' into codex/map-studioBekzat Daulen
- 2026-09-23 17:21Identify active map-studio work separately from integrated stagesaltynbek
Все коммиты (60)
- 2026-09-23 17:20Add centered map studio with district focus and draggable eventsBekzat Daulen
- 2026-09-23 17:20Merge remote-tracking branch 'origin/main' into codex/map-studioBekzat Daulen
- 2026-09-23 17:19Explain codex/deploy stage and link to main applicationaltynbek
- 2026-09-23 17:19Explain codex/scenario-features stage and link to main applicationaltynbek
- 2026-09-23 17:19Explain codex/resident-feedback stage and link to main applicationaltynbek
- 2026-09-23 17:19Explain codex/dataset-prep stage and link to main applicationaltynbek
- 2026-09-23 17:19Explain codex/contracts stage and link to main applicationaltynbek
- 2026-09-23 17:18Update README.mdBekzat Daulen
- 2026-09-23 17:18Merge pull request #3 from BAITC-Hacks/codex/uiAltynbek
- 2026-09-23 17:17Make main the canonical application branchaltynbek
- 2026-09-23 17:05Merge remote-tracking branch 'origin/main' into codex/uialtynbek
- 2026-09-23 17:05Present Akim simulator and document branches on repository homepagealtynbek
- 2026-09-23 17:04Document project for hackathon judges and map repository branchesaltynbek
- 2026-09-23 16:52Record updated UI release and verified scenario plus fixBekzat Daulen
- 2026-09-23 16:50Fix empty scenario plus buttons and verify desktop/mobile interactionsBekzat Daulen
- 2026-09-23 16:44Redesign city simulator and integrate scenario toolsaltynbek
- 2026-09-23 16:35Merge remote-tracking branch 'origin/codex/deploy' into codex/uialtynbek
- 2026-09-23 16:34Record public deployment checks and map performance diagnosisBekzat Daulen
- 2026-09-23 16:31Preserve nullable scenario fields across Redis leaderboard readsBekzat Daulen
- 2026-09-23 16:29Handle Upstash empty leaderboard JSON encodingBekzat Daulen
- 2026-09-23 16:27Support Vercel Marketplace Redis credentials in productionBekzat Daulen
- 2026-09-23 16:20Prepare integrated hackathon release for Vercel deploymentBekzat Daulen
- 2026-09-23 16:18Merge remote-tracking branch 'origin/codex/ui' into codex/deployBekzat Daulen
- 2026-09-23 16:16Merge remote-tracking branch 'origin/codex/scenario-features' into codex/uialtynbek
- 2026-09-23 16:04Document feature integration, live checks and Redis setupBekzat Daulen
- 2026-09-23 16:01Implement shared leaderboard API and live AI feature endpointsBekzat Daulen
- 2026-09-23 15:58Redesign simulator as guided city game with geographic Astana mapaltynbek
- 2026-09-23 15:50Add feature contracts and deterministic recommendations, events and slidesBekzat Daulen
- 2026-09-23 15:29Verify live review extraction and bounded city updatesBekzat Daulen
- 2026-09-23 15:26Add review-driven experimental city state projectionBekzat Daulen
- 2026-09-23 15:10Connect verified AI reports and document tested simulator designaltynbek
- 2026-09-23 15:09Merge remote-tracking branch 'origin/codex/dataset-prep' into codex/uialtynbek
- 2026-09-23 15:05Record compatibility with integrated scenario UIBekzat Daulen
- 2026-09-23 15:04Merge remote-tracking branch 'origin/codex/ui' into codex/dataset-prepBekzat Daulen
- 2026-09-23 15:03Verify production HTTP analysis and document backend handoffBekzat Daulen
- 2026-09-23 15:00Integrate backend simulation and explanation APIsaltynbek
- 2026-09-23 15:00Connect scenario planning to shared simulation and persist draftsaltynbek
- 2026-09-23 14:58Merge remote-tracking branch 'origin/codex/ui' into codex/dataset-prepBekzat Daulen
- 2026-09-23 14:58Add simulate and analyze APIs with grounded explanation-only OpenAIBekzat Daulen
- 2026-09-23 14:55Integrate authoritative dataset simulation and validationaltynbek
- 2026-09-23 14:54Build city simulator shell and interactive isometric designaltynbek
- 2026-09-23 14:53Use source dataset and implement lagged simulation with Score checksBekzat Daulen
- 2026-09-23 14:50Integrate contracts aligned with authoritative GitHub datasetaltynbek
- 2026-09-23 14:46Merge remote-tracking branch 'origin/codex/contracts' into codex/dataset-prepBekzat Daulen
- 2026-09-23 14:46Replace contracts with authoritative dataset rules and explanation-only AIBekzat Daulen
- 2026-09-23 14:34Record Node 22 verification and integration handoffBekzat Daulen
- 2026-09-23 14:33Verify catalog contracts and real structured-output model accessBekzat Daulen
- 2026-09-23 14:31Prepare fixed six-district catalog and model handoffBekzat Daulen
- 2026-09-23 14:26Define simulator contracts and explicit UI fixturesBekzat Daulen
- 2026-09-23 14:09Add structured city districts dataset and documentationBekzat Daulen
- 2026-09-23 10:21Delete .gitignoreAltynbek
- 2026-09-22 21:33Add gitignorealtynbek
Структура репозитория (113 файлов)
.env.example .github/pull_request_template.md .gitignore .nvmrc .vercelignore AGENTS.md CONTRIBUTING.md README.md build_dataset.py dataset/README.md dataset/dataset.json docs/README.md docs/ai.md docs/assets/map-studio-desktop.png docs/assets/map-studio-focused.png docs/assets/readme-banner.svg docs/demo.md docs/deployment.md docs/features.md docs/map-studio.md docs/map.md docs/model.md docs/repository.md docs/ui/choose-decision.png docs/ui/desktop.png docs/ui/mobile.png docs/ui/recommendations.png eslint.config.mjs next-env.d.ts next.config.ts package-lock.json package.json playwright.config.ts postcss.config.mjs public/maps/astana-source.json public/maps/astana.svg scripts/build-city-map.py src/app/api/_lib/analyze-handler.ts src/app/api/_lib/feature-input.ts src/app/api/_lib/feedback-handler.ts src/app/api/_lib/leaderboard-handler.ts src/app/api/_lib/presentation-handler.ts src/app/api/_lib/recommendations-handler.ts src/app/api/_lib/scenario.ts src/app/api/analyze/route.ts src/app/api/catalog/route.ts src/app/api/events/preview/route.ts src/app/api/events/route.ts src/app/api/events/simulate/route.ts src/app/api/feedback/recalculate/route.ts src/app/api/leaderboard/route.ts src/app/api/presentation/route.ts src/app/api/recommendations/route.ts src/app/api/simulate/route.ts src/app/globals.css src/app/layout.tsx src/app/page.tsx src/app/studio.css src/components/city-map.tsx src/components/city-workspace.tsx src/components/map-studio.tsx src/components/report-explanation.tsx src/components/scenario-tools.tsx src/data/control-scenarios.ts src/data/events.ts src/data/index.ts src/features/map/camera.ts src/features/map/geography.ts src/features/map/infrastructure.json src/features/map/use-playground.ts src/features/scenario-tools/client.ts src/features/simulator/use-report.ts src/features/simulator/use-scenario.ts src/lib/ai/analyze.ts src/lib/ai/evidence.ts src/lib/ai/prompt.ts src/lib/ai/recommendations.ts src/lib/ai/reviews.ts src/lib/competition/identity.ts src/lib/competition/store.ts src/lib/feedback/projection.ts src/lib/simulation/events.ts src/lib/simulation/index.ts src/lib/simulation/leaderboard.ts src/lib/simulation/map-events.ts src/lib/simulation/presentation.ts src/lib/simulation/recommendations.ts src/shared/contracts.ts src/shared/features-fixtures.ts src/shared/features.ts src/shared/feedback-fixtures.ts src/shared/feedback.ts src/shared/fixtures.ts tests/api/features-live-smoke.mjs tests/api/features.test.ts tests/api/feedback-live-smoke.mjs tests/api/feedback.test.ts tests/api/live-smoke.mjs tests/api/map-events.test.ts tests/api/routes.test.ts tests/e2e/workspace.spec.ts tests/unit/ai.test.ts tests/unit/catalog.test.ts tests/unit/competition.test.ts tests/unit/contracts.test.ts tests/unit/features.test.ts tests/unit/feedback.test.ts tests/unit/map-events.test.ts tests/unit/recommendation-ai.test.ts tests/unit/review-ai.test.ts tests/unit/simulation.test.ts tsconfig.json vitest.config.ts
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.