Версия: 1.0
Дата: 2025-12-27
Связано: ARCHITECTURE.md, UI_SCREENS.md
Система ролей для управления доступом к функциям платформы:
- 5 ролей с разными уровнями доступа
- Гибкое назначение операторов на диалоги
- Аудит всех действий пользователей
- Интеграция с существующей архитектурой
Описание: Полный контроль над платформой
Права доступа:
- ✅ Все права Admin
- ✅ Управление пользователями (создание, удаление, блокировка)
- ✅ Назначение ролей (включая Admin)
- ✅ Доступ к биллингу и лицензиям
- ✅ Удаление ботов и данных
- ✅ Экспорт/импорт всей системы
- ✅ Доступ к логам и аудиту
Количество: 1-2 на инсталляцию
UI доступ:
✅ Dashboard ✅ Bots ✅ Chats
✅ Channels ✅ Knowledge Base ✅ Analytics
✅ Settings ✅ Users & Roles ✅ Billing
✅ System Logs ✅ Backups
Описание: Управление ботами и контентом, но не системой
Права доступа:
- ✅ Создание/редактирование/деактивация ботов
- ✅ Настройка AI-моделей и промптов
- ✅ Управление базой знаний
- ✅ Подключение мессенджеров
- ✅ Просмотр аналитики по всем ботам
- ✅ Назначение операторов
- ✅ Настройка сценариев
- ❌ Удаление ботов (только Owner)
- ❌ Управление пользователями
- ❌ Доступ к биллингу
Количество: 1-5 на компанию
UI доступ:
✅ Dashboard ✅ Bots (create/edit) ✅ Chats (view all)
✅ Channels ✅ Knowledge Base ✅ Analytics
✅ Bot Settings ❌ Users & Roles ❌ Billing
Типичный пользователь: Руководитель отдела продаж, CRM-менеджер
Описание: Мониторинг и координация работы операторов
Права доступа:
- ✅ Просмотр всех диалогов
- ✅ Подключение к диалогам (режим наблюдения)
- ✅ Перераспределение диалогов между операторами
- ✅ Просмотр аналитики по операторам
- ✅ Редактирование базы знаний
- ✅ Просмотр настроек ботов
- ❌ Создание/изменение ботов
- ❌ Настройка AI-моделей
- ❌ Подключение каналов
Количество: 2-10 на компанию
UI доступ:
✅ Dashboard ⚠️ Bots (read-only) ✅ Chats (all)
❌ Channels ✅ Knowledge Base ✅ Analytics (team)
⚠️ Bot Settings (view) ❌ Users & Roles ❌ Billing
Типичный пользователь: Старший менеджер, супервайзер, руководитель смены
Описание: Ведение диалогов с клиентами
Права доступа:
- ✅ Просмотр назначенных диалогов
- ✅ Ответы в режиме Assistant (одобрение предложений бота)
- ✅ Ответы в режиме Manual (без бота)
- ✅ Подключение бота к диалогу
- ✅ Эскалация диалога менеджеру
- ✅ Просмотр истории диалога
- ✅ Использование шаблонов из базы знаний
- ❌ Просмотр чужих диалогов (если не назначены)
- ❌ Изменение настроек бота
- ❌ Просмотр аналитики по другим операторам
Количество: Неограниченно
UI доступ:
⚠️ Dashboard (own) ❌ Bots ✅ Chats (assigned)
❌ Channels ⚠️ Knowledge (view) ⚠️ Analytics (own)
❌ Bot Settings ❌ Users & Roles ❌ Billing
Типичный пользователь: Менеджер по продажам, оператор поддержки
Описание: Только чтение для аналитики и отчётов
Права доступа:
- ✅ Просмотр Dashboard
- ✅ Просмотр аналитики
- ✅ Экспорт отчётов
- ✅ Просмотр списка ботов
- ❌ Доступ к диалогам
- ❌ Изменение настроек
- ❌ Создание контента
Количество: Неограниченно
UI доступ:
✅ Dashboard ⚠️ Bots (list only) ❌ Chats
❌ Channels ❌ Knowledge Base ✅ Analytics (read)
❌ Bot Settings ❌ Users & Roles ❌ Billing
Типичный пользователь: Руководитель, аналитик, внешний консультант
| Функция | Owner | Admin | Manager | Operator | Viewer |
|---|---|---|---|---|---|
| БОТЫ | |||||
| Создать бота | ✅ | ✅ | ❌ | ❌ | ❌ |
| Редактировать бота | ✅ | ✅ | ❌ | ❌ | ❌ |
| Удалить бота | ✅ | ❌ | ❌ | ❌ | ❌ |
| Деактивировать бота | ✅ | ✅ | ❌ | ❌ | ❌ |
| Просмотр настроек | ✅ | ✅ | ✅ | ❌ | ⚠️ |
| Изменить AI-модель | ✅ | ✅ | ❌ | ❌ | ❌ |
| Изменить промпты | ✅ | ✅ | ❌ | ❌ | ❌ |
| ДИАЛОГИ | |||||
| Просмотр всех | ✅ | ✅ | ✅ | ❌ | ❌ |
| Просмотр своих | ✅ | ✅ | ✅ | ✅ | ❌ |
| Ответить клиенту | ✅ | ✅ | ✅ | ✅ | ❌ |
| Назначить оператора | ✅ | ✅ | ✅ | ❌ | ❌ |
| Закрыть диалог | ✅ | ✅ | ✅ | ✅ | ❌ |
| Экспорт диалога | ✅ | ✅ | ✅ | ⚠️ | ❌ |
| КАНАЛЫ | |||||
| Подключить канал | ✅ | ✅ | ❌ | ❌ | ❌ |
| Отключить канал | ✅ | ✅ | ❌ | ❌ | ❌ |
| Просмотр токенов | ✅ | ✅ | ❌ | ❌ | ❌ |
| БАЗА ЗНАНИЙ | |||||
| Создать статью | ✅ | ✅ | ✅ | ❌ | ❌ |
| Редактировать | ✅ | ✅ | ✅ | ❌ | ❌ |
| Удалить статью | ✅ | ✅ | ❌ | ❌ | ❌ |
| Просмотр | ✅ | ✅ | ✅ | ✅ | ❌ |
| АНАЛИТИКА | |||||
| Вся компания | ✅ | ✅ | ✅ | ❌ | ✅ |
| Своя команда | ✅ | ✅ | ✅ | ❌ | ❌ |
| Свои данные | ✅ | ✅ | ✅ | ✅ | ❌ |
| Экспорт отчётов | ✅ | ✅ | ✅ | ⚠️ | ✅ |
| ПОЛЬЗОВАТЕЛИ | |||||
| Создать | ✅ | ❌ | ❌ | ❌ | ❌ |
| Изменить роль | ✅ | ❌ | ❌ | ❌ | ❌ |
| Заблокировать | ✅ | ❌ | ❌ | ❌ | ❌ |
| Просмотр списка | ✅ | ⚠️ | ⚠️ | ❌ | ❌ |
| СИСТЕМА | |||||
| Настройки | ✅ | ⚠️ | ❌ | ❌ | ❌ |
| Биллинг | ✅ | ❌ | ❌ | ❌ | ❌ |
| Логи и аудит | ✅ | ❌ | ❌ | ❌ | ❌ |
| Бэкапы | ✅ | ❌ | ❌ | ❌ | ❌ |
Легенда:
- ✅ Полный доступ
- ⚠️ Ограниченный доступ
- ❌ Нет доступа
Кто назначает: Manager, Admin, Owner
Процесс:
1. Новый диалог появляется в очереди "Неназначенные"
2. Менеджер выбирает оператора из списка
3. Диалог переходит в очередь оператора
4. Оператор получает уведомление
UI:
┌─────────────────────────────────────────┐
│ 📋 Неназначенные диалоги (8) │
├─────────────────────────────────────────┤
│ [14:23] Иван Петров │
│ "Нужна консультация по товару" │
│ │
│ Назначить на: │
│ [▼ Выбрать оператора] │
│ ○ Анна (онлайн, 3 диалога) │
│ ○ Мария (онлайн, 2 диалога) │
│ ○ Сергей (не в сети) │
│ │
│ [✅ Назначить] │
└─────────────────────────────────────────┘
Настройка: 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 # Если не ответил — следующему
Описание: Операторы сами берут диалоги из общей очереди
Процесс:
1. Диалог в статусе "Waiting"
2. Оператор видит в списке "Доступные"
3. Нажимает "Взять диалог"
4. Диалог закрепляется за оператором
UI для оператора:
┌─────────────────────────────────────────┐
│ 📬 Доступные диалоги (5) │
├─────────────────────────────────────────┤
│ [14:30] Елена Смирнова │
│ "Подскажите по доставке" │
│ ⏱️ Ждёт 2 мин │
│ [🟢 Взять диалог] │
├─────────────────────────────────────────┤
│ [14:28] Дмитрий К. │
│ "Есть ли скидки на опт?" │
│ ⏱️ Ждёт 4 мин │
│ [🟢 Взять диалог] │
└─────────────────────────────────────────┘
Когда: Оператор не может решить вопрос
Процесс:
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);
Структура: {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',
],
}
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
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 │
└─────────────────────────────────────────────────────────────┘
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>
-- 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);
# Пользователи
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)
# Скрипт 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
# Для демо
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']
)
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