From 5489fc3b43d29b66f43fbd03a1101d24edd5227f Mon Sep 17 00:00:00 2001 From: ochenstarik Date: Fri, 11 Sep 2026 02:34:51 +0700 Subject: [PATCH] docs(control-center): add comprehensive handoff specifications and atomic zero-downtime deployment package --- deploy/kcc/deploy-kcc.sh | 68 +++++++++ deploy/kcc/nginx-kccdemo.conf | 78 ++++++++++ .../control-center/ACCEPTANCE-TESTS.md | 117 +++++++++++++++ .../handoff/control-center/DEPLOYMENT-DEMO.md | 136 ++++++++++++++++++ .../control-center/FRONTEND-CONTRACTS.md | 80 +++++++++++ docs/handoff/control-center/PERMISSIONS.md | 47 ++++++ docs/handoff/control-center/ROUTES.md | 29 ++++ docs/handoff/control-center/STATES.md | 62 ++++++++ docs/handoff/control-center/UX-SPEC.md | 88 ++++++++++++ 9 files changed, 705 insertions(+) create mode 100644 deploy/kcc/deploy-kcc.sh create mode 100644 deploy/kcc/nginx-kccdemo.conf create mode 100644 docs/handoff/control-center/ACCEPTANCE-TESTS.md create mode 100644 docs/handoff/control-center/DEPLOYMENT-DEMO.md create mode 100644 docs/handoff/control-center/FRONTEND-CONTRACTS.md create mode 100644 docs/handoff/control-center/PERMISSIONS.md create mode 100644 docs/handoff/control-center/ROUTES.md create mode 100644 docs/handoff/control-center/STATES.md create mode 100644 docs/handoff/control-center/UX-SPEC.md diff --git a/deploy/kcc/deploy-kcc.sh b/deploy/kcc/deploy-kcc.sh new file mode 100644 index 0000000..160de27 --- /dev/null +++ b/deploy/kcc/deploy-kcc.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# ============================================================================== +# Krona Control Center (KCC) - Atomic Zero-Downtime Deployment Script +# Target: https://kccdemo.ochenstarik.ru +# Target Host: 178.212.13.102 (User: kcc) +# ============================================================================== + +set -euo pipefail + +APP_ROOT="/srv/kccdemo" +RELEASES_DIR="$APP_ROOT/releases" +CURRENT_LINK="$APP_ROOT/current" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +NEW_RELEASE_DIR="$RELEASES_DIR/$TIMESTAMP" + +echo "=================================================================" +echo " [KCC Deploy] Initiating atomic release: $TIMESTAMP" +echo "=================================================================" + +# 1. Create target release directory +mkdir -p "$NEW_RELEASE_DIR" + +# 2. Deploy static SPA artifacts +if [ -d "./dist" ]; then + echo "Copying ./dist to $NEW_RELEASE_DIR..." + cp -r ./dist/* "$NEW_RELEASE_DIR/" +elif [ -d "../dist" ]; then + echo "Copying ../dist to $NEW_RELEASE_DIR..." + cp -r ../dist/* "$NEW_RELEASE_DIR/" +else + echo "ERROR: Production build directory 'dist' not found!" >&2 + exit 1 +fi + +# Set proper permissions for kcc user +chmod -R 755 "$NEW_RELEASE_DIR" + +# 3. Atomic symlink switch +echo "Switching active release symlink ($CURRENT_LINK -> $NEW_RELEASE_DIR)..." +ln -sfn "$NEW_RELEASE_DIR" "$CURRENT_LINK" + +# 4. Prune older releases (keep last 3 for instant rollback) +echo "Cleaning up old releases (retaining last 3)..." +cd "$RELEASES_DIR" +# List matching release directories sorted by date descending, remove all except top 3 +ls -1dt 20* 2>/dev/null | tail -n +4 | xargs -r rm -rf + +# 5. Reload Nginx +if command -v systemctl >/dev/null 2>&1; then + echo "Reloading Nginx web server..." + sudo systemctl reload nginx || systemctl reload nginx || echo "Nginx reload skipped (no sudo permission)" +fi + +# 6. Post-deploy health verification +echo "Executing health verification on local loopback..." +HTTP_STATUS=$(curl -sk -o /dev/null -w "%{http_code}" https://127.0.0.1/control/gate -H "Host: kccdemo.ochenstarik.ru" || true) + +echo "Local Healthcheck HTTP Status: $HTTP_STATUS" +if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "301" ] || [ "$HTTP_STATUS" = "302" ]; then + echo "=== [KCC Deploy] Health check: PASSED ===" +else + echo "WARNING: Health check returned status $HTTP_STATUS. Please verify Nginx configuration." +fi + +echo "=================================================================" +echo " [KCC Deploy] Release $TIMESTAMP successfully deployed and active!" +echo " URL: https://kccdemo.ochenstarik.ru" +echo "=================================================================" diff --git a/deploy/kcc/nginx-kccdemo.conf b/deploy/kcc/nginx-kccdemo.conf new file mode 100644 index 0000000..0b97b6f --- /dev/null +++ b/deploy/kcc/nginx-kccdemo.conf @@ -0,0 +1,78 @@ +# ============================================================================== +# Krona Control Center - Nginx Server Block Configuration +# Domain: kccdemo.ochenstarik.ru +# Target Host: 178.212.13.102 +# ============================================================================== + +# HTTP -> HTTPS redirect +server { + listen 80; + listen [::]:80; + server_name kccdemo.ochenstarik.ru; + + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / { + return 301 https://$host$request_uri; + } +} + +# Production HTTPS server +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name kccdemo.ochenstarik.ru; + + # SSL Certificate configuration + ssl_certificate /etc/letsencrypt/live/kccdemo.ochenstarik.ru/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/kccdemo.ochenstarik.ru/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 1d; + ssl_session_tickets off; + + # Root pointing to atomic symlink + root /srv/kccdemo/current; + index index.html; + + # Security Headers + add_header X-Frame-Options "DENY" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: https:; connect-src 'self' ws: wss:; frame-ancestors 'none';" always; + + # Compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml; + + # Static assets cache control + location /assets/ { + expires 1y; + add_header Cache-Control "public, immutable"; + access_log off; + } + + # Favicon and robots + location = /favicon.ico { + access_log off; + log_not_found off; + } + + # SPA routing fallback: send all routes to index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Dedicated access and error logs + access_log /var/log/nginx/kccdemo_access.log; + error_log /var/log/nginx/kccdemo_error.log warn; +} diff --git a/docs/handoff/control-center/ACCEPTANCE-TESTS.md b/docs/handoff/control-center/ACCEPTANCE-TESTS.md new file mode 100644 index 0000000..a59bef7 --- /dev/null +++ b/docs/handoff/control-center/ACCEPTANCE-TESTS.md @@ -0,0 +1,117 @@ +# Реестр приёмочных сценариев (Acceptance Tests) Krona Control Center + +Все приёмочные сценарии автоматизированы в Playwright E2E сьюте (`e2e/11-control-center.spec.ts`) и покрывают как функциональные требования, так и устойчивость интерфейса. + +--- + +### Сценарий 1: Поиск организации и открытие 360° Инспектора +- **Предусловия**: Оператор находится на странице `/control/organizations`. +- **Шаги**: + 1. Ввести в поле поиска `"Северная"`. + 2. Убедиться, что в таблице отображается только «Северная Ритейл Группа». + 3. Нажать кнопку `"360° Карточка"`. +- **Ожидаемый результат**: + - Открывается боковой Drawer инспектора с карточкой организации, ИНН, датой регистрации. + - Доступны вкладки «Обзор», «Модули», «Инсталляции», «Биллинг». + - Переключение на вкладку «Модули» отображает установленные версии модулей и их статус. + +--- + +### Сценарий 2: Подтверждение опасного действия с обязательным обоснованием +- **Предусловия**: Открыт 360° инспектор организации. +- **Шаги**: + 1. Нажать кнопку `"Выдать Trial +14 дней"`. + 2. Проверить появление модального диалога `ConfirmOperatorAction`. + 3. Проверить, что кнопка подтверждения отключена при пустом поле обоснования. + 4. Ввести обоснование `"Запрос от аккаунт-директора на пилотное тестирование филиала"`. + 5. Нажать `"Подтвердить операцию"`. +- **Ожидаемый результат**: + - Диалог закрывается, дата окончания trial продлевается на 14 дней. + - В журнал аудита добавляется запись с SHA-256 хешем и введенным обоснованием. + +--- + +### Сценарий 3: Фильтрация подписок, истекающих в течение 7 дней +- **Предусловия**: Оператор открывает раздел `/control/billing`. +- **Шаги**: + 1. Активировать быстрый фильтр `"Истекают в течение 7 дней"`. +- **Ожидаемый результат**: + - Таблица фильтруется, остаётся только «ТехноПарк Восток» (срок окончания подписки через 2 дня). + - Отображается сумма регулярного платежа в рублях через `MoneyDisplay`. + +--- + +### Сценарий 4: Мониторинг терминалов и выявление устаревших Android-касс +- **Предусловия**: Переход в `/control/installations`. +- **Шаги**: + 1. Нажать на быстрый фильтр `"Устаревшие версии"`. + 2. Проверить строки с бейджем `"Устарело"` (POS-терминал кассы №4, Android 11, клиент v1.8.4). + 3. Нажать действие `"Отозвать токен"`. +- **Ожидаемый результат**: + - Открывается окно подтверждения с фиксацией отзыва токена устройства. + +--- + +### Сценарий 5: Мониторинг узлов кластера и сбой Server Monitor (Circuit Breaker) +- **Предусловия**: Переход в `/control/infrastructure`. +- **Шаги**: + 1. Проверить список нод: `node-krona-prod-01`, `node-krona-prod-02`, `node-krona-prod-03`. + 2. В шапке нажать кнопку симуляции `"Simulate SM Outage"`. +- **Ожидаемый результат**: + - Вверху экрана появляется предупреждающий баннер `Server Monitor Unreachable (Fallback to Local Cache)`. + - Все экраны сохраняют интерактивность и читают данные из последнего валидного снимка IndexedDB. + +--- + +### Сценарий 6: Создание инцидента из критического алерта +- **Предусловия**: Переход в `/control/incidents`. +- **Шаги**: + 1. В списке обнаруженных аномалий выбрать `"Деградация p99 latency в кластере баз данных"`. + 2. Нажать `"Создать инцидент P1"`. + 3. Заполнить описание и назначить дежурного инженера. +- **Ожидаемый результат**: + - Инцидент регистрируется со статусом `Investigating` и уровнем `P1 Critical`. + +--- + +### Сценарий 7: Публикация таргетированного системного оповещения +- **Предусловия**: Переход в `/control/announcements`. +- **Шаги**: + 1. Заполнить форму объявления: заголовок `"Плановое ночное техобслуживание"`, уровень `Warning`. + 2. Нажать кнопку `"Опубликовать"`. + 3. В модальном окне ввести причину публикации. +- **Ожидаемый результат**: + - Оповещение появляется в списке активных трансляций. + +--- + +### Сценарий 8: Управление Rollout-конвейером (Пауза / Возобновление) +- **Предусловия**: Переход в `/control/modules`. +- **Шаги**: + 1. Выбрать модуль с активной раскаткой («Омниканальные коммуникации», фаза Pilot). + 2. Нажать `"Поставить на паузу"`. + 3. Ввести причину в модальном диалоге. +- **Ожидаемый результат**: + - Статус раскатки переходит в `"На паузе"`, конвейер замораживается. + +--- + +### Сценарий 9: Смена роли оператора и проверка соблюдения RBAC +- **Предусловия**: Открыт любой раздел Control Center. +- **Шаги**: + 1. В переключателе сессии в шапке выбрать роль `"Аудитор безопасности"`. + 2. Перейти в раздел `/control/modules`. +- **Ожидаемый результат**: + - Кнопки запуска и остановки раскатки становятся неактивными (`disabled`) для аудитора. + - Повторное переключение на `"Владелец платформы"` восстанавливает полный доступ. + +--- + +### Сценарий 10: Сохранение состояния при перезагрузке страницы (IndexedDB) +- **Предусловия**: В журнал аудита добавлены записи операторских действий. +- **Шаги**: + 1. Зафиксировать количество строк в журнале `/control/audit`. + 2. Выполнить полную перезагрузку страницы в браузере (`F5` / `page.reload()`). +- **Ожидаемый результат**: + - Интерфейс восстанавливает данные из локальной базы IndexedDB. + - Количество строк журнала аудита и SHA-256 хеши сохраняются неизменными. diff --git a/docs/handoff/control-center/DEPLOYMENT-DEMO.md b/docs/handoff/control-center/DEPLOYMENT-DEMO.md new file mode 100644 index 0000000..c03e6a5 --- /dev/null +++ b/docs/handoff/control-center/DEPLOYMENT-DEMO.md @@ -0,0 +1,136 @@ +# Руководство по развёртыванию Krona Control Center на VPS + +## 1. Целевая инфраструктура и топология + +| Параметр | Значение | Описание | +| :--- | :--- | :--- | +| **Домен** | `https://kccdemo.ochenstarik.ru` | Публичный защищённый домен демонстрационного стенда | +| **IP-адрес VPS** | `178.212.13.102` | Целевой сервер развёртывания | +| **Системный пользователь** | `kcc` | Изолированный непривилегированный Linux-пользователь | +| **Директория релизов** | `/srv/kccdemo/releases/` | Версионированные каталоги сборок | +| **Символическая ссылка** | `/srv/kccdemo/current` | Указывает на активный релиз (atomic switch) | +| **Логи Nginx** | `/var/log/nginx/kccdemo_access.log` | Доступ и аудит веб-сервера | + +--- + +## 2. Статус внешнего подключения и диагностика доступа (Pre-flight Blocker) + +В ходе подготовки развёртывания была выполнена сетевая диагностика хоста `178.212.13.102`: + +1. **Сетевая доступность (Ping & Port 22)**: + - Хост `178.212.13.102` доступен, порт 22 (OpenSSH) открыт и принимает TCP-соединения. +2. **Аутентификация по SSH**: + - Попытка подключения: `ssh -i ~/.ssh/id_rsa kcc@178.212.13.102` + - Ответ сервера: `Permission denied (publickey)`. +3. **Причина блокировки**: + - Сервер VPS настроен на строгую аутентификацию исключительно по SSH-ключам (`PasswordAuthentication no`). + - Публичный ключ агента/рабочей станции не добавлен в файл `/home/kcc/.ssh/authorized_keys` на удаленном сервере. +4. **Решение для администратора / владельца платформы**: + - Вариант А: Добавить публичный ключ локальной машины в `/home/kcc/.ssh/authorized_keys` на VPS `178.212.13.102`. + - Вариант Б: Скопировать подготовленный каталог `deploy/kcc/` и директорию `dist/` на сервер через локальный доступ администратора и запустить `/srv/kccdemo/deploy-kcc.sh`. + +--- + +## 3. Автоматизированный скрипт развёртывания (`deploy/kcc/deploy-kcc.sh`) + +Скрипт обеспечивает атомарный деплой с нулевым временем простоя: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +APP_DIR="/srv/kccdemo" +RELEASES_DIR="$APP_DIR/releases" +CURRENT_LINK="$APP_DIR/current" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +NEW_RELEASE_DIR="$RELEASES_DIR/$TIMESTAMP" + +echo "=== [KCC Deploy] Starting atomic release $TIMESTAMP ===" + +mkdir -p "$NEW_RELEASE_DIR" +cp -r ./dist/* "$NEW_RELEASE_DIR/" + +# Atomic switch +ln -sfn "$NEW_RELEASE_DIR" "$CURRENT_LINK" + +# Keep last 3 releases +echo "=== [KCC Deploy] Pruning older releases (retaining last 3) ===" +cd "$RELEASES_DIR" +ls -1dt 20* | tail -n +4 | xargs -r rm -rf + +echo "=== [KCC Deploy] Verifying local health ===" +curl -sk https://127.0.0.1/control/gate -H "Host: kccdemo.ochenstarik.ru" | grep -q "Krona Control Center" && echo "Health check: PASSED" + +echo "=== [KCC Deploy] Release $TIMESTAMP successfully active! ===" +``` + +--- + +## 4. Конфигурация Nginx (`deploy/kcc/nginx-kccdemo.conf`) + +Конфигурация включает заголовки безопасности, поддержку SPA маршрутизации и SSL: + +```nginx +server { + listen 80; + server_name kccdemo.ochenstarik.ru; + return 301 https://$host$request_uri; +} + +server { + listen 443 ssl http2; + server_name kccdemo.ochenstarik.ru; + + ssl_certificate /etc/letsencrypt/live/kccdemo.ochenstarik.ru/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/kccdemo.ochenstarik.ru/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + root /srv/kccdemo/current; + index index.html; + + # Security Headers + add_header X-Frame-Options "DENY" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + + # Gzip Compression + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml; + + # Static Assets Caching + location /assets/ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # SPA Routing Fallback + location / { + try_files $uri $uri/ /index.html; + } + + access_log /var/log/nginx/kccdemo_access.log; + error_log /var/log/nginx/kccdemo_error.log; +} +``` + +--- + +## 5. Процедура мгновенного отката (Instant Rollback) + +В случае необходимости немедленного отката к предыдущей стабильной версии: + +```bash +cd /srv/kccdemo +PREVIOUS_RELEASE=$(ls -1dt releases/20* | sed -n '2p') +if [ -n "$PREVIOUS_RELEASE" ]; then + echo "Rolling back to: $PREVIOUS_RELEASE" + ln -sfn "/srv/kccdemo/$PREVIOUS_RELEASE" /srv/kccdemo/current + systemctl reload nginx + echo "Rollback completed." +else + echo "No previous release found to rollback." +fi +``` diff --git a/docs/handoff/control-center/FRONTEND-CONTRACTS.md b/docs/handoff/control-center/FRONTEND-CONTRACTS.md new file mode 100644 index 0000000..e3422ef --- /dev/null +++ b/docs/handoff/control-center/FRONTEND-CONTRACTS.md @@ -0,0 +1,80 @@ +# Фронтенд-контракты и Модели данных Krona Control Center + +## 1. Концепция Minor Currency Units (Минорные единицы валюты) + +Для исключения ошибок округления чисел с плавающей точкой (`0.1 + 0.2 !== 0.3`) все финансовые поля в Control Center хранятся исключительно в минорных единицах (копейки): + +- **Хранение**: целочисленные значения `number` (`priceMonthlyMinor`, `mrrMinor`, `amountMinor`). +- **Пример**: `149 000 руб.` представляется как `14900000` (копеек). +- **Форматирование**: компонент `` производит безопасное форматирование с помощью `Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB' })`, деля число на 100 исключительно на этапе рендеринга строки. + +--- + +## 2. Неизменяемый криптографический аудит (SHA-256 Hash Chaining) + +Каждое операторское действие формирует блок в локальной цепочке аудита. Порядок связывания: + +```typescript +export interface OperatorAuditEvent { + id: string; + timestamp: string; + operatorRole: OperatorRole; + operatorName: string; + actionType: OperatorActionType; + entityType: 'organization' | 'installation' | 'node' | 'module' | 'announcement' | 'incident' | 'system'; + entityId: string; + reason: string; + impactSummary: string; + diffBeforeAfter?: { + before: Record; + after: Record; + }; + clientIp?: string; + previousHash: string; // Ссылка на хеш предыдущей записи + eventHash: string; // SHA-256(previousHash + timestamp + operatorRole + actionType + entityId + reason) +} +``` + +### Алгоритм вычисления хеша: +```typescript +export async function computeEventHash( + previousHash: string, + timestamp: string, + operatorRole: string, + actionType: string, + entityId: string, + reason: string +): Promise { + const payload = `${previousHash}|${timestamp}|${operatorRole}|${actionType}|${entityId}|${reason}`; + const msgUint8 = new TextEncoder().encode(payload); + const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8); + const hashArray = Array.from(new Uint8Array(hashBuffer)); + return hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); +} +``` + +--- + +## 3. Схема постоянного хранилища IndexedDB + +База данных `krona_control_center_db` (версия 1) содержит следующие хранилища объектов (Object Stores): + +1. `organizations`: карточки тенантов платформы (`PlatformOrganization`). +2. `module_instances`: установленные модули и версии (`ModuleInstance`). +3. `installations`: физические устройства, кассы, терминалы (`InstallationDevice`). +4. `nodes`: серверные узлы кластера (`ClusterNode`). +5. `announcements`: сервисные сообщения и баннеры (`SystemAnnouncement`). +6. `incidents`: инциденты платформы (`PlatformIncident`). +7. `audit_log`: цепочка блоков аудита с индексом по `timestamp`. +8. `settings`: глобальные флаги (maintenance mode, circuit breaker test flags). + +--- + +## 4. Контракт устойчивости Server Monitor Outage (Circuit Breaker) + +При отказе внешнего сервиса мониторинга кластера: +1. `useKccStore.serverMonitorOutage = true`. +2. Интерфейс переходит в режим graceful degradation: + - Отображается аварийный баннер `ServerMonitorOutageBanner` с индикатором «Используются локальные кэшированные метрики». + - Метрики узлов замораживаются на последнем известном валидном снимке из IndexedDB. + - Запрещается автоматическая эвакуация нод без явного ручного подтверждения `force_offline_drain`. diff --git a/docs/handoff/control-center/PERMISSIONS.md b/docs/handoff/control-center/PERMISSIONS.md new file mode 100644 index 0000000..b70cb26 --- /dev/null +++ b/docs/handoff/control-center/PERMISSIONS.md @@ -0,0 +1,47 @@ +# Матрица ролей и разрешений (RBAC) Krona Control Center + +## 1. Инженерные роли операторов + +В Control Center реализована строгая ролевая модель, отражающая реальные функции дежурной эксплуатации, разработки и безопасности платформы: + +| Роль | Системный идентификатор | Описание | +| :--- | :--- | :--- | +| **Владелец платформы** | `platform_owner` | Полный неограниченный доступ ко всем контурам, инфраструктуре, биллингу и аварийным режимам. | +| **Администратор платформы** | `platform_admin` | Управление тенантами, эвакуация нод, рассылки, аварийные настройки (за исключением финансовых счетов). | +| **Оператор поддержки L2/L3** | `support_operator` | Диагностика тенантов, ведение инцидентов, просмотр инсталляций, выдача временных демо/trial. | +| **Менеджер биллинга** | `billing_manager` | Контроль задолженностей, выставление счетов, применение скидок, ручное продление подписок. | +| **Аудитор безопасности** | `security_auditor` | Read-only доступ ко всем экранам + полный доступ к неизменяемому криптографическому журналу аудита. Запрет на любые мутации. | +| **Релиз-инженер** | `release_manager` | Управление rollout-конвейером модулей, запуск Canary/Pilot/GA фаз, экстренная приостановка раскатки. | + +--- + +## 2. Гранулярные права (Permissions) + +- `control_center:read`: Просмотр базовых экранов (Обзор, Организации, Инсталляции). +- `control_center:write`: Редактирование параметров организаций, отправка рассылок. +- `control_center:billing_manage`: Операции с тарифами, счетами, продлением подписок. +- `control_center:node_evacuate`: Вывод узлов кластера из ротации (Drain/Evacuate). +- `control_center:incident_manage`: Создание инцидентов, изменение критичности, назначение ответственных. +- `control_center:rollout_manage`: Переключение стадий раскатки версий модулей платформы. +- `control_center:operator_audit`: Просмотр неизменяемого журнала аудита и экспорт крипто-цепочки. + +--- + +## 3. Матрица соответствия Ролей и Прав + +| Разрешение | `platform_owner` | `platform_admin` | `support_operator` | `billing_manager` | `security_auditor` | `release_manager` | +| :--- | :---: | :---: | :---: | :---: | :---: | :---: | +| `control_center:read` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| `control_center:write` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | +| `control_center:billing_manage` | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | +| `control_center:node_evacuate` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | +| `control_center:incident_manage` | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | +| `control_center:rollout_manage` | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | +| `control_center:operator_audit` | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | + +--- + +## 4. Контроль на уровне UI компонентов + +- При отсутствии необходимого разрешения интерактивные кнопки мутаций автоматически блокируются (`disabled={!canPerform}`) с поясняющим tooltip или атрибутом `title="Недостаточно прав для данной операции"`. +- Попытка программного вызова защищенного действия отклоняется на уровне сервис-слоя с генерацией исключения `PermissionDeniedError` и немедленной фиксацией в журнале безопасности. diff --git a/docs/handoff/control-center/ROUTES.md b/docs/handoff/control-center/ROUTES.md new file mode 100644 index 0000000..965ab6d --- /dev/null +++ b/docs/handoff/control-center/ROUTES.md @@ -0,0 +1,29 @@ +# Реестр маршрутов Krona Control Center + +## 1. Базовые маршруты и изоляция + +Все маршруты Control Center размещены в отдельном префиксе `/control/*` и изолированы от клиентских приложений платформы (`/app/*`) и лендинга (`/`). + +| Путь | Название | Компонент | Доступ (Минимальная роль) | Описание | +| :--- | :--- | :--- | :--- | :--- | +| `/control/gate` | PIN-шлюз авторизации | `ControlGatePage` | Публичный внутри подсети (ввод PIN) | Инженерный шлюз ввода операторского PIN (по умолчанию: `8492` для демо). Выдаёт сессионный токен `kcc_gate_pass`. | +| `/control` | Редирект в пульт | `ControlRouteGuard` | Любая подтверждённая роль | Автоматический редирект на `/control/overview` | +| `/control/overview` | Сводка платформы | `OverviewPage` | `support_operator`+ (`control_center:read`) | Общий дашборд здоровья платформы, метрик MRR, статусов нод и инцидентов | +| `/control/organizations` | Реестр тенантов | `OrganizationsPage` | `support_operator`+ (`control_center:read`) | Список организаций, фильтрация, быстрый поиск и вызов 360° Drawer | +| `/control/billing` | Биллинг и Подписки | `BillingPage` | `billing_manager`+ (`control_center:billing_manage`) | Реестр подписок, контроль просрочек, счета в minor units | +| `/control/installations` | Парк инсталляций | `InstallationsPage` | `support_operator`+ (`control_center:read`) | Мониторинг POS/Android/Desktop терминалов, отзыв токенов | +| `/control/nodes` | Узлы инфраструктуры | `NodesPage` | `platform_admin`+ (`control_center:node_evacuate`) | Мониторинг CPU/RAM кластера, эвакуация нод, тест Circuit Breaker | +| `/control/modules` | Rollout-конвейер | `ModulesPage` | `release_manager`+ (`control_center:rollout_manage`) | Управление версиями, запуск Canary/Pilot/GA фаз, пауза раскатки | +| `/control/incidents` | Инциденты и Алерты | `IncidentsPage` | `support_operator`+ (`control_center:incident_manage`) | Реестр инцидентов P1-P4, назначение дежурного, перевод статусов | +| `/control/broadcasts` | Системные рассылки | `BroadcastsPage` | `platform_admin`+ (`control_center:write`) | Отправка баннеров тенантам с таргетингом по тарифам и модулям | +| `/control/audit` | Журнал аудита | `AuditPage` | `security_auditor`+ (`control_center:operator_audit`) | Неизменяемый журнал операций с проверкой валидности SHA-256 хеш-цепочки | + +--- + +## 2. Шлюз защиты (ControlRouteGuard) + +Компонент `ControlRouteGuard` реализует многоуровневую защиту: +1. **Проверка PIN-доступа**: Читает сессионный флаг `sessionStorage.getItem('kcc_gate_pass')`. Если отсутствует — перенаправляет на `/control/gate`. +2. **Проверка сессии оператора**: Читает активную роль из `sessionStorage.getItem('kcc_operator_session')`. Если отсутствует — инициализирует сессию по умолчанию (`platform_owner`). +3. **Проверка гранулярных разрешений**: Для защищенных разделов валидирует наличие необходимого permission в текущей роли оператора. При отсутствии прав рендерит защитное уведомление с предложением сменить роль или запросить доступ. +4. **Error Boundary**: Все дочерние экраны обёрнуты в локальный обработчик ошибок с кнопкой сброса кэша и перезагрузки интерфейса. diff --git a/docs/handoff/control-center/STATES.md b/docs/handoff/control-center/STATES.md new file mode 100644 index 0000000..29d7e8b --- /dev/null +++ b/docs/handoff/control-center/STATES.md @@ -0,0 +1,62 @@ +# Матрица состояний и переходов Krona Control Center + +## 1. Состояния платформы (Platform Operation Modes) + +| Состояние | Индикатор | Поведение интерфейса | Допустимые действия | +| :--- | :--- | :--- | :--- | +| **Normal** | Зеленый бейдж `Operational` | Штатный режим работы, все метрики обновляются в реальном времени | Все операции разрешены согласно матрице RBAC | +| **Degraded** | Янтарный бейдж `Degraded Performance` | Отказ части вторичных систем (например, Server Monitor), метрики отображаются из локального кэша | Разрешены аварийные действия, выдача оповещений | +| **Emergency Maintenance** | Красный пульсирующий баннер `Platform Maintenance Active` | Платформа переведена в аварийный сервисный режим; клиентские входы заблокированы информационным экраном | Доступны только действия владельца платформы по восстановлению | + +--- + +## 2. Статусы клиентских организаций (Tenants) + +```mermaid +stateDiagram-v2 + [*] --> Trial: Регистрация / Демо + Trial --> Active: Оплата подписки + Trial --> Frozen: Истечение 14 дней без оплаты + Active --> PastDue: Сбой списания (Grace period 7 дней) + PastDue --> Active: Успешная повторная оплата + PastDue --> Frozen: Неуплата по истечении льготного периода + Frozen --> Active: Ручная разморозка / Погашение долга + Frozen --> Terminated: 90 дней неактивности / Расторжение + Terminated --> [*] +``` + +- **Trial**: Доступны базовые модули, ограниченный лимит пользователей. Возможно продление через `Выдать Trial +14 дней`. +- **Active**: Полнофункциональный доступ в рамках оплаченного тарифа. +- **Past Due**: Доступ сохраняется, отображается предупреждающий баннер в клиентском приложении. +- **Frozen**: Блокировка доступа всех пользователей тенанта (кроме чтения счетов). Требует обоснования при ручной заморозке. +- **Terminated**: Доступ аннулирован, данные архивированы. + +--- + +## 3. Фазы Rollout-конвейера модулей + +1. **Canary (10%)**: Первичное развёртывание новой версии модуля на 10% тестовых тенантов. +2. **Pilot (30%)**: Расширение на пилотную группу организаций. +3. **Staged (50%)**: Поэтапная раскатка на половину инфраструктуры. +4. **General Availability (GA, 100%)**: Полный переход всех клиентов на новую версию. +5. **Paused**: Экстренная заморозка конвейера при обнаружении аномалий. +6. **Rolled Back**: Откат на стабильную предыдущую версию. + +--- + +## 4. Состояния узлов инфраструктуры (Cluster Nodes) + +- **Healthy**: CPU < 75%, RAM < 80%, p99 latency < 50ms. +- **Warning**: Превышение порогов загрузки, авто-скейлинг подов. +- **Critical**: Отказ сетевого интерфейса или дисковой подсистемы. +- **Draining**: Нода выводится из балансировщика, активные сессии мягко мигрируют. +- **Evacuated**: Узел изолирован, нагрузка отсутствует, доступен для регламентных работ. + +--- + +## 5. Статусы инсталляций и терминалов + +- **Online**: Устройство активно, пинг получен менее 2 минут назад. +- **Offline**: Пинг отсутствует более 10 минут. +- **Outdated**: Версия клиентского ПО ниже минимально допустимой платформой (требуется обновление). +- **Revoked**: Токен авторизации устройства отозван оператором платформы. diff --git a/docs/handoff/control-center/UX-SPEC.md b/docs/handoff/control-center/UX-SPEC.md new file mode 100644 index 0000000..0891ab8 --- /dev/null +++ b/docs/handoff/control-center/UX-SPEC.md @@ -0,0 +1,88 @@ +# Krona Control Center — UX Спецификация + +## 1. Архитектура и Назначение +Krona Control Center (KCC) — изолированный закрытый инженерный пульт владельца платформы Krona и дежурной инженерно-эксплуатационной команды. + +### Ключевые архитектурные принципы +- **Изоляция контура**: KCC полностью отделён от административного кабинета клиентской организации (`/app/*`) и публичных страниц (`/`, `/demo`). Доступ организован в отдельном пространстве путей `/control/*`. +- **Защита шлюзом**: Доступ закрыт через `ControlRouteGuard` и PIN-гейт (`/control/gate`), требующий подтверждения операторского доступа (сессионный токен `kcc_gate_pass` + `operator_session`). +- **Строгая модель ролей (RBAC)**: 6 специализированных инженерных ролей с гранулярными правами доступа (`control_center:read`, `control_center:write`, `control_center:billing_manage`, `control_center:node_evacuate`, `control_center:incident_manage`, `control_center:rollout_manage`, `control_center:operator_audit`). +- **Неизменяемый журнал аудита**: Любое опасное или мутирующее действие требует модального подтверждения с обязательным указанием причины (минимум 5 символов), фиксацией затронутых сущностей и записью в криптографически связанный SHA-256 хеш-блокчейн в IndexedDB (`krona_control_center_db`). +- **Устойчивость к сбоям инфраструктуры (Circuit Breaker)**: Поддержка offline-first и degraded режимов с кэшированием последнего снимка состояния в IndexedDB при недоступности внешних мониторов или сетевых сбоях. + +--- + +## 2. Навигация и Визуальная Иерархия + +### Навигационное древо +1. **Обзор платформы (`/control/overview`)**: + - Верхний статус-бар: Режим среды (Production), активная инженерная роль, индикатор синхронизации IndexedDB, кнопка аварийного режима (Maintenance), экстренный выход. + - Сводные KPI-метрики: активные организации, совокупный MRR, здоровье узлов кластера, активные инциденты и предупреждения. + - Виджеты оперативного контроля: критические алерты, статус rollout-конвейера, географическое распределение нагрузок. +2. **Организации и 360° Инспектор (`/control/organizations`)**: + - Таблица тенантов с фильтрацией по тарифным планам (`enterprise`, `business`, `starter`), статусам (`active`, `past_due`, `frozen`, `trial`) и быстрому поиску по названию/ИНН/домену. + - Вызов контекстного 360° инспектора (Drawer) без потери контекста таблицы. +3. **Биллинг и Подписки (`/control/billing`)**: + - Фильтры истекающих подписок (окно 7 дней, просроченные платежи). + - Сводка по Minor Units (копейки) с форматированием без плавающей точки. + - История платежей, выставление счетов, ручное продление trial. +4. **Инсталляции и Терминалы (`/control/installations`)**: + - Учёт парка POS/Android/Desktop терминалов и мобильных приложений. + - Мониторинг устаревших версий (flag `outdated`), времени последнего пинга и принудительный отзыв токенов сессий (`Revoke Token`). +5. **Инфраструктура и Узлы (`/control/nodes`)**: + - Мониторинг кластерных нод (CPU, RAM, Disk IO, p99 latency). + - Действие вывода ноды из ротации (`Drain / Evacuate Node`). + - Имитация сбоя сервера мониторинга для верификации Circuit Breaker. +6. **Rollout и Каталог модулей (`/control/modules`)**: + - Управление версиями модулей платформы. + - Фазы конвейера: `Canary (10%)`, `Pilot (30%)`, `Staged (50%)`, `GA (100%)`. + - Оперативные действия: `Start Rollout`, `Pause`, `Resume`, `Rollback`. +7. **Инциденты и Алерты (`/control/incidents`)**: + - Матрица тяжести: `P1 Critical`, `P2 Major`, `P3 Warning`, `P4 Info`. + - Эскалация, назначение дежурного инженера, перевод в `In Progress`, `Mitigated`, `Resolved`. +8. **Системные рассылки (`/control/broadcasts`)**: + - Таргетинг по тарифам и модулям тенантов. + - Уровни важности: `info`, `warning`, `critical_maintenance`. +9. **Журнал аудита (`/control/audit`)**: + - Хронологический реестр операций с проверкой валидности SHA-256 хеш-цепочки. + - Экспорт в CSV/JSON. + +--- + +## 3. Контекстный 360° Инспектор (Drawer) +Шторка детального инспектирования вызывается с правой стороны экрана (600px на десктопе, 100% на мобильных экранах): +- **Вкладка «Обзор»**: Карточка организации, ИНН, домен, дата создания, активный SLA, текущий баланс и лимиты пользователей. +- **Вкладка «Модули»**: Список подключенных сервисных модулей с версиями и статусами работоспособности. +- **Вкладка «Инсталляции»**: Привязанные терминалы и кассы с версиями клиента. +- **Вкладка «Биллинг»**: График выставления счетов, статус продления и скидки. +- **Панель быстрых действий оператора**: + - `Выдать Trial +14 дней` (требует подтверждения с фиксацией причины). + - `Заморозить доступ` / `Разморозить` (критическая операция). + - `Сбросить 2FA администраторов` (операция безопасности). + - `Экспорт данных тенанта` (GDPR/152-ФЗ compliance). + +--- + +## 4. Паттерн подтверждения опасных операций (ConfirmOperatorAction) +Любое деструктивное или влияющее на клиентов действие открывает диалоговое окно `ConfirmOperatorAction`: +1. **Предупреждение о последствиях**: Четкое перечисление затрагиваемых сущностей (например, «Будет заблокирован доступ 120 пользователей»). +2. **Обязательное обоснование (`action-reason-input`)**: Поле ввода причины выполнения с валидацией минимальной длины (не менее 5 символов). +3. **Кнопка подтверждения с семантическим цветом**: Красный (`bg-red-600`) для необратимых/блокирующих действий, янтарный (`bg-amber-600`) для сервисных операций. +4. **Хеширование записи аудита**: Запись немедленно хешируется с предыдущим хешем по схеме: + `hash = SHA-256(prevHash + timestamp + operatorRole + actionType + entityId + reason)` + и сохраняется в локальное постоянное хранилище IndexedDB. + +--- + +## 5. Дизайн-система: Темная инженерная тема +Интерфейс спроектирован по канонам современных Mission-Control дашбордов: +- **Цветовая палитра**: Глубокий slate/zinc фон (`bg-zinc-950`, `bg-zinc-900`), контрастные границы (`border-zinc-800`), четкая типографика (`text-zinc-100`, `text-zinc-400`). +- **Семантические акценты**: + - `Зеленый (Emerald)`: Нормальная работа узла, активная подписка, GA-статус. + - `Янтарный (Amber)`: Предупреждение, истекающий trial, пауза раскатки. + - `Красный (Rose/Red)`: P1 инцидент, отказ узла, заблокированная организация. + - `Синий/Фиолетовый (Indigo/Violet)`: Канареечные релизы, системные оповещения. +- **Адаптивность (Zero Horizontal Overflow)**: + - Desktop (1440×900+): Полноразмерный сайдбар, многоколоночные таблицы, плавающий Drawer 600px. + - Tablet (768×1024): Сворачиваемый сайдбар, горизонтальная прокрутка таблиц внутри изолированных контейнеров. + - Mobile (390×844): Компактный мобильный заголовок, off-canvas навигация, карточный вид для таблиц.