core/docs/admin-panel.md

561 lines
15 KiB
Markdown
Raw Normal View History

2025-07-02 19:30:21 +00:00
# Администраторская панель Discours
## Обзор
Администраторская панель — это комплексная система управления платформой Discours, предоставляющая полный контроль над пользователями, публикациями, сообществами и их ролями.
## Архитектура системы доступа
### Уровни доступа
1. **Системные администраторы** — email в переменной `ADMIN_EMAILS` (управление системой через переменные среды)
2. **RBAC роли в сообществах**`reader`, `author`, `artist`, `expert`, `editor`, `admin` (управляемые через админку)
**ВАЖНО**:
- Роль `admin` в RBAC — это обычная роль в сообществе, управляемая через админку
- "Системный администратор" — синтетическая роль, которая НЕ хранится в базе данных
- Синтетическая роль добавляется только в API ответы для пользователей из `ADMIN_EMAILS`
- На фронте в сообществах синтетическая роль НЕ отображается
### Декораторы безопасности
```python
@admin_auth_required # Доступ только системным админам (ADMIN_EMAILS)
@editor_or_admin_required # Доступ редакторам и админам сообщества (RBAC роли)
```
## Модули администрирования
### 1. Управление пользователями
#### Получение списка пользователей
```graphql
query AdminGetUsers(
$limit: Int = 20
$offset: Int = 0
$search: String = ""
) {
adminGetUsers(limit: $limit, offset: $offset, search: $search) {
authors {
id
email
name
slug
roles
created_at
last_seen
}
total
page
perPage
totalPages
}
}
```
**Особенности:**
- Поиск по email, имени и ID
- Пагинация с ограничением 1-100 записей
- Роли получаются из основного сообщества (ID=1)
- Автоматическое добавление синтетической роли "Системный администратор" для email из `ADMIN_EMAILS`
#### Обновление пользователя
```graphql
mutation AdminUpdateUser($user: AdminUserUpdateInput!) {
adminUpdateUser(user: $user) {
success
error
}
}
```
**Поддерживаемые поля:**
- `email`с проверкой уникальности
- `name` — имя пользователя
- `slug`с проверкой уникальности
- `roles` — массив ролей для основного сообщества
### 2. Система ролей и разрешений (RBAC)
#### Иерархия ролей
```
reader → author → artist → expert → editor → admin
```
Каждая роль наследует права предыдущих **только при инициализации** сообщества.
#### Получение ролей
```graphql
query AdminGetRoles($community: Int) {
adminGetRoles(community: $community) {
id
name
description
}
}
```
- Без `community` — все системные роли
- С `community` — роли конкретного сообщества + счетчик разрешений
#### Управление ролями в сообществах
**Получение ролей пользователя:**
```graphql
query AdminGetUserCommunityRoles(
$author_id: Int!
$community_id: Int!
) {
adminGetUserCommunityRoles(
author_id: $author_id
community_id: $community_id
) {
author_id
community_id
roles
}
}
```
**Назначение ролей:**
```graphql
mutation AdminSetUserCommunityRoles(
$author_id: Int!
$community_id: Int!
$roles: [String!]!
) {
adminSetUserCommunityRoles(
author_id: $author_id
community_id: $community_id
roles: $roles
) {
success
error
author_id
community_id
roles
}
}
```
**Добавление отдельной роли:**
```graphql
mutation AdminAddUserToRole(
$author_id: Int!
$role_id: String!
$community_id: Int!
) {
adminAddUserToRole(
author_id: $author_id
role_id: $role_id
community_id: $community_id
) {
success
error
}
}
```
**Удаление роли:**
```graphql
mutation AdminRemoveUserFromRole(
$author_id: Int!
$role_id: String!
$community_id: Int!
) {
adminRemoveUserFromRole(
author_id: $author_id
role_id: $role_id
community_id: $community_id
) {
success
removed
}
}
```
### 3. Управление сообществами
#### Участники сообщества
```graphql
query AdminGetCommunityMembers(
$community_id: Int!
$limit: Int = 20
$offset: Int = 0
) {
adminGetCommunityMembers(
community_id: $community_id
limit: $limit
offset: $offset
) {
members {
id
name
email
slug
roles
}
total
community_id
}
}
```
#### Настройки ролей сообщества
**Получение настроек:**
```graphql
query AdminGetCommunityRoleSettings($community_id: Int!) {
adminGetCommunityRoleSettings(community_id: $community_id) {
community_id
default_roles
available_roles
error
}
}
```
**Обновление настроек:**
```graphql
mutation AdminUpdateCommunityRoleSettings(
$community_id: Int!
$default_roles: [String!]!
$available_roles: [String!]!
) {
adminUpdateCommunityRoleSettings(
community_id: $community_id
default_roles: $default_roles
available_roles: $available_roles
) {
success
error
community_id
default_roles
available_roles
}
}
```
#### Создание пользовательской роли
```graphql
mutation AdminCreateCustomRole($role: CustomRoleInput!) {
adminCreateCustomRole(role: $role) {
success
error
role {
id
name
description
}
}
}
```
#### Удаление пользовательской роли
```graphql
mutation AdminDeleteCustomRole(
$role_id: String!
$community_id: Int!
) {
adminDeleteCustomRole(
role_id: $role_id
community_id: $community_id
) {
success
error
}
}
```
### 4. Управление публикациями
#### Получение списка публикаций
```graphql
query AdminGetShouts(
$limit: Int = 20
$offset: Int = 0
$search: String = ""
$status: String = "all"
$community: Int
) {
adminGetShouts(
limit: $limit
offset: $offset
search: $search
status: $status
community: $community
) {
shouts {
id
title
slug
body
lead
subtitle
# ... остальные поля
created_by {
id
email
name
slug
}
community {
id
name
slug
}
authors {
id
email
name
slug
}
topics {
id
title
slug
}
}
total
page
perPage
totalPages
}
}
```
**Статусы публикаций:**
- `all` — все публикации (включая удаленные)
- `published` — опубликованные
- `draft` — черновики
- `deleted` — удаленные
#### Операции с публикациями
**Обновление:**
```graphql
mutation AdminUpdateShout($shout: AdminShoutUpdateInput!) {
adminUpdateShout(shout: $shout) {
success
error
}
}
```
**Удаление (мягкое):**
```graphql
mutation AdminDeleteShout($shout_id: Int!) {
adminDeleteShout(shout_id: $shout_id) {
success
error
}
}
```
**Восстановление:**
```graphql
mutation AdminRestoreShout($shout_id: Int!) {
adminRestoreShout(shout_id: $shout_id) {
success
error
}
}
```
### 5. Управление приглашениями
#### Получение списка приглашений
```graphql
query AdminGetInvites(
$limit: Int = 20
$offset: Int = 0
$search: String = ""
$status: String = "all"
) {
adminGetInvites(
limit: $limit
offset: $offset
search: $search
status: $status
) {
invites {
inviter_id
author_id
shout_id
status
inviter {
id
email
name
slug
}
author {
id
email
name
slug
}
shout {
id
title
slug
created_by {
id
email
name
slug
}
}
}
total
page
perPage
totalPages
}
}
```
**Статусы приглашений:**
- `PENDING` — ожидает ответа
- `ACCEPTED` — принято
- `REJECTED` — отклонено
#### Операции с приглашениями
**Обновление статуса:**
```graphql
mutation AdminUpdateInvite($invite: AdminInviteUpdateInput!) {
adminUpdateInvite(invite: $invite) {
success
error
}
}
```
**Удаление:**
```graphql
mutation AdminDeleteInvite(
$inviter_id: Int!
$author_id: Int!
$shout_id: Int!
) {
adminDeleteInvite(
inviter_id: $inviter_id
author_id: $author_id
shout_id: $shout_id
) {
success
error
}
}
```
**Пакетное удаление:**
```graphql
mutation AdminDeleteInvitesBatch($invites: [AdminInviteIdInput!]!) {
adminDeleteInvitesBatch(invites: $invites) {
success
error
}
}
```
### 6. Переменные окружения
Системные администраторы могут управлять переменными окружения:
```graphql
query GetEnvVariables {
getEnvVariables {
name
description
variables {
key
value
description
type
isSecret
}
}
}
```
```graphql
mutation UpdateEnvVariable($key: String!, $value: String!) {
updateEnvVariable(key: $key, value: $value) {
success
error
}
}
```
## Особенности реализации
### Принцип DRY
- Переиспользование логики из `reader.py`, `editor.py`
- Общие утилиты в `_get_user_roles()`
- Централизованная обработка ошибок
### Новая RBAC система
- Роли хранятся в CSV формате в `CommunityAuthor.roles`
- Методы модели: `add_role()`, `remove_role()`, `set_roles()`, `has_role()`
- Права наследуются **только при инициализации**
- Redis кэширование развернутых прав
### Синтетические роли
- **"Системный администратор"** — добавляется автоматически для пользователей из `ADMIN_EMAILS`
- НЕ хранится в базе данных, только в API ответах
- НЕ отображается на фронте в интерфейсах управления сообществами
- Используется только для индикации системных прав доступа
### Безопасность
- Валидация всех входных данных
- Проверка существования сущностей
- Контроль доступа через декораторы
- Логирование всех административных действий
### Производительность
- Пагинация для всех списков
- Индексы по ключевым полям
- Ограничения на размер выборки (max 100)
- Оптимизированные SQL запросы с `joinedload`
## Миграция данных
При переходе на новую RBAC систему используется функция:
```python
from orm.community import migrate_old_roles_to_community_author
migrate_old_roles_to_community_author()
```
Функция автоматически переносит роли из старых таблиц в новый формат CSV.
## Мониторинг и логирование
Все административные действия логируются с уровнем INFO:
- Изменение ролей пользователей
- Обновление настроек сообществ
- Операции с публикациями
- Управление приглашениями
Ошибки логируются с уровнем ERROR и полным стектрейсом.
## Лучшие практики
1. **Всегда проверяйте роли перед назначением**
2. **Используйте транзакции для групповых операций**
3. **Логируйте критические изменения**
4. **Валидируйте права доступа на каждом этапе**
5. **Применяйте принцип минимальных привилегий**
## Расширение функциональности
Для добавления новых административных функций:
1. Создайте резолвер с соответствующим декоратором
2. Добавьте GraphQL схему в `schema/admin.graphql`
3. Реализуйте логику с переиспользованием существующих компонентов
4. Добавьте тесты и документацию
5. Обновите права доступа при необходимости