Gaming Club Management System — SaaS-платформа управления компьютерными клубами. Один локальный сервер на клуб (local-node), веб-консоль для администратора и кассира (admin-web), kiosk-приложение игроку на каждой станции (kiosk + kiosk-watchdog).
Этот README — точка входа для нового разработчика и для оператора, ставящего demo. Бизнес-scope зафиксирован в docs/MVP_SCOPE.md, правила работы AI-агентов и людей — в docs/AGENT_RULES.md, архитектурные заметки — в docs/ARCHITECTURE_NOTES.md.
# 1. Секрет для подписи токенов admin-web (>= 16 символов).
cp .env.example .env
# открыть .env, выставить GCMS_JWT_SECRET=...
# 2. Поднять стек (миграции + seed выполняются автоматически).
.\scripts\dev-up.ps1
# 3. В браузере: http://127.0.0.1:5173/
# Owner login: owner@demo.gcms / owner-demo-Pass-2026!
# Cashier login: cashier@demo.gcms / cashier-demo-Pass-2026!Прохождение демо — docs/DEMO_SCRIPT.md: открыть смену → создать клиента + PIN → пополнить депозит → начать/паузить/завершить сессию → отчёт по смене → offline-сценарий.
Остановить: .\scripts\dev-down.ps1. SQLite остаётся на диске; следующий запуск с -SkipMigrate -SkipSeed поднимет всё там же, где остановилось.
cp .env.example .env
# выставить GCMS_JWT_SECRET=... (16+ символов)
docker compose up --build -d
# Один раз — миграции и seed:
docker compose run --rm local-node npm run migrate
docker compose run --rm local-node npm run seed
# Открыть http://localhost:5173/Остановить: docker compose down. SQLite в named volume gcms_sqlite-data — данные переживают down/up. Полный wipe: docker compose down -v.
Kiosk-приложение в docker-compose не входит — WPF приложение, только Windows-native. Backend в Docker и kiosk на хосте совместимы: пропишите
LocalNodeUrlкиоска на хост-машину (или192.168.x.yиз LAN).
Только для Windows; ставится отдельно от admin-стенда. Шаги, включая hardening (Winlogon Shell / AppLocker / DisallowRun) — docs/KIOSK_INSTALL.md.
Минимум для разработки:
cd apps\kiosk
$env:GCMS_KIOSK_DEV_MODE = "true" # windowed, dev-toolbar виден, keyboard hook не ставится
dotnet run --project GcmsKiosk| Компонент | Что нужно | Зачем |
|---|---|---|
apps/local-node |
Node.js 22 LTS, npm | Fastify-сервер, SQLite (better-sqlite3 — нативный модуль). |
apps/admin-web |
Node.js 22 LTS, npm | Vite + React 18, dev-режим. |
apps/kiosk, apps/kiosk-watchdog |
Windows 10/11, .NET 10 SDK, PowerShell 5.1+ | WPF + Worker Service. На Linux/Mac не собирается. |
| Docker-путь | Docker Engine 24+ с Compose v2 | Альтернатива для evaluator'а, не имеющего .NET/Node. |
npm install запускается автоматически из dev-up.ps1; вручную:
cd apps/local-node && npm install
cd apps/admin-web && npm installGCMS/
+-- apps/
| +-- admin-web/ # React/Vite. Запуск: npm run dev. Тесты: npm test.
| +-- local-node/ # Fastify + SQLite. npm run start | dev | migrate | seed | test.
| +-- kiosk/ # WPF (.NET 10). dotnet run --project GcmsKiosk; dotnet test.
| +-- kiosk-watchdog/ # Windows Service (Worker). dotnet test; install.ps1.
+-- packages/
| +-- shared/ # Общие Zod-схемы / типы между admin-web и local-node.
+-- docs/
| +-- MVP_SCOPE.md
| +-- ARCHITECTURE_NOTES.md
| +-- AGENT_RULES.md
| +-- DEMO_SCRIPT.md # <-- операторская инструкция demo
| +-- KIOSK_INSTALL.md # <-- Windows install kiosk+watchdog+hardening
+-- scripts/
| +-- dev-up.ps1 # Native dev-launcher (Windows).
| +-- dev-down.ps1
| +-- windows-kiosk-hardening/
+-- Brandbook/ # Палитра, типографика, символ, плейбук.
+-- docker-compose.yml # local-node + admin-web для cross-platform demo.
+-- .env.example
+-- README.md # этот файл
Внутри каждого модуля — свой README.md со специфичными деталями.
Четыре независимых suite'а — по одной команде на модуль.
| Модуль | Команда | Что покрывает |
|---|---|---|
apps/local-node |
cd apps/local-node && npm test |
Vitest, 462 теста. MVP-критерии: [MVP-FLOOR-MAP], [MVP-PER-MINUTE], [MVP-FIXED-PKG], [MVP-RBAC-CASHIER], [MVP-AUDIT-END], [MVP-HEARTBEAT]. |
apps/admin-web |
cd apps/admin-web && npm test |
Vitest + Testing Library + jsdom, 164 теста. |
apps/kiosk |
cd apps/kiosk && dotnet test |
xUnit, 153 теста (non-WPF логика). MVP-критерии: [MVP-KIOSK-OFFLINE], [MVP-KIOSK-AUTH-OFFLINE], [MVP-KIOSK-OUTBOX]. |
apps/kiosk-watchdog |
cd apps/kiosk-watchdog && dotnet test |
xUnit, 7 тестов (FSM, retry, escalation). |
Запустить всё подряд:
cd apps/local-node ; npm test ; cd ../admin-web ; npm test ; cd ../kiosk ; dotnet test ; cd ../kiosk-watchdog ; dotnet testMVP acceptance tests изолированы в выделенных файлах:
apps/local-node/src/__tests__/mvp_acceptance.test.ts— 10 кейсов.apps/kiosk/GcmsKiosk.Tests/MvpAcceptanceTests.cs— 4 кейса.
Каждый кейс начинается с [MVP-<short-id>] — падение сразу показывает, какой acceptance criterion регрессировал.
| Роль | Пароль | |
|---|---|---|
| OWNER | owner@demo.gcms |
owner-demo-Pass-2026! |
| CASHIER | cashier@demo.gcms |
cashier-demo-Pass-2026! |
OWNER видит все разделы (Настройки, Журнал действий, Каталог игр, Тарифы). CASHIER — только рабочие (Касса / Смена, Клиенты, Карта зала, Тарифы read-only, Отчёты).
Seed создаёт один клуб club_demo, 3 зоны, 14 станций (10x PC-, 2x VIP-, 2x Console-) и 2 тарифа: Standard Minute (PER_MINUTE, 2,00 руб/мин) и 3-Hour Package (FIXED_PACKAGE, 180 мин, 300,00 руб).
Это сознательные ограничения текущей итерации — не баги, а граница scope. Подробности — в docs/MVP_SCOPE.md и README соответствующих модулей.
- Облачная синхронизация — only interface:
event_queue+ICloudSyncTransport+ scheduler + retry policy реализованы и затестированы; реального HTTP-транспорта нет, события навсегда остаются в локальной БД (видны черезsync_conflicts/event_queueесли когда-нибудь начнут деливериться). - Multi-club не поддерживается: один local-node = один клуб (
GCMS_CLUB_ID). - Внешние webhooks нет — telemetry не шлётся никуда наружу.
- Authentication только локальная: bcrypt-хеши паролей сотрудников и PIN-кодов клиентов. SSO / LDAP / OAuth — out of scope.
- Refresh-token storage in DB — без external session store. Перезапуск local-node инвалидирует все access-токены до refresh.
- Только Windows. WPF, .NET 10.
- Steam/Epic/Riot/Battle.net autologin cleanup — заглушка (
NoopExternalLauncherSessionHook). - Keyboard hook блокирует Win / Alt+Tab / Alt+F4 / Ctrl+Esc. Не блокирует Ctrl+Shift+Esc (Task Manager) и Ctrl+Alt+Del (Secure Attention Sequence) — закрываются GPO / AppLocker (см.
scripts/windows-kiosk-hardening/). - Watchdog auto-restart работает (тестировано), но в demo-стенде не разворачивается — это отдельный install (
apps/kiosk-watchdog/install.ps1, см. docs/KIOSK_INSTALL.md). - GPO/AppLocker hardening — только скрипты с dry-run/backup/restore (
scripts/windows-kiosk-hardening/). Реально применять только на тестовой Windows-машине. - Shell replacement / AppLocker policy НЕ применяется автоматически в
dev-up.ps1. Только вApply-KioskHardening.ps1с явным-Apply.
- Brand styling: admin-web использует placeholder-цвета (slate). Брендбук в
Brandbook/, применение — отдельный промпт. - Локализация: русский inline в коде; i18n-инфраструктуры нет.
- Мобильное приложение / iPad cashier: нет, только desktop browser admin-web.
- Production installer для kiosk — нет, только
dotnet build+ ручной copy +install.ps1. MSI/MSIX deferred. - Cloud deploy — нет, только локальный demo. Облачная сторона MVP — отдельный проект.
- TLS — нет в demo-стенде.
cookieSecure: falsebaked in. Production stand требует обратного прокси с TLS. - CI/CD — отсутствует, тесты гоняются локально вручную (см. секцию "Тесты").
- better-sqlite3 в Docker — собирается из исходников при первом
docker compose build(~30 сек). Это нормально.
- Дефолтный seed-пароль
owner-demo-Pass-2026!— известный, сменить перед любой production-инсталляцией. GCMS_JWT_SECRETиз.env.example— placeholder. Использоватьnode -e "console.log(require('crypto').randomBytes(32).toString('hex'))"для реального деплоя.- SQLite-файл (
gcms.db) не зашифрован. BitLocker / EFS — вне MVP.
- Реальный HTTP-транспорт для cloud-sync (
HttpCloudSyncTransport). - Auto-login kiosk-юзера через LSA Secrets / Credential Guard.
- Stylesheet применение Brandbook к admin-web.
- Production installer (MSI/MSIX) для kiosk + watchdog.
- Облачная половина платформы (multi-club, billing reports).
Внутренний проект, лицензия пока не выбрана. Не публиковать без явного апрува.