Роли и клиенты
Три роли в проде (
owner/dm/player), как они разграничены в RLS, и что ждёт на горизонте:spectator,see_all, multi-DM как фундамент west-marches.
Членство в кампании хранится в таблице campaign_members (миграция 024):
один row на пару (user_id, campaign_id) с полем role. Один пользователь
может состоять в нескольких кампаниях с разными ролями. Ровно один owner
на кампанию (unique partial index).
Таблица ролей
| Роль | Может читать | Может писать | Особенности |
|---|---|---|---|
owner | всё в кампании | всё | единственный owner; управляет ролями участников |
dm | всё в кампании | всё, кроме auth.users и чужих кампаний | несколько DM на кампанию — поддерживается |
player | всё в кампании | свой PC + не-character ноды (031) | создаёт и правит нод мира; чужой PC — нельзя |
Несколько dm-аккаунтов на одну кампанию — уже работает. Это фундамент для
west-marches со множеством DM: каждый ведёт свои сессии, видит общий мир.
Как роли проверяются
Три helper-функции SECURITY DEFINER (миграция 024):
is_member(campaign_id)— базовая проверка членства (для SELECT-политик).is_dm_or_owner(campaign_id)— для write-политик и DM-эксклюзивных действий.is_owner(campaign_id)— только для операций уровня кампании (состав участников, настройки).
Server actions используют resolveAuth(campaignId) из
app/actions/transactions.ts — возвращает { role }, и дальше action
бранчится: player-only actions требуют role='player' + isPcOwner.
Создание и управление ролями
Пользователи не регистрируются самостоятельно. Флоу:
owner(или DM) создаёт аккаунт через скрипт / admin UI (scripts/seed-owner.ts— первый admin).user_profiles.must_change_password = true→ при первом входе редирект на/onboarding.- Owner назначает роль через
/c/[slug]/members. - Смена роли — через ту же страницу; понижение
dm → playerне лишает права читать историю, но лишает права писать DM-операции.
Инвайт-ссылки и самостоятельная регистрация — roadmap.
Защита PC через node_pc_owners
PC-ноды — особый случай. Помимо роли, используется таблица node_pc_owners
(миграция 027): (node_id, user_id). Игрок может редактировать только PC,
записанный на него в этой таблице. Функция can_edit_node(node_id) проверяет
роль И наличие строки в node_pc_owners.
Несколько игроков могут контролировать один PC (совместный персонаж) —
просто добавляется несколько строк в node_pc_owners.
Spectator — на горизонте
spectator — участник кампании без управляемых персонажей. Наблюдатель,
зритель live-broadcast, ассистент DM. В проде роли пока нет.
Когда появится: spectator видит то же, что player (все события с
mode='all'). Опциональный флаг participants.see_all: bool даст
расширенный доступ — spectator с see_all=true видит и dm_only-события.
Партии — UI-агрегация, не security-граница
«Пачка» — это состав конкретной сессии (рёбра participated_in). Партия
не является security-сущностью: нет «роли в партии», нет membership-таблицы
пачки. Если событие адресовано «только этой пачке» — оно несёт явный список
character_ids в поле visibility.
→
features/auth-and-membership/README.md— как работают приглашения и управление участниками. →dm-as-demiurge.md— что конкретно DM может делать и как это гейтится. →visibility.md— какvisibilityполе работает поверх ролевой системы.