Auth и RBAC
Better Auth, 7 ролей, 56 permissions и 4 уровня защиты
Аутентификация — Better Auth (src/lib/auth/), сессии в cookie. Регистрация только по приглашениям.
7 ролей
| Роль | Кто это |
|---|---|
super_admin | Полный доступ ко всему, включая AI-настройки |
monster_admin | Администратор Monster Team: пользователи, компании, аудит |
monster_pm | Проект-менеджер команды |
monster_creator | Исполнитель (производство роликов) |
client_owner | Владелец компании-клиента, максимум прав в своей компании |
client_manager | Менеджер клиента: создаёт задачи, материалы, правки |
client_viewer | Read-only доступ |
Permissions
56 ключей в src/lib/auth/permissions.ts, сгруппированы по доменам:
task.* view / create / update / delete
file.* upload / download / delete
content.* view_ready / upload_ready / approve / request_revision / delete_ready
revision.* create / view / resolve
calendar.* view / assign_date / move_item
ai.* generate_prompt / generate_copy / view_usage
user.* view / invite / change_role
company.* view / create / edit
admin.* manage_clients / manage_storage / manage_ai_budget
audit.view
safebot.* view / create / edit / delete / promote
reference_category.* create / update / deleteИсточник истины — ROLE_PERMISSIONS_MATRIX. Хардкод проверок ролей в коде запрещён.
Динамические overrides
Помимо матрицы, отдельному пользователю можно добавить/забрать права через таблицу UserPermission (админ UI: /users, API: /api/admin/users/[id]/permissions). Кэш overrides хранится в User.permissionOverridesJson.
4 уровня защиты
1. src/proxy.ts (middleware) — есть ли сессия вообще
2. lib/auth/redirects.ts — может ли роль видеть страницу (server-side redirect)
3. withPermission("key", handler) — guard каждого API endpoint
4. usePermissions() / <Can> — скрытие кнопок и секций в UIUI-уровень — только косметика; настоящая защита — уровень 3. Любой новый endpoint обязан быть обёрнут:
import { withPermission } from "@/lib/auth/with-permission";
export const POST = withPermission("task.create", async (req, { auth }) => {
// auth: { userId, role, companyId, permissions }
});Multi-tenancy
Все данные привязаны к companyId. Скоуп определяется в src/lib/api/scope.ts:
companyScope(auth)— клиент получает фильтр по своей компании, Monster/super видит всё;resolveWriteCompanyId(auth, requestedId)— валидация, куда можно писать.
Приглашения
- Админ создаёт приглашение:
POST /api/admin/invitations(permissionuser.invite) → ссылка с токеном. - Пользователь открывает
/invite/accept?token=…, форма показывает email/роль/компанию (GET /api/invitations/[token]). POST /api/invitations/[token]/accept— создание аккаунта и вход.
Как добавить новое право
- Добавить ключ в
src/lib/auth/permissions.tsи вROLE_PERMISSIONS_MATRIXнужным ролям. - Человекочитаемое название — в
permission-presets.ts(для admin UI). - Обернуть API в
withPermission("новый.ключ", …). - В UI —
usePermissions().can("новый.ключ")или<Can permission="новый.ключ">.