|
| 1 | +# PRD: минимальная панель использования платформы (Usage Dashboard) |
| 2 | + |
| 3 | +**Версия документа:** 0.1 |
| 4 | +**Дата:** 2026-03-25 |
| 5 | +**Статус:** черновик требований (без реализации) |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## 1. Резюме |
| 10 | + |
| 11 | +Нужна **минимальная операторская панель** (read-only), показывающая **сводное использование** платформы SpawnDock: сколько уникальных **субъектов** активны, **как израсходованы лимиты** (где применимы) и **какие из пяти контролируемых сервисов** задействованы. |
| 12 | + |
| 13 | +**Контролируемые сервисы (обязательная сегментация в отчётах):** |
| 14 | + |
| 15 | +| ID | Компонент | Типовой вход / заметка | |
| 16 | +|---------|------------------|-------------------------| |
| 17 | +| `search` | Knowledge search | Публичный `POST /knowledge/api/v1/search`, внутренние вызовы MCP → search | |
| 18 | +| `mcp` | MCP / control plane | `mcp-server`: HTTP/SSE, инструменты, preview и пр. | |
| 19 | +| `bot` | Telegram bot | Polling/webhook, команды, выдача токенов | |
| 20 | +| `tunnel`| Dev tunnel | Клиенты `dev-tunnel`, WebSocket к control plane | |
| 21 | +| `landing` | Лендинг / статика | Трафик на корневой лендинг за Caddy (не API) | |
| 22 | + |
| 23 | +Панель **не заменяет** полноценный APM (Grafana/Prometheus); цель — **единый минимальный обзор** для оператора на одном экране или двух. |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## 2. Цели и критерии успеха |
| 28 | + |
| 29 | +| ID | Цель | Сигнал успеха | |
| 30 | +|----|------|----------------| |
| 31 | +| G1 | Видимость **активности по сервисам** | В панели отображаются счётчики/серии хотя бы за **24ч / 7д** по пяти ID выше | |
| 32 | +| G2 | Видимость **лимитов** там, где они уже есть | Для **search** — попадания в квоты (free/basic), **429**, необязательно поминутно в v0 | |
| 33 | +| G3 | Видимость **«пользователей»** в разумном определении | Оператор видит **число уникальных субъектов** и разбивку по типу (см. §4) без ручного сбора логов | |
| 34 | +| G4 | **Безопасность** | Панель недоступна публично; доступ только **операторам** (см. §8) | |
| 35 | +| G5 | **Минимализм** | MVP без биллинга, без self-service для конечных пользователей | |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +## 3. Не в scope (v0) |
| 40 | + |
| 41 | +- Оплата, счета, лимиты «pro/enterprise» как продукт. |
| 42 | +- Редактирование квот или блокировка пользователей из UI (только просмотр; действия — вне v0 или отдельный PRD). |
| 43 | +- Гарантия 100% сквозной идентичности «один человек = один user_id» между Telegram, браузером и MCP (см. §4.3). |
| 44 | +- Хостинг панели на том же публичном префиксе, что и лендинг, **без** отдельной аутентификации. |
| 45 | + |
| 46 | +--- |
| 47 | + |
| 48 | +## 4. Определения: «пользователь» и учёт |
| 49 | + |
| 50 | +### 4.1 Субъект (actor) |
| 51 | + |
| 52 | +Минимальная модель данных для агрегации: |
| 53 | + |
| 54 | +- **`actor_type`**: `api_token` | `telegram_user` | `anonymous_ip` | `tunnel_client` | `unknown` |
| 55 | +- **`actor_key`**: стабильный строковый идентификатор **без** хранения секретов в открытом виде: |
| 56 | + - `api_token` → **хэш** токена (например SHA-256 с солью из env) или внутренний `token_id`, если позже появится таблица токенов |
| 57 | + - `telegram_user` → `telegram_user_id` (число) |
| 58 | + - `anonymous_ip` → IP за доверенным прокси (как в search free-tier) |
| 59 | + - `tunnel_client` → стабильный client/session id из протокола tunnel (уточнить при инструментировании) |
| 60 | + |
| 61 | +### 4.2 Связь actor ↔ сервис |
| 62 | + |
| 63 | +Каждое значимое событие учёта помечается **`service`** ∈ { `search`, `mcp`, `bot`, `tunnel`, `landing` }. |
| 64 | + |
| 65 | +Один субъект может появляться в **нескольких** сервисах; панель показывает **пересечения** (например «только search», «mcp+bot», таблица или sankey — опционально в v1). |
| 66 | + |
| 67 | +### 4.3 Ограничения идентификации |
| 68 | + |
| 69 | +- **Landing**: чаще всего **без** логина — учёт по **сессии** (cookie/анонимный id) или только агрегаты (просмотры/UV по IP+fingerprint — v1, мягко). |
| 70 | +- **MCP с токеном** и **бот** могут относиться к одному человеку; в v0 допустима **дубликатная** учётная запись в статистике с пометкой «разные actor_type». |
| 71 | + |
| 72 | +--- |
| 73 | + |
| 74 | +## 5. Требования к данным по сервисам |
| 75 | + |
| 76 | +### 5.1 `search` |
| 77 | + |
| 78 | +**Уже есть (концептуально):** free/basic tier, лимиты per minute / per day, различие публичного трафика ( `X-Forwarded-For` ) и внутреннего MCP. |
| 79 | + |
| 80 | +**Нужно для панели (instrumentation):** |
| 81 | + |
| 82 | +- Счётчики: `requests_ok`, `requests_429`, по **`tier`** (`free` / `basic`). |
| 83 | +- Разрез по **`actor_key`** (для basic — hash токена; для free — IP или сегмент). |
| 84 | +- Опционально: доля **cache_hit** из `meta` (если включён кэш search). |
| 85 | + |
| 86 | +**Источник:** метрики из процесса `search` (экспорт Prometheus, stdout JSON, или периодический сброс в SQLite/Redis — решение implementer pass). |
| 87 | + |
| 88 | +### 5.2 `mcp` |
| 89 | + |
| 90 | +**Нужно:** |
| 91 | + |
| 92 | +- Счётчики запросов к **чувствительным** маршрутам: например SSE/MCP сессии, вызовы инструментов (хотя бы суммарно). |
| 93 | +- При наличии **Bearer / сессии** — привязка к `api_token` hash или внутреннему session id. |
| 94 | + |
| 95 | +**Источник:** middleware в `mcp-server` (`repo/api`), единый формат лог-события `service=mcp`. |
| 96 | + |
| 97 | +### 5.3 `bot` |
| 98 | + |
| 99 | +**Нужно:** |
| 100 | + |
| 101 | +- События: команды (`/start`, `/gettoken`, и т.д.), активные пользователи за окно. |
| 102 | +- **`actor_key`** = `telegram_user_id`. |
| 103 | + |
| 104 | +**Источник:** hooks в `repo/api` bot polling; избегать логирования секретов. |
| 105 | + |
| 106 | +### 5.4 `tunnel` |
| 107 | + |
| 108 | +**Нужно:** |
| 109 | + |
| 110 | +- Подключения / сессии / переданные байты (минимум: **число активных / новых сессий** за период). |
| 111 | +- Идентификатор клиента — из протокола `repo/dev-tunnel` и бэкенда. |
| 112 | + |
| 113 | +**Источник:** control plane в `repo/api` + при необходимости агент `dev-tunnel`. |
| 114 | + |
| 115 | +### 5.5 `landing` |
| 116 | + |
| 117 | +**Нужно:** |
| 118 | + |
| 119 | +- Базовые **визиты** (page views), опционально **уникальные** по дню. |
| 120 | +- Без PII в сыром виде в панели. |
| 121 | + |
| 122 | +**Источник:** access log Caddy (разбор на edge) или лёгкий **pixel/counter** endpoint за отдельным путём с rate limit. |
| 123 | + |
| 124 | +--- |
| 125 | + |
| 126 | +## 6. Функциональные требования (MVP панели) |
| 127 | + |
| 128 | +### 6.1 Экран «Обзор» |
| 129 | + |
| 130 | +- Карточки за период **24ч / 7д** (переключатель): |
| 131 | + - **Активные субъекты** (уникальные `actor_key`, с разбивкой по `actor_type`). |
| 132 | + - **События по сервисам** — столбчатая или таблица: `search` | `mcp` | `bot` | `tunnel` | `landing`. |
| 133 | + - **Search limits:** суммарно **429**, запросы **ok**, (если доступно) **остаток** до дневного/минутного лимита **в агрегате** по tier. |
| 134 | + |
| 135 | +### 6.2 Экран или блок «Search detail» |
| 136 | + |
| 137 | +- Таблица топ-N **субъектов** по числу запросов (обезличенно: префикс хэша, не токен). |
| 138 | +- График или счётчик **429** по времени. |
| 139 | + |
| 140 | +### 6.3 Экран или блок «Сервисы × субъекты» (v0.5, желательно) |
| 141 | + |
| 142 | +- Матрица: сколько субъектов касалось каждого сервиса; простая **venn-подобная** сводка или мультивыбор фильтра. |
| 143 | + |
| 144 | +### 6.4 Обновление данных |
| 145 | + |
| 146 | +- Задержка **≤ 1–5 мин** для агрегатов (достаточно batch/offline rollups). |
| 147 | + |
| 148 | +--- |
| 149 | + |
| 150 | +## 7. Нефункциональные требования |
| 151 | + |
| 152 | +- **Retention сырых событий:** v0 — 7–30 дней (конфигурируемо); агрегаты — дольше. |
| 153 | +- **Производительность:** панель не должна сканировать полные текстовые логи в runtime; только БД/TSDB. |
| 154 | +- **GDPR/приватность:** не хранить содержимое запросов search в таблицах панели; максимум длина/хэш для отладки — отдельный флаг. |
| 155 | + |
| 156 | +--- |
| 157 | + |
| 158 | +## 8. Безопасность и доступ |
| 159 | + |
| 160 | +- URL панели **не** индексировать; **отдельный** admin-префикс (например `/ops/usage`) за Caddy. |
| 161 | +- Аутентификация v0: **HTTP Basic** с паролем из env, **или** OIDC позже, **или** VPN-only + IP allowlist (решение ops). |
| 162 | +- Роль: только `operator`; аудит входов — желательно (лог). |
| 163 | + |
| 164 | +--- |
| 165 | + |
| 166 | +## 9. Зависимости и фазы |
| 167 | + |
| 168 | +### Фаза 0 — контракт событий |
| 169 | + |
| 170 | +- Ввести единую схему **usage event**: `{ ts, service, event_type, actor_type, actor_key, tier?, status?, bytes? }`. |
| 171 | +- Писать в **одно** хранилище (SQLite на VPS / Postgres / ClickHouse lite — выбрать по нагрузке). |
| 172 | + |
| 173 | +### Фаза 1 — сборщики |
| 174 | + |
| 175 | +- Инструментирование **search**, **mcp**, **bot** (минимум). |
| 176 | +- **tunnel** и **landing** — следующими PR. |
| 177 | + |
| 178 | +### Фаза 2 — UI |
| 179 | + |
| 180 | +- Один сервис **static+api** или Next.js micro-app в монорепе; **или** Grafana dashboard + документация, если UI «панели» = дашборд (explicit decision). |
| 181 | + |
| 182 | +--- |
| 183 | + |
| 184 | +## 10. Открытые вопросы |
| 185 | + |
| 186 | +1. Единый **Postgres** для control plane + usage или отдельная БД? |
| 187 | +2. Нужен ли **экспорт CSV** для оператора в v0? |
| 188 | +3. Согласовать **имена сервисов** с метриками infra (Kubernetes labels и т.д.), если появятся. |
| 189 | + |
| 190 | +--- |
| 191 | + |
| 192 | +## 11. Связанные документы |
| 193 | + |
| 194 | +- `docs/PRD-public-knowledge-search-service.md` — модель лимитов **search** (`free` / `basic`, 429). |
| 195 | +- `OPERATOR.md` (если есть) — деплой, Caddy, секреты. |
| 196 | + |
| 197 | +--- |
| 198 | + |
| 199 | +## 12. Утверждение |
| 200 | + |
| 201 | +- Product / Ops: перечень метрик и определение «пользователь». |
| 202 | +- Security: хранение хэшей, доступ к панели, landing tracking. |
| 203 | + |
| 204 | +--- |
| 205 | + |
| 206 | +*Конец PRD.* |
0 commit comments