# MENET / ClubNet: задание для Claude

Создай Windows-приложение MENET на основе предоставленного clubnet.zip.
Бренд: MENET. Продукт сайта: MENET Arena. Контакт: mennett.org@gmail.com.

Сайт уже содержит реальные аккаунты, Cloudflare D1, клубы, места, бронирования,
сеансы, расчёт стоимости, роли сотрудников, ручную проверку оплат, подписку и
защищённое скачивание исходного clubnet.zip. Приложение в исходном архиве
пока работает отдельно от сайта.

## Текущий архив

- clubnet/server.js: Node.js + Express + ws; локальная панель, WebSocket
  агентов, команды и запись данных в data.json.
- clubnet/agent/agent.py: Python, websocket-client, Tkinter, команды
  lock/unlock/message/shutdown/restart.
- clubnet/public/index.html и guide.html: интерфейс и руководство.
- Это исходники, не установщик .exe. Не обещай готовый установщик до сборки
  и тестирования на Windows.
- Исходный код содержит дефолтные ADMIN_PASS=admin, AGENT_KEY=change-me.
  Заменить на настройку владельцем без универсальных паролей.
- Текущая валюта в локальном интерфейсе обозначена рублём: заменить на сом.

## Интеграция с уже готовым API

BASE_URL — настоящий HTTPS-адрес развернутого сайта MENET.
Ключ каждого ПК создаётся владельцем клуба в кабинете:
«Устройства → Создать ключ». Ключ показывается только один раз.

POST BASE_URL/api/agent/heartbeat

Заголовок: Authorization: Bearer <ключ_этого_ПК>

Ответ:
{
  "ok": true,
  "server_time": 1790000000000,
  "resource": {"id": "uuid", "name": "PC 01"},
  "session": {
    "id": "uuid",
    "status": "running",
    "started_at": 1790000000000,
    "planned_end": 1790003600000,
    "paused_at": null,
    "paused_ms": 0,
    "hourly_rate": 150
  }
}

session=null — активного сеанса нет. status=running или paused.
Времена — миллисекунды Unix UTC. В интерфейсе клуба время Бишкека, UTC+6.
Ключ связан с одним resource_id на сервере. Не добавляй в запрос
произвольный resource_id и не делай общий ключ для всех клубов.

Опрос каждые 15–20 секунд. Хранить токен в защищённом хранилище Windows,
не в коде и не в логах. 401 означает неверный или отозванный ключ.
402 означает истекший доступ клуба. При потере сети не выключать ПК
автоматически, не терять состояние и показывать оператору причину.

Текущий heartbeat выдаёт состояние сеанса; отдельного API произвольных
команд питания нет. Для синхронизации running → доступен сеанс, paused
или null → отобразить подходящий экран после согласованной настройки.
Не выдавай это за полноценную защиту ОС: Tkinter-окно не заменяет
права Windows, управление учётными записями или kiosk-mode.

## Веб-операции, уже реализованные

Браузер входит через email/пароль, получает HttpOnly cookie.
Все браузерные POST/PUT/PATCH/DELETE должны быть same-origin и содержать:
Content-Type: application/json
X-MENET-Request: 1

- GET /api/me
- POST /api/auth/register {name,email,password}
- POST /api/auth/login {email,password}
- POST /api/auth/logout
- POST /api/auth/password {old_password,new_password}
- GET /api/dashboard
- POST /api/club {name,slug,city,count,rate}
- PUT /api/club {name,city,address,phone,opens,closes}
- POST /api/resources {name,kind,zone,specs,rate}
- PATCH /api/resources/:id {name,zone,specs,rate} или {archive:true}
- POST /api/bookings {resource_id,name,contact,start_at,end_at}
- DELETE /api/bookings/:id
- POST /api/sessions {resource_id,name,minutes,booking_id?}
- POST /api/sessions/:id/pause
- POST /api/sessions/:id/resume
- POST /api/sessions/:id/stop {paid:true|false}
- POST /api/sessions/:id/pay
- GET /api/export
- POST /api/team/invite
- POST /api/team/join {code}
- DELETE /api/team/:user_id
- POST /api/devices/pair {resource_id}
- POST /api/devices/revoke {resource_id}

Пароль и сессии не передавать агенту ПК. Для агента — только отдельный
ключ устройства. Доступ к клубу и роли проверяются сервером.
Для дополнительных возможностей Windows-клиента спроектировать новый
scoped API и внести изменения в _worker.js; текущий web-cookie API
не обходить подделкой Origin.

## Заказы и архив

- GET /api/store — цена, доступность продаж, период.
- GET /api/orders — свои заказы и лицензия.
- POST /api/orders — создать заказ; сумму определяет сервер.
- POST /api/orders/:id/receipt {mime,base64} — JPG/PNG/WebP до 600 КБ.
- GET /api/license — активность и срок доступа своего аккаунта.
- GET /api/download — только для оплаченного аккаунта с активным периодом.

Оплата переводом подтверждается владельцем MENET вручную. Не добавлять
кнопку клиента, которая сама делает заказ оплаченным. Открытая ссылка
на app.zip в public/assets недопустима. Текущий clubnet.zip встроен
в серверный _worker.js, передаётся только после проверки прав.

Подписка продлевается на 30 дней. Она не является DRM уже скачанного
архива. Не утверждать, что локальная копия автоматически перестанет
работать, пока проверка лицензии не реализована в приложении.

## Требуемый результат приложения

1. Брендинг MENET, русская локализация, валюта сом.
2. Настройка HTTPS-сайта и ключа каждого устройства.
3. Подключение к описанному heartbeat, отображение сетевого статуса.
4. Без универсальных паролей и общих секретов в бинарнике.
5. Сборка отдельного администратора и агента для Windows.
6. Проверка на реальном Windows: установка, подключение, пауза,
   завершение, отозванный ключ и восстановление сети.
7. Документировать, что реализовано и что проверено.

Сайт написан на обычных HTML/CSS/JavaScript, без JSX и сборки.
Сервер _worker.js — Cloudflare Pages Advanced Mode, DB — Cloudflare D1.
