Видимость событий

Кто что видит в кампании. Объясняет три режима видимости событий, почему по умолчанию всё открыто, и как архитектура рассчитана на туман войны без повторных миграций.

Все события приложения имеют поле visibility — JSONB трёх форм. На Day 1 всё создаётся с режимом all — открытая видимость по умолчанию. Архитектура финальная сразу: когда добавится UI скрытых действий, миграций схемы не нужно.


Три режима видимости

Форма visibilityКто видит
{"mode": "all"}Все участники кампании + spectator'ы
{"mode": "dm_only"}Только DM и spectator с see_all=true
{"mode": "characters", "character_ids": [...]}Только перечисленные персонажи + DM

Режим characters — это «только эти PC знают». Используется для личных квестов, секретных знаний, информации, которая не должна утечь в общий чат.

Что есть в проде сейчас

Поле visibility на events не существует — универсального лога событий ещё нет. Все данные открыты всем участникам кампании. RLS проверяет только членство в кампании (is_member(campaign_id)), а не content-level visibility.

Это сознательный выбор для MVP: игроки кооперируются, делятся информацией, DM пишет подробные рекапы. Туман войны и скрытые действия — roadmap.

roadmap/visibility-and-sandbox.md

Целевая RLS-политика

В целевой архитектуре политика events_select проверяет visibility JSONB:

-- псевдокод
CASE
  WHEN visibility->>'mode' = 'all' THEN is_member(campaign_id)
  WHEN visibility->>'mode' = 'dm_only' THEN is_dm_or_owner(campaign_id) OR see_all(...)
  WHEN visibility->>'mode' = 'characters' THEN is_dm_or_owner(campaign_id)
    OR my_character_id IN (visibility->'character_ids')
END

Это один вызов RLS без приложенческого кода. Вся логика видимости — в базе данных.

Spectator с see_all

spectator — роль, которой ещё нет в проде (только owner/dm/player). Spectator — это participant без управляемых персонажей: наблюдатель, зритель, ассистент DM.

Опциональный флаг participants.see_all: bool даёт расширенный доступ — spectator с see_all=true видит и dm_only-события. Нужен для соведущих и трансляций.

roles-and-clients.md

Партии — UI-агрегация, не security-граница

«Пачка» (party) — это состав сессии, группа PC которые ходили вместе. Хранится как рёбра participated_in (session → character). Партия не security-граница: «только партия X видит событие» выражается через mode='characters' с явным перечислением ID — не через membership в пачке. Это важно, потому что партии ad-hoc и меняются каждую сессию.

Live broadcast как побочный эффект

Когда все события имеют mode='all', трансляция кампании зрителям — тривиальный случай: spectator без see_all видит ровно то же самое, что и рядовой игрок. Никакой отдельной логики «публичной видимости». → roadmap/live-broadcast.md


Поле visibility — архитектурное решение «один раз и навсегда». UI туман-войны придёт позже, схема под него уже готова.