system/@bot-platform.system/ROLES_PERMISSIONS.md

РОЛИ И ПРАВА ДОСТУПА

Bot Platform - Система управления доступом

Версия: 1.0
Дата: 2025-12-27
Связано: ARCHITECTURE.md, UI_SCREENS.md


ОБЗОР

Система ролей для управления доступом к функциям платформы:
- 5 ролей с разными уровнями доступа
- Гибкое назначение операторов на диалоги
- Аудит всех действий пользователей
- Интеграция с существующей архитектурой


РОЛИ

1. OWNER (Владелец)

Описание: Полный контроль над платформой

Права доступа:
- ✅ Все права Admin
- ✅ Управление пользователями (создание, удаление, блокировка)
- ✅ Назначение ролей (включая Admin)
- ✅ Доступ к биллингу и лицензиям
- ✅ Удаление ботов и данных
- ✅ Экспорт/импорт всей системы
- ✅ Доступ к логам и аудиту

Количество: 1-2 на инсталляцию

UI доступ:

✅ Dashboard            ✅ Bots                ✅ Chats
✅ Channels             ✅ Knowledge Base      ✅ Analytics
✅ Settings             ✅ Users & Roles       ✅ Billing
✅ System Logs          ✅ Backups

2. ADMIN (Администратор)

Описание: Управление ботами и контентом, но не системой

Права доступа:
- ✅ Создание/редактирование/деактивация ботов
- ✅ Настройка AI-моделей и промптов
- ✅ Управление базой знаний
- ✅ Подключение мессенджеров
- ✅ Просмотр аналитики по всем ботам
- ✅ Назначение операторов
- ✅ Настройка сценариев
- ❌ Удаление ботов (только Owner)
- ❌ Управление пользователями
- ❌ Доступ к биллингу

Количество: 1-5 на компанию

UI доступ:

✅ Dashboard            ✅ Bots (create/edit)  ✅ Chats (view all)
✅ Channels             ✅ Knowledge Base      ✅ Analytics
✅ Bot Settings         ❌ Users & Roles       ❌ Billing

Типичный пользователь: Руководитель отдела продаж, CRM-менеджер


3. MANAGER (Менеджер)

Описание: Мониторинг и координация работы операторов

Права доступа:
- ✅ Просмотр всех диалогов
- ✅ Подключение к диалогам (режим наблюдения)
- ✅ Перераспределение диалогов между операторами
- ✅ Просмотр аналитики по операторам
- ✅ Редактирование базы знаний
- ✅ Просмотр настроек ботов
- ❌ Создание/изменение ботов
- ❌ Настройка AI-моделей
- ❌ Подключение каналов

Количество: 2-10 на компанию

UI доступ:

✅ Dashboard            ⚠️ Bots (read-only)    ✅ Chats (all)
❌ Channels             ✅ Knowledge Base      ✅ Analytics (team)
⚠️ Bot Settings (view) ❌ Users & Roles       ❌ Billing

Типичный пользователь: Старший менеджер, супервайзер, руководитель смены


4. OPERATOR (Оператор)

Описание: Ведение диалогов с клиентами

Права доступа:
- ✅ Просмотр назначенных диалогов
- ✅ Ответы в режиме Assistant (одобрение предложений бота)
- ✅ Ответы в режиме Manual (без бота)
- ✅ Подключение бота к диалогу
- ✅ Эскалация диалога менеджеру
- ✅ Просмотр истории диалога
- ✅ Использование шаблонов из базы знаний
- ❌ Просмотр чужих диалогов (если не назначены)
- ❌ Изменение настроек бота
- ❌ Просмотр аналитики по другим операторам

Количество: Неограниченно

UI доступ:

⚠️ Dashboard (own)       Bots                 Chats (assigned)
 Channels             ⚠️ Knowledge (view)    ⚠️ Analytics (own)
 Bot Settings          Users & Roles        Billing

Типичный пользователь: Менеджер по продажам, оператор поддержки


5. VIEWER (Наблюдатель)

Описание: Только чтение для аналитики и отчётов

Права доступа:
- ✅ Просмотр Dashboard
- ✅ Просмотр аналитики
- ✅ Экспорт отчётов
- ✅ Просмотр списка ботов
- ❌ Доступ к диалогам
- ❌ Изменение настроек
- ❌ Создание контента

Количество: Неограниченно

UI доступ:

✅ Dashboard            ⚠️ Bots (list only)    ❌ Chats
❌ Channels             ❌ Knowledge Base      ✅ Analytics (read)
❌ Bot Settings         ❌ Users & Roles       ❌ Billing

Типичный пользователь: Руководитель, аналитик, внешний консультант


МАТРИЦА ПРАВ ДОСТУПА

По функциям

Функция Owner Admin Manager Operator Viewer
БОТЫ
Создать бота
Редактировать бота
Удалить бота
Деактивировать бота
Просмотр настроек ⚠️
Изменить AI-модель
Изменить промпты
ДИАЛОГИ
Просмотр всех
Просмотр своих
Ответить клиенту
Назначить оператора
Закрыть диалог
Экспорт диалога ⚠️
КАНАЛЫ
Подключить канал
Отключить канал
Просмотр токенов
БАЗА ЗНАНИЙ
Создать статью
Редактировать
Удалить статью
Просмотр
АНАЛИТИКА
Вся компания
Своя команда
Свои данные
Экспорт отчётов ⚠️
ПОЛЬЗОВАТЕЛИ
Создать
Изменить роль
Заблокировать
Просмотр списка ⚠️ ⚠️
СИСТЕМА
Настройки ⚠️
Биллинг
Логи и аудит
Бэкапы

Легенда:
- ✅ Полный доступ
- ⚠️ Ограниченный доступ
- ❌ Нет доступа


НАЗНАЧЕНИЕ ОПЕРАТОРОВ

Режимы назначения

1. Ручное назначение (Manual Assignment)

Кто назначает: Manager, Admin, Owner

Процесс:
1. Новый диалог появляется в очереди "Неназначенные"
2. Менеджер выбирает оператора из списка
3. Диалог переходит в очередь оператора
4. Оператор получает уведомление

UI:

┌─────────────────────────────────────────┐
│ 📋 Неназначенные диалоги (8)            │
├─────────────────────────────────────────┤
│ [14:23] Иван Петров                     │
│ "Нужна консультация по товару"          │
│                                         │
│ Назначить на:                           │
│ [▼ Выбрать оператора]                   │
│ ○ Анна (онлайн, 3 диалога)              │
│ ○ Мария (онлайн, 2 диалога)             │
│ ○ Сергей (не в сети)                    │
│                                         │
│ [✅ Назначить]                           │
└─────────────────────────────────────────┘

2. Автоназначение (Auto Assignment)

Настройка: Admin в Bot Settings → Assignment Rules

Стратегии:

A. Round Robin (по кругу)

assignment:
  strategy: round_robin
  pool:
    - operator_id: 123
    - operator_id: 456
    - operator_id: 789
  only_online: true

Б. По нагрузке (Least Active)

assignment:
  strategy: least_active
  pool: [123, 456, 789]
  max_concurrent: 5

В. По специализации (Skill-based)

assignment:
  strategy: skill_based
  rules:
    - if:
        channel: vip_telegram
      assign_to: [123]  # VIP-менеджер
    - if:
        bot_stage: cold
      assign_to: [456, 789]  # Junior операторы
    - if:
        bot_stage: hot
      assign_to: [123, 234]  # Senior операторы

Г. По доступности (First Available)

assignment:
  strategy: first_available
  pool: [123, 456, 789]
  timeout_seconds: 30  # Если не ответил — следующему

3. Самоназначение (Self Assignment)

Описание: Операторы сами берут диалоги из общей очереди

Процесс:
1. Диалог в статусе "Waiting"
2. Оператор видит в списке "Доступные"
3. Нажимает "Взять диалог"
4. Диалог закрепляется за оператором

UI для оператора:

┌─────────────────────────────────────────┐
│ 📬 Доступные диалоги (5)                │
├─────────────────────────────────────────┤
│ [14:30] Елена Смирнова                  │
│ "Подскажите по доставке"                │
│ ⏱️ Ждёт 2 мин                            │
│ [🟢 Взять диалог]                        │
├─────────────────────────────────────────┤
│ [14:28] Дмитрий К.                      │
│ "Есть ли скидки на опт?"                │
│ ⏱️ Ждёт 4 мин                            │
│ [🟢 Взять диалог]                        │
└─────────────────────────────────────────┘

4. Эскалация (Escalation)

Когда: Оператор не может решить вопрос

Процесс:
1. Оператор нажимает "Эскалировать"
2. Выбирает причину и адресата (Manager/специалист)
3. Менеджер получает уведомление
4. Может подключиться к диалогу или переназначить

UI для оператора:

┌─────────────────────────────────────────┐
 🆘 Эскалация диалога                    
├─────────────────────────────────────────┤
 Причина:                                
  Технический вопрос                    
  Требует скидку >20%                   
  Жалоба                                
  Другое: [________________]            
                                         
 Эскалировать на:                        
  Мой менеджер (Анна Петрова)           
  Руководитель отдела                   
  Специалист по ценам                   
                                         
 Комментарий:                            
 [Клиент просит 25% скидку на           │
│  крупный заказ 500,000₽]                
                                         
 [✅ Эскалировать] [❌ Отмена]            
└─────────────────────────────────────────┘

БАЗА ДАННЫХ

Новые таблицы

-- Пользователи системы
CREATE TABLE platform_users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    full_name VARCHAR(255),
    role VARCHAR(50) NOT NULL,  -- owner, admin, manager, operator, viewer

    -- Настройки
    timezone VARCHAR(50) DEFAULT 'UTC',
    language VARCHAR(10) DEFAULT 'ru',

    -- Статус
    is_active BOOLEAN DEFAULT true,
    is_online BOOLEAN DEFAULT false,
    last_seen TIMESTAMP,

    -- Лимиты для operator
    max_concurrent_chats INTEGER DEFAULT 5,

    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

-- Права доступа (для гибкой настройки)
CREATE TABLE user_permissions (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES platform_users(id) ON DELETE CASCADE,
    permission VARCHAR(100) NOT NULL,  -- bots.create, chats.view_all, etc.
    granted BOOLEAN DEFAULT true,

    UNIQUE(user_id, permission)
);

-- Логи действий (аудит)
CREATE TABLE user_activity_log (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES platform_users(id),
    action VARCHAR(100) NOT NULL,  -- bot.create, message.send, user.block
    target_type VARCHAR(50),  -- bot, chat, user
    target_id INTEGER,
    details JSONB,
    ip_address VARCHAR(45),

    created_at TIMESTAMP DEFAULT NOW()
);

-- Назначение операторов (расширение chat_conversations)
ALTER TABLE chat_conversations ADD COLUMN assigned_to INTEGER REFERENCES platform_users(id);
ALTER TABLE chat_conversations ADD COLUMN assigned_at TIMESTAMP;
ALTER TABLE chat_conversations ADD COLUMN assigned_by INTEGER REFERENCES platform_users(id);

-- Онлайн статус операторов
CREATE TABLE operator_status (
    user_id INTEGER PRIMARY KEY REFERENCES platform_users(id),
    status VARCHAR(50) DEFAULT 'offline',  -- online, away, busy, offline
    status_message TEXT,
    active_chats_count INTEGER DEFAULT 0,
    updated_at TIMESTAMP DEFAULT NOW()
);

Индексы для производительности

-- Быстрый поиск по ролям
CREATE INDEX idx_users_role ON platform_users(role) WHERE is_active = true;

-- Поиск онлайн операторов
CREATE INDEX idx_users_online ON platform_users(is_online) WHERE role = 'operator';

-- Аудит по пользователю и времени
CREATE INDEX idx_activity_user_time ON user_activity_log(user_id, created_at DESC);

-- Диалоги оператора
CREATE INDEX idx_chats_assigned ON chat_conversations(assigned_to, status);

ПРАВА ДОСТУПА (детализация)

Формат записи permission

Структура: {resource}.{action}

Примеры:

bots.create                  # Создание бота
bots.edit                    # Редактирование бота
bots.delete                  # Удаление бота
bots.view                    # Просмотр настроек

chats.view_all               # Просмотр всех диалогов
chats.view_assigned          # Только назначенные
chats.assign                 # Назначение операторов
chats.message_send           # Отправка сообщений

channels.connect             # Подключение каналов
channels.disconnect          # Отключение

knowledge.create             # Создание статей
knowledge.edit               # Редактирование
knowledge.delete             # Удаление
knowledge.view               # Просмотр

analytics.view_all           # Вся аналитика
analytics.view_team          # Команда
analytics.view_own           # Свои данные
analytics.export             # Экспорт отчётов

users.create                 # Создание пользователей
users.edit                   # Редактирование
users.delete                 # Удаление
users.block                  # Блокировка

settings.view                # Просмотр настроек
settings.edit                # Изменение
billing.view                 # Просмотр биллинга
billing.edit                 # Изменение тарифа

system.logs                  # Доступ к логам
system.backups               # Бэкапы

Стандартные наборы прав по ролям

ROLE_PERMISSIONS = {
    'owner': ['*'],  # Все права

    'admin': [
        'bots.*',                 # Все действия с ботами
        'chats.view_all',
        'chats.assign',
        'chats.message_send',
        'channels.*',
        'knowledge.*',
        'analytics.view_all',
        'analytics.export',
        'settings.view',
        'settings.edit',
    ],

    'manager': [
        'bots.view',
        'chats.view_all',
        'chats.assign',
        'chats.message_send',
        'knowledge.create',
        'knowledge.edit',
        'knowledge.view',
        'analytics.view_all',
        'analytics.export',
    ],

    'operator': [
        'chats.view_assigned',
        'chats.message_send',
        'knowledge.view',
        'analytics.view_own',
    ],

    'viewer': [
        'bots.view',
        'analytics.view_all',
        'analytics.export',
    ],
}

MIDDLEWARE ДЛЯ ПРОВЕРКИ ПРАВ

Python (FastAPI)

from functools import wraps
from fastapi import HTTPException, Depends

async def check_permission(user_id: int, permission: str) -> bool:
    """Проверить право пользователя"""

    # Получить роль пользователя
    user = await db.fetch_one(
        "SELECT role FROM platform_users WHERE id = $1 AND is_active = true",
        user_id
    )

    if not user:
        return False

    role = user['role']

    # Owner имеет все права
    if role == 'owner':
        return True

    # Проверить стандартные права роли
    role_perms = ROLE_PERMISSIONS.get(role, [])

    # Точное совпадение
    if permission in role_perms:
        return True

    # Wildcard (bots.* покрывает bots.create)
    resource = permission.split('.')[0]
    if f"{resource}.*" in role_perms:
        return True

    # Проверить кастомные права
    custom = await db.fetch_one(
        """
        SELECT granted FROM user_permissions
        WHERE user_id = $1 AND permission = $2
        """,
        user_id, permission
    )

    if custom:
        return custom['granted']

    return False


def require_permission(permission: str):
    """Декоратор для проверки прав"""
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, current_user: dict = Depends(get_current_user), **kwargs):
            has_perm = await check_permission(current_user['id'], permission)

            if not has_perm:
                raise HTTPException(
                    status_code=403,
                    detail=f"Permission denied: {permission}"
                )

            return await func(*args, current_user=current_user, **kwargs)
        return wrapper
    return decorator


# Использование в API
@app.post("/bots")
@require_permission("bots.create")
async def create_bot(bot_data: BotCreate, current_user: dict):
    """Создать бота (только Admin/Owner)"""
    # ... создание бота
    pass


@app.get("/chats")
async def list_chats(current_user: dict):
    """Список диалогов (видимость зависит от роли)"""

    if await check_permission(current_user['id'], 'chats.view_all'):
        # Manager/Admin/Owner видят всё
        query = "SELECT * FROM chat_conversations"

    elif await check_permission(current_user['id'], 'chats.view_assigned'):
        # Operator видит только свои
        query = """
            SELECT * FROM chat_conversations
            WHERE assigned_to = $1
        """
        # ... выполнить с current_user['id']

    else:
        raise HTTPException(403, "No permission to view chats")

АУДИТ ДЕЙСТВИЙ

Логирование

async def log_user_action(
    user_id: int,
    action: str,
    target_type: str = None,
    target_id: int = None,
    details: dict = None,
    ip_address: str = None
):
    """Записать действие пользователя в лог"""

    await db.execute(
        """
        INSERT INTO user_activity_log
        (user_id, action, target_type, target_id, details, ip_address)
        VALUES ($1, $2, $3, $4, $5, $6)
        """,
        user_id, action, target_type, target_id,
        json.dumps(details) if details else None,
        ip_address
    )

# Использование
@app.post("/bots")
@require_permission("bots.create")
async def create_bot(bot_data: BotCreate, current_user: dict, request: Request):
    bot = await create_bot_in_db(bot_data)

    # Записать в аудит
    await log_user_action(
        user_id=current_user['id'],
        action='bot.create',
        target_type='bot',
        target_id=bot['id'],
        details={'bot_name': bot['name'], 'bot_type': bot['type']},
        ip_address=request.client.host
    )

    return bot

Просмотр логов (Owner)

UI Screen: System Logs

┌─────────────────────────────────────────────────────────────┐
 📊 ЛОГИ ПОЛЬЗОВАТЕЛЕЙ                                       
├─────────────────────────────────────────────────────────────┤
 Фильтры:                                                    
 Пользователь: [▼ Все]  Действие: [▼ Все]  Период: [7 дней] 
├─────────────────────────────────────────────────────────────┤
 2025-12-27 14:35:12 | admin@company.ru | bot.create         
    Создан бот "Sales Bot" (id: 15)                         
   IP: 192.168.1.105                                         
                                                             
 2025-12-27 14:22:03 | operator@company.ru | message.send    
    Отправлено сообщение в диалог #4521                     
   IP: 192.168.1.110                                         
                                                             
 2025-12-27 14:10:45 | manager@company.ru | chat.assign      
    Назначен оператор Anna на диалог #4520                  
   IP: 192.168.1.108                                         
                                                             
 2025-12-27 13:58:21 | admin@company.ru | channel.connect    
    Подключен канал Telegram @support_bot                   
   IP: 192.168.1.105                                         
├─────────────────────────────────────────────────────────────┤
 [Экспорт в CSV]                         Показано: 50 из 248 
└─────────────────────────────────────────────────────────────┘

UI ЭЛЕМЕНТЫ ПО РОЛЯМ

Главное меню (адаптивное)

def get_menu_for_role(role: str) -> list:
    """Вернуть пункты меню в зависимости от роли"""

    base_menu = [
        {'label': 'Dashboard', 'path': '/'},
    ]

    if role in ['owner', 'admin', 'manager']:
        base_menu.extend([
            {'label': 'Боты', 'path': '/bots'},
            {'label': 'Диалоги', 'path': '/chats'},
        ])

    if role == 'operator':
        base_menu.append({'label': 'Мои диалоги', 'path': '/chats/my'})

    if role in ['owner', 'admin']:
        base_menu.extend([
            {'label': 'Каналы', 'path': '/channels'},
            {'label': 'База знаний', 'path': '/knowledge'},
        ])

    if role in ['owner', 'admin', 'manager', 'viewer']:
        base_menu.append({'label': 'Аналитика', 'path': '/analytics'})

    if role == 'owner':
        base_menu.extend([
            {'label': 'Пользователи', 'path': '/users'},
            {'label': 'Настройки', 'path': '/settings'},
        ])

    return base_menu

Кнопки действий (условные)

<!-- Пример: Карточка бота -->
<div class="bot-card">
    <h3>{{ bot.name }}</h3>

    <div class="actions">
        <!-- Все видят -->
        <button>📊 Статистика</button>

        <!-- Только Admin/Owner -->
        {% if user.role in ['owner', 'admin'] %}
            <button>⚙️ Настроить</button>
            <button>🔗 Подключить канал</button>
        {% endif %}

        <!-- Только Owner -->
        {% if user.role == 'owner' %}
            <button class="danger">🗑️ Удалить</button>
        {% endif %}
    </div>
</div>

ИНТЕГРАЦИЯ С ARCHITECTURE.md

Изменения в существующих таблицах

-- bot_instances: добавить owner
ALTER TABLE bot_instances ADD COLUMN created_by INTEGER REFERENCES platform_users(id);
ALTER TABLE bot_instances ADD COLUMN updated_by INTEGER REFERENCES platform_users(id);

-- chat_conversations: расширить поля оператора
-- (уже добавлено assigned_to, assigned_at, assigned_by)

-- chat_messages: кто отправил
ALTER TABLE chat_messages ADD COLUMN sent_by INTEGER REFERENCES platform_users(id);

API методы (новые)

# Пользователи
POST   /api/users                    # Создать пользователя (Owner)
GET    /api/users                    # Список (Owner/Admin/Manager)
GET    /api/users/{id}               # Детали (Owner)
PATCH  /api/users/{id}               # Изменить (Owner)
DELETE /api/users/{id}               # Удалить (Owner)
POST   /api/users/{id}/block         # Заблокировать (Owner)

# Назначение операторов
POST   /api/chats/{id}/assign        # Назначить оператора (Manager+)
POST   /api/chats/{id}/take          # Взять диалог (Operator)
POST   /api/chats/{id}/escalate      # Эскалировать (Operator)

# Права доступа
GET    /api/permissions              # Список доступных прав (Owner)
GET    /api/users/{id}/permissions   # Права пользователя (Owner)
POST   /api/users/{id}/permissions   # Добавить право (Owner)
DELETE /api/users/{id}/permissions/{perm}  # Отозвать (Owner)

# Аудит
GET    /api/audit/logs               # Логи действий (Owner)
GET    /api/audit/users/{id}         # Логи пользователя (Owner)

ПЕРВОНАЧАЛЬНАЯ НАСТРОЙКА

1. Создание Owner при установке

# Скрипт setup_platform.py
python3 setup_platform.py --create-owner \
    --email owner@company.ru \
    --password SuperSecretPassword123 \
    --name "Владимир Владимиров"
# setup_platform.py
import asyncpg
import bcrypt

async def create_owner(email: str, password: str, full_name: str):
    """Создать первого пользователя (Owner)"""

    # Хеш пароля
    password_hash = bcrypt.hashpw(
        password.encode('utf-8'),
        bcrypt.gensalt()
    ).decode('utf-8')

    # Создать
    pool = await get_pool()
    async with pool.acquire() as conn:
        user_id = await conn.fetchval(
            """
            INSERT INTO platform_users (email, password_hash, full_name, role)
            VALUES ($1, $2, $3, 'owner')
            RETURNING id
            """,
            email, password_hash, full_name
        )

    print(f"✅ Owner created: {email} (id: {user_id})")
    return user_id

2. Создание тестовых пользователей

# Для демо
TEST_USERS = [
    {'email': 'admin@demo.ru', 'role': 'admin', 'name': 'Анна Админова'},
    {'email': 'manager@demo.ru', 'role': 'manager', 'name': 'Мария Менеджерова'},
    {'email': 'operator1@demo.ru', 'role': 'operator', 'name': 'Ольга Операторова'},
    {'email': 'operator2@demo.ru', 'role': 'operator', 'name': 'Сергей Сергеев'},
    {'email': 'viewer@demo.ru', 'role': 'viewer', 'name': 'Виктор Смотрящий'},
]

for user_data in TEST_USERS:
    await create_user(
        email=user_data['email'],
        password='demo123',  # Пароль для всех в demo
        role=user_data['role'],
        full_name=user_data['name']
    )

БЕЗОПАСНОСТЬ

Хранение паролей

JWT токены

import jwt
from datetime import datetime, timedelta

SECRET_KEY = os.getenv('JWT_SECRET_KEY')  # Из .env
ALGORITHM = 'HS256'
ACCESS_TOKEN_EXPIRE_MINUTES = 60

def create_access_token(user_id: int, role: str) -> str:
    """Создать JWT токен"""

    payload = {
        'user_id': user_id,
        'role': role,
        'exp': datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES),
        'iat': datetime.utcnow(),
    }

    token = jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
    return token

def verify_token(token: str) -> dict:
    """Проверить и декодировать токен"""
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(401, "Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(401, "Invalid token")

Ограничение попыток входа

# Redis для rate limiting
from redis import asyncio as aioredis

async def check_login_attempts(ip: str) -> bool:
    """Проверить количество попыток входа с IP"""

    redis = await aioredis.from_url('redis://localhost')

    key = f"login_attempts:{ip}"
    attempts = await redis.get(key)

    if attempts and int(attempts) >= 5:
        # Заблокировано на 15 минут
        ttl = await redis.ttl(key)
        raise HTTPException(429, f"Too many attempts. Try again in {ttl}s")

    return True

async def record_failed_login(ip: str):
    """Записать неудачную попытку"""
    redis = await aioredis.from_url('redis://localhost')

    key = f"login_attempts:{ip}"
    await redis.incr(key)
    await redis.expire(key, 900)  # 15 минут

РЕЗЮМЕ

Система ролей создана

Готово к реализации

Документ содержит:
1. SQL схему для 4 новых таблиц
2. Python код для middleware и проверки прав
3. API endpoints для управления пользователями
4. UI mockups для экранов с учётом ролей
5. Безопасность (bcrypt, JWT, rate limiting)


Следующий шаг: Реализация API и UI для управления пользователями

Файлы для создания:
- system/@bot-platform.system/api/users.py - API управления пользователями
- system/@bot-platform.system/api/auth.py - Авторизация и JWT
- system/@bot-platform.system/middleware/permissions.py - Проверка прав
- system/@bot-platform.system/setup_users.py - Создание таблиц и Owner