TicketsPage.tsx — список open/closed тикетов + тред сообщений + ответ +
закрытие (owner/moderator/support). ObservabilityPage.tsx — вкладки
дашбордов Grafana через iframe за auth-гейтом Caddy, URL берётся из
GET /api/v1/config (grafana_url), страница просто не показывает
дашборды, пока GRAFANA_PUBLIC_URL не задан на сервере. StaffPage.tsx —
форма создания support-аккаунта (только Owner).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ролевая система вместо привязки к Telegram
----------------------------------------
Раньше единственный способ получить админ-доступ — admin_guard, пускавший
по ADMIN_TG_ID или role=="admin" (без сеттера для роли). Заменяет на
Owner/Moderator/Partner:
- migrations/0005_roles_and_partners.sql — username/password_hash на users
(NULL у обычных Ghost/Telegram-юзеров, тот же паттерн, что и у seed_hash/
tg_id), can_manage_nodes, commission_percent, partner_code,
referred_by_partner_id; новые таблицы partner_commissions и
withdrawal_requests.
- auth/guard.rs — admin_guard заменён на owner_guard/staff_guard/
node_manage_guard/partner_guard; ADMIN_TG_ID убран из ApiState и main.rs.
- auth/service.rs — hash_password/login_staff со случайной Argon2-солью на
каждого юзера (не общий фиксированный ARGON_SALT, который годится для
высокоэнтропийных seed-логинов, но не для человеческих паролей).
- POST /api/v1/auth/admin/login — вход модератора/партнёра/овнера паролем,
переиспользует существующий issue_session().
- --create-owner CLI-флаг (main.rs) со скрытым вводом пароля (rpassword) —
вместо ручного SQL для создания первого владельца с VPS-консоли.
- src/modules/staff/ — эндпоинты создания модераторов/партнёров, переключения
can_manage_nodes, списка заявок на вывод и их approve/reject/paid.
- Комиссия партнёра начисляется в BillingService::confirm_payment отдельным
шагом после существующей рефералки, пересчитывается через
get_plan_price(invoice.plan_name, invoice.currency) — НЕ через
invoice.amount напрямую, потому что у провайдеров разная внутренняя
единица (TON — nanoTON+2% буфер, CryptoBot — фиатные центы напрямую).
- bot.rs — /start p_XXXXXX привязывает покупателя к партнёру по коду
(first-wins, до существующих веток numeric-tg_id-рефералки и кода входа).
- frontend/ — AdminLogin/AdminLayout/StaffPage/WithdrawalsPage/EarningsPage
поверх существующего Vite-админ-фронта (без отдельного проекта).
Оплата через @CryptoBot
------------------------
- modules/billing/providers/cryptobot.rs — новый PaymentProvider (Crypto Pay
API), плюс попутно исправлены два реальных бага в существующем коде:
confirm_payment был жёстко завязан на TON-провайдера при любом инвойсе, и
InvoiceRecord не хранил currency, из-за чего TON-курс молча применялся ко
всем провайдерам вместо родной валюты инвойса.
- bot.rs — экран выбора способа оплаты для CryptoBot-инвойсов.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>