docs(control-center): add comprehensive handoff specifications and atomic zero-downtime deployment package
This commit is contained in:
parent
8e0f640673
commit
5489fc3b43
9 changed files with 705 additions and 0 deletions
68
deploy/kcc/deploy-kcc.sh
Normal file
68
deploy/kcc/deploy-kcc.sh
Normal file
|
|
@ -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 "================================================================="
|
||||||
78
deploy/kcc/nginx-kccdemo.conf
Normal file
78
deploy/kcc/nginx-kccdemo.conf
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
117
docs/handoff/control-center/ACCEPTANCE-TESTS.md
Normal file
117
docs/handoff/control-center/ACCEPTANCE-TESTS.md
Normal file
|
|
@ -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 хеши сохраняются неизменными.
|
||||||
136
docs/handoff/control-center/DEPLOYMENT-DEMO.md
Normal file
136
docs/handoff/control-center/DEPLOYMENT-DEMO.md
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
# Руководство по развёртыванию Krona Control Center на VPS
|
||||||
|
|
||||||
|
## 1. Целевая инфраструктура и топология
|
||||||
|
|
||||||
|
| Параметр | Значение | Описание |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| **Домен** | `https://kccdemo.ochenstarik.ru` | Публичный защищённый домен демонстрационного стенда |
|
||||||
|
| **IP-адрес VPS** | `178.212.13.102` | Целевой сервер развёртывания |
|
||||||
|
| **Системный пользователь** | `kcc` | Изолированный непривилегированный Linux-пользователь |
|
||||||
|
| **Директория релизов** | `/srv/kccdemo/releases/<TIMESTAMP>` | Версионированные каталоги сборок |
|
||||||
|
| **Символическая ссылка** | `/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
|
||||||
|
```
|
||||||
80
docs/handoff/control-center/FRONTEND-CONTRACTS.md
Normal file
80
docs/handoff/control-center/FRONTEND-CONTRACTS.md
Normal file
|
|
@ -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` (копеек).
|
||||||
|
- **Форматирование**: компонент `<MoneyDisplay amountMinor={14900000} currency="RUB" />` производит безопасное форматирование с помощью `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<string, unknown>;
|
||||||
|
after: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
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<string> {
|
||||||
|
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`.
|
||||||
47
docs/handoff/control-center/PERMISSIONS.md
Normal file
47
docs/handoff/control-center/PERMISSIONS.md
Normal file
|
|
@ -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` и немедленной фиксацией в журнале безопасности.
|
||||||
29
docs/handoff/control-center/ROUTES.md
Normal file
29
docs/handoff/control-center/ROUTES.md
Normal file
|
|
@ -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**: Все дочерние экраны обёрнуты в локальный обработчик ошибок с кнопкой сброса кэша и перезагрузки интерфейса.
|
||||||
62
docs/handoff/control-center/STATES.md
Normal file
62
docs/handoff/control-center/STATES.md
Normal file
|
|
@ -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**: Токен авторизации устройства отозван оператором платформы.
|
||||||
88
docs/handoff/control-center/UX-SPEC.md
Normal file
88
docs/handoff/control-center/UX-SPEC.md
Normal file
|
|
@ -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 навигация, карточный вид для таблиц.
|
||||||
Loading…
Reference in a new issue