AAYMA
RU
Войти

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

Веб-симулятор распределения городского бюджета: пользователь выбирает 5 мер по районам и получает объяснимый индекс качества жизни с лагами…

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

О проекте

Команда: nerds
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Рабочий MVP

Задача кейса: «Аким на 5 часов»: городской симулятор, распределяющий бюджет по 5 направлениям и 5 районам

Суть

Веб-симулятор распределения городского бюджета: пользователь выбирает 5 мер по районам и получает объяснимый индекс качества жизни с лагами, синергиями и ограничениями совместимости.

Как устроено

Встроенный набор данных: 5 районов, 10 показателей, 14 мер, 70 строк эффектов. Клиентский JS-движок считает новые показатели как clip(исходный + Σ эффект×(8−лаг)/8 + синергии), индекс района взвешенной суммой, итоговый Score = 0.7×средний индекс по населению + 0.3×худший район − число критических показателей; проверяет бюджет и несовместимые пары мер. Next.js + PostgreSQL отвечают только за регистрацию и сессии, сценарии хранятся в localStorage; AI не реализован.

Ключевые решения

  • deterministic scoring formula
  • lag coefficients
  • synergy/incompatibility rules
  • population-weighted index

Особенности

Прозрачная формула Score с учётом худшего района и штрафом за критические показатели; README открыто перечисляет, что не реализовано (серверный Score, обязательный охват 5 направлений, генеративный AI). Из минусов: в репозитории лежат ZIP-архивы исходников.

Стек

Next.js · React · Node.js · PostgreSQL · pg · JavaScript · Netlify OpenNext · Docker


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-7e132a35-nerds.

README

README.md

«Аким на 5 часов» — симулятор городских решений

Веб-приложение для учебного распределения бюджета между городскими инициативами. Пользователь регистрируется, выбирает пять мероприятий, задаёт районы и получает объяснимый индекс качества жизни с изменениями показателей, лагами, синергиями и ограничениями совместимости.

Этот README относится именно к архиву akim-server-deploy-netlify.zip. Здесь есть серверная авторизация, но расчёт сценариев выполняется в браузере. Генеративный AI и серверное хранение сценариев в этой версии не реализованы. Возможности из других архивов проекта сюда автоматически не перенесены.

Возможности и границы реализации

ВозможностьТекущее состояние
Регистрация, вход, выход, сессииNext.js API + PostgreSQL
Стартовый бюджет100 условных единиц во встроенном наборе
Данные5 районов, 10 показателей, 14 мер, 70 строк эффектов
Итоговый планРовно 5 мер, каждую можно выбрать только один раз; не более 2 мер одного направления
Контроль бюджета и совместимостиВ интерфейсе и клиентском движке
Расчёт индекса и разбор результатаДетерминированная формула, без AI
Сохранение сценариевlocalStorage, отдельно для аккаунта и браузера; последние 10 версий
Перенос сценарияЭкспорт / импорт JSON; импорт данных JSON, CSV, XLSX
Общий утверждённый набор и серверный ScoreНе реализованы
Обязательный охват всех пяти направленийНе проверяется: допустим план с 4 направлениями
Администрирование импортируемых данныхНадпись «Режим организатора» не ограничивает импорт; участник тоже может менять локальный набор

Проект полезен как объяснимый учебный симулятор. Для защищённого соревнования и полного соответствия исходному заданию нужны общий серверный набор, проверка/сохранение результатов на сервере и настоящий AI-анализ. Предлагаемый порядок развития — в конце README.

Технологии и архитектура

  • Next.js 16.3.6 / React: страница входа и личный кабинет.
  • Node.js / pg / PostgreSQL: авторизация и хранение сессий.
  • HTML/CSS/JavaScript: защищённый симулятор, открываемый в iframe.
  • Netlify OpenNext: целевая платформа выполнения серверных маршрутов.

Зафиксированные pnpm-lock.yaml версии: React и React DOM 19.3.0, pg 8.23.0. В package.json для этих библиотек заданы диапазоны; воспроизводимая установка требует --frozen-lockfile.

flowchart LR
  U[Браузер] --> N[Next.js: вход и API]
  N --> P[(PostgreSQL: пользователи и сессии)]
  N --> S[Защищённый HTML симулятора]
  S --> M[Клиентская модель: бюджет и Score]
  M --> L[(localStorage: сценарии)]

Индекс не поступает на сервер для верификации. Резервная копия PostgreSQL не содержит пользовательские сценарии.

Быстрый локальный запуск

Нужны Node.js 24, pnpm 11.19.0 и доступная PostgreSQL. engines допускает Node 22.12+, но эта поставка проверена на Node 24.19.0. Docker-конфигурация использует PostgreSQL 16; нативная проверка выполнена на PostgreSQL 17.10.

Все команды выполняйте из папки с package.json:

npm install --global [email protected]
pnpm install --frozen-lockfile

Создайте отдельную пустую базу PostgreSQL и пользователя с правами создавать таблицы в ней. Скопируйте .env.example в .env.local и заполните:

APP_ORIGIN=http://localhost:3000
ALLOW_HTTP_LOCALHOST=true
DATABASE_URL=postgresql://USER:[email protected]:5432/akim
ALLOW_REGISTRATION=true
SESSION_HOURS=12
PG_POOL_MAX=1

USER, PASSWORD и akim замените своими значениями. Зарезервированные символы пароля в URL нужно кодировать. Реальные настройки не добавляйте в Git.

pnpm db:init
pnpm test:model
pnpm build
pnpm start

Откройте http://localhost:3000, зарегистрируйтесь и войдите. Предустановленного аккаунта нет. Пароль пользователя — 12–128 символов; логин — 3–40 латинских букв, цифр, точек, дефисов или подчёркиваний. Для разработки вместо сборки и запуска можно выполнить pnpm dev.

Важно открывать именно origin из APP_ORIGIN: localhost и 127.0.0.1 считаются разными адресами. При смене порта поменяйте также APP_ORIGIN.

Развёртывание на Netlify

Нужна внешняя PostgreSQL: Netlify не запускает базу из compose.yaml. Проект должен собираться из распакованных исходников в GitHub, а не из лежащего в репозитории ZIP. Netlify Drop со статическими файлами не заменяет серверные API.

  1. Создайте PostgreSQL и выполните db/001_auth.sql пользователем, имеющим право создавать таблицы. На Netlify миграция при сборке автоматически не запускается.
  2. Выдайте серверной роли приложения права SELECT, INSERT, UPDATE, DELETE на users, sessions, auth_limits, а также CONNECT на базу и USAGE на схему. Для создания таблиц используйте отдельный административный доступ.
  3. Подключите репозиторий к Netlify и выберите ветку с этой версией.
  4. Укажите Base directory: папку, где лежат package.json и netlify.toml. Если они в корне репозитория, оставьте поле пустым. Если проект в akim-server-deploy-netlify/, укажите эту папку.
  5. Build command: pnpm build; Publish directory: .next. В netlify.toml заданы Node 24 и PNPM_FLAGS=--shamefully-hoist; pnpm зафиксирован в package.json.
  6. Добавьте переменные из таблицы ниже в Netlify UI, с доступом для Functions, и выполните Deploy.
  7. Проверьте /api/health, затем регистрацию, вход, загрузку /simulator, оценку сценария и выход.
ПеременнаяЗначение / назначение
DATABASE_URLСекретная строка подключения к внешней PostgreSQL с SSL по требованиям провайдера
APP_ORIGINТочный адрес, например https://YOUR-SITE.netlify.app, без / в конце
ALLOW_REGISTRATIONtrue для самостоятельной регистрации; false для выдачи аккаунтов организатором
SESSION_HOURS12; допустимо 1–168 часов
PG_POOL_MAX1 для serverless; код допускает 1–10
ALLOW_HTTP_LOCALHOSTДля публичного HTTPS-сайта не требуется; оставьте false

Для Supabase рекомендуемый вариант для serverless — Transaction pooler, порт 6543. Скопируйте адрес из панели Connect; для пользовательской роли логин имеет вид ROLE.PROJECT_REF. В приложении нет именованных prepared statements. Не используйте localhost или Docker-имя db в Netlify. Для миграций, бэкапов и тестов с search_path используйте прямое подключение либо подходящее session-подключение, а не transaction pooler.

После смены домена обновите APP_ORIGIN и разверните приложение повторно. Deploy Preview с другим доменом также требует своего APP_ORIGIN и, желательно, отдельной тестовой базы. Секреты не должны иметь префикс NEXT_PUBLIC_.

Полная инструкция: NETLIFY-QUICKSTART.md. Конфигурация сверена с Netlify Next.js, требованиями pnpm и Supabase connections. Реальный deploy в аккаунт Netlify в ходе проверки не выполнялся.

Воспроизводимый демонстрационный сценарий

Начните с встроенного набора, без импорта. Стартовый Score: 52,55768 (на экране 52,56).

В матрице нажмите ячейку нужного района, затем «Включить»:

КодМераРайонСтоимость
M7Школа + детсадНура24
M8Центр семейного здоровья / поликлиникаНура20
M10Освещение и камерыНура12
M12Единая цифровая платформа обращенийВесь город14
M5Перевод частного сектора на чистое топливоСарыарка25
Итого95

Нажмите «Оценить сценарий». Ожидаемые значения с округлением:

  • Score: 56,54; остаток бюджета: 5.
  • Средний индекс: 58,08; худший район: 52,96.
  • Критических показателей: 0 вместо 2.
  • Синергия M10 + M12 в Нуре: B1 +2.

Это пример текущих правил: он охватывает четыре направления, без транспорта. Не выдавайте этот тест за доказательство обязательного охвата всех пяти направлений.

Откройте результаты по районам, скачайте JSON и перезагрузите страницу: сценарий должен восстановиться в том же браузере. На другом компьютере для переноса понадобится экспортированный файл.

Методика расчёта

Десять показателей T1…C2 находятся в диапазоне 0–100; больше — лучше. Доли населения районов суммируются до 1. Данные в simulator/model.js — учебные допущения, не подтверждённая статистика города; название набора «HackAlem» в коде само по себе не подтверждает происхождение данных.

Горизонт — 8 кварталов; для меры с лагом L коэффициент эффекта r=(8−L)/8.

Новый показатель = clip(исходный + Σ(эффект × r) + Σсинергий, 0, 100)
Индекс района D = Σ(показатель × вес)
Средний индекс Davg = Σ(D × доля населения)
Score = clip(0.7 × Davg + 0.3 × min(D) − Ncrit, 0, 100)

Ncrit — число пар «район × показатель» со значением строго ниже 40. Ограничение шкалы применяется после суммирования эффектов. Веса T1…C2: 0.10, 0.10, 0.09, 0.11, 0.11, 0.11, 0.09, 0.09, 0.10, 0.10. Синергии фиксированы и не умножаются на лаг. Округление — только при отображении.

Синергии: M1+M2 → T1+2; M10+M12 → B1+2; M5+M6 → E2+2 в каждом районе совместного действия. Несовместимости: M1+M3 везде; M4+M7 в одном районе; M5+M13 в одном районе. Городская мера оплачивается один раз. Нельзя повторить одно мероприятие в другом районе, чтобы считать его отдельным решением.

Показатель можно называть учебным Astana Quality of Life Score; текущий интерфейс использует подпись «Итоговый балл города». Это авторская формула, не официальный индекс. Реальные сроки, эксплуатационные затраты и статистическая неопределённость полноценно не моделируются.

Тесты и проверка

pnpm test:model       # модель; база не нужна
pnpm test            # 12 проверок авторизации на PostgreSQL
pnpm test:snapshot   # восстановление синтетических данных в отдельной схеме
pnpm test:http       # требуется запущенный сервер и ALLOW_REGISTRATION=true
pnpm build           # production-сборка

Для тестов используйте отдельную тестовую PostgreSQL в .env.local. Тестовой роли нужны права создавать схемы; ограниченная production-роль для этого не подходит. test и test:snapshot создают и удаляют только свои временные схемы; HTTP-тест создаёт и удаляет временного пользователя. Восстановление тестируется на синтетических данных и не требует приватного файла бэкапа.

Результаты проверки именно этого архива: VERIFICATION.md. Локальная сборка, модель, PostgreSQL-тесты, HTTP и пользовательский сценарий проверены. Docker, Windows-скрипты, внешняя Supabase и настоящий Netlify runtime отдельно не запускались.

Авторизация, API и данные

МетодМаршрутНазначение
GET/api/auth/configДоступность регистрации
POST/api/auth/register{login,password,name}; создаётся только participant
POST/api/auth/loginВход и установка cookie
POST/api/auth/logoutУдаление сессии
GET/api/meТекущий пользователь; без сессии 401
GET/api/healthПроверка подключения и чтения трёх таблиц авторизации
GET/simulatorHTML симулятора после проверки сессии
GET/simulator/app.js, /simulator/model.jsЗащищённые ресурсы

POST авторизации проверяет Origin. Пароли хешируются scrypt. Сервер хранит SHA-256 хеш токена сессии; cookie имеет HttpOnly, SameSite=Strict и Secure при HTTPS. Есть ограничения частоты регистрации и попыток входа. SQL-запросы параметризованы. Регистрация не позволяет повысить роль через JSON.

Таблицы: users, sessions, auth_limits. Таблиц для наборов и сценариев нет. Роль admin можно создать через pnpm user:create, задав NEW_USER_LOGIN, NEW_USER_PASSWORD, NEW_USER_NAME, NEW_USER_ROLE=admin; это не добавляет отсутствующую серверную защиту импорта.

Docker, сервер и резервные копии

Локальный Docker-вариант:

node scripts/review.mjs 3000

Скрипт создаёт .review.env со случайными паролями и запускает Compose. Требуется установленный Docker с Linux-контейнерами. PostgreSQL хранится в именованном томе; останавливайте docker compose --env-file .review.env down без -v, если нужно сохранить данные.

compose.server.yaml и Caddy предназначены для отдельного VPS, не для Netlify. deploy.sh требует заранее подготовленный .server.env с DOMAIN, POSTGRES_PASSWORD, APP_DB_PASSWORD, ALLOW_REGISTRATION; файл не включён в поставку. Для Netlify эти скрипты не запускайте.

scripts/export-snapshot.mjs экспортирует авторизацию в backup/database.json; restore-snapshot.mjs отказывается перезаписывать непустую базу. Резервные копии содержат пользовательские записи и данные сессий — храните их приватно, вне Git. Симуляционные планы нужно экспортировать отдельно через интерфейс.

Структура

app/                 вход, кабинет, API, выдача симулятора
lib/                 PostgreSQL, авторизация, HTTP-защита
simulator/           интерфейс, расчёт и встроенный набор
db/                  схема авторизации и Docker-инициализация
scripts/             миграции, пользователи, запуск и бэкапы
tests/               модель, авторизация, HTTP, восстановление
netlify.toml         настройки сборки Netlify
next.config.mjs      заголовки и включение файлов симулятора
Dockerfile           альтернативная контейнерная сборка

Типичные ошибки

  • 503 на health / сервис входа недоступен: проверить подключение, SSL, три таблицы и права серверной роли.
  • 403 при входе: APP_ORIGIN не совпадает с адресом браузера; проверьте HTTPS, порт и отсутствие завершающего /.
  • 404 / не загружается симулятор: нужен полный Next.js deploy; проверьте Base directory и inclusion файлов simulator в функции.
  • 429: достигнут лимит попыток; подождите 15 минут.
  • План исчез на другом устройстве: он хранится в localStorage; используйте экспорт JSON.
  • Ошибка импорта: набор должен содержать шесть листов, включая «Ограничения»; доли населения должны давать 1. XLSX требует доступа к CDN.

Приоритеты дальнейшей работы

  1. Подключить настоящий серверный AI-разбор, сохранив детерминированный расчёт балла.
  2. Закрепить общий набор и бюджет на сервере; проверять права организатора.
  3. Сохранять и пересчитывать сценарии в PostgreSQL, не доверять клиентскому Score.
  4. Согласовать правило пяти направлений с организаторами. Сейчас «5 решений» не означает «5 направлений».
  5. Подтвердить полный путь на опубликованном Netlify-сайте, затем добавить сравнение команд и проверяемые рекомендации.

Документ Рекомендации-по-проекту-Аким.md в архиве — ранее составленный план развития, а не список уже реализованных функций. Актуальное состояние этой поставки описано выше.

Звёзды
⭐ 0
Форки
0
Язык
HTML
Последний push
в прошлом месяце
Коммиты
19
Авторы
4
Файлы
66
Ветки
3

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

amirlyand 7snr-png 5Julia Kozlova 5lisstikks 2

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

  • 2026-09-23 17:46Add files via uploadsnr-png
  • 2026-09-23 17:14Add files via uploadamirlyand
  • 2026-09-23 17:10Add verified Netlify project with README and verification reportJulia Kozlova
  • 2026-09-23 16:56Add Netlify-ready city simulatorsnr-png
  • 2026-09-23 16:28Add files via uploadamirlyand
  • 2026-09-23 16:27Add updated auth simulator source archiveJulia Kozlova
  • 2026-09-23 15:47Combine city simulator with existing hackathon resourcesJulia Kozlova
  • 2026-09-23 15:34Add files via uploadsnr-png
Все коммиты (19)
  • 2026-09-23 15:30Add files via uploadamirlyand
  • 2026-09-23 15:18Add files via uploadlisstikks
  • 2026-09-23 15:16Add files via uploadsnr-png
  • 2026-09-23 15:13Add files via uploadamirlyand
  • 2026-09-23 14:58Build city management simulator with budget validation and AI analysisJulia Kozlova
  • 2026-09-23 14:34first commitJulia Kozlova
  • 2026-09-23 14:32Add files via uploadamirlyand
  • 2026-09-23 14:29Merge pull request #1 from BAITC-Hacks/codex/latest-city-planner-mockupamirlyand
  • 2026-09-23 14:28Add files via uploadlisstikks
  • 2026-09-23 14:27Add files via uploadsnr-png
  • 2026-09-23 14:15Add latest Russian city planner mockup with data importamirlyand
Структура репозитория (66 файлов)
.dockerignore
.env.example
.env.production.example
.gitignore
Dockerfile
NETLIFY-QUICKSTART.md
README.md
START-HERE.md
akim-auth-source-updated.zip
akim-auth-source.zip
akim-mockup.html
akim-server-deploy-netlify.zip
app/api/auth/config/route.js
app/api/auth/login/route.js
app/api/auth/logout/route.js
app/api/auth/register/route.js
app/api/health/route.js
app/api/me/route.js
app/globals.css
app/layout.js
app/page.js
app/simulator/[asset]/route.js
app/simulator/route.js
backup-server.sh
compose.server.yaml
compose.yaml
db/001_auth.sql
db/docker-init.sh
deploy.sh
deploy/Caddyfile
lib/auth.mjs
lib/db.mjs
lib/http.mjs
lib/service.mjs
mockup/README.md
mockup/akim-auth-source.zip
mockup/akim-city-planner.fragment.html
mockup/index.html
netlify.toml
next.config.mjs
package.json
pnpm-lock.yaml
pnpm-workspace.yaml
scripts/bootstrap-postgres.mjs
scripts/create-user.mjs
scripts/download-postgres.mjs
scripts/export-snapshot.mjs
scripts/migrate.mjs
scripts/prepare-local-config.mjs
scripts/restore-snapshot.mjs
scripts/review.mjs
scripts/setup-postgres.ps1
scripts/snapshot.mjs
scripts/start-local.ps1
simulator/app.js
simulator/index.html
simulator/model.js
tests/auth.test.mjs
tests/http.test.mjs
tests/model.test.cjs
tests/snapshot.test.mjs
ЗАПУСК-НА-СЕРВЕРЕ.md
Рекомендации-по-проекту-Аким.md
СОСТАВ-ПАКЕТА.md
Формулы симулятора Аким на 5 часов.md
Формулы_симулятора_Аким_на_5_часов.md
Ветки (3)

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

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

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