---
name: xbsl-pattern-rls
description: >
  Реализует полный паттерн RLS (Row-Level Security) — разграничение доступа к строкам
  данных — для объектов конфигурации 1С:Элемент (Справочник, Документ и др.).

  За один вызов создаёт все необходимые артефакты: КлючДоступа (.yaml + .xbsl),
  обновляет YAML объекта (КонтрольДоступа + РасчетРазрешенийПо) и дописывает в
  .xbsl объекта два обработчика — уровень 1 (доступ к таблице) и уровень 2
  (доступ к конкретным строкам).

  Вызывай когда пользователь хочет: настроить RLS на справочник или документ;
  ограничить видимость записей по владельцу/ответственному/организации;
  реализовать «каждый видит только свои записи»; настроить доступ группы
  пользователей к записям по контекстному параметру.

  Паттерны: P0 — доступ без построчной фильтрации (РазрешеноАутентифицированным /
  РазрешеноАдминистраторам, без обработчиков); P1 — пользователь видит только свои
  записи (предопределённый ключ, файлы не создаются); P2 — группа по параметру
  (собственный КлючДоступа + обработчик ПроверитьНаличиеКлючейДоступа); P2-б —
  ролевой ключ без параметров; P3 — два участника с разными правами на один объект.
compatibility: Requires Python 3.
---

Во всех командах ниже `{python}` означает `python` в Windows и `python3` в macOS/Linux/WSL. Выбирай команду сразу по текущей ОС, не запускай оба варианта.

# RLS-паттерн для объектов 1С:Элемент

Перед созданием или дополнением `.xbsl` прочитай `.claude/xbsl-spec.md`.
Прочитай `references/rls-паттерны.md` — там точные шаблоны YAML и XBSL для обоих паттернов.

## Шаг 1: Определи целевой объект

Из запроса пользователя извлеки тип (`Справочник`, `Документ`) и имя объекта.
Если имя не указано — спроси пользователя.

## Шаг 2: Разведка объекта

Запусти `rls_state`:

```bash
{python} .claude/skills/xbsl-pattern-rls/scripts/rls_state.py --name <ИмяОбъекта> --root .
```

Из результата возьми:
- `object_path` — папка, куда класть файлы ключа
- `yaml_file` — имя YAML-файла объекта
- `xbsl_file` / `xbsl_exists` — путь к `.xbsl`-файлу и признак его существования
- `pattern_hints` — подсказки по паттерну на основе типов реквизитов
- `control_access` — текущее состояние секции `КонтрольДоступа` (используй на шаге 7)
- `handlers` — наличие обработчиков уровня 1/2 (используй на шаге 8)

Если скрипт вернул `error` с несколькими `matches` — покажи список и попроси уточнить имя.

⚠️ RLS-обработчики записываются в `<Имя>.xbsl` (без суффикса `.Объект`). Файл `<Имя>.Объект.xbsl` предназначен только для lifecycle-событий (`ПослеЗаписи`, `ДоЗаписи`) — туда RLS не кладётся. Если `rls_state` вернул `xbsl_file: null` — создай файл `<ИмяОбъекта>.xbsl`.

## Шаг 3: Выбери паттерн

Сначала спроси пользователя: **нужна ли построчная фильтрация?**
Если нет — используй P0 и завершай на шаге 7 (только YAML).

Для построчной фильтрации проанализируй `fields` из шага 2:

| Признак | Паттерн |
|---------|---------|
| Не нужна фильтрация по строкам (все видят всё) | **P0 — Без RLS** |
| Один реквизит типа `Пользователи.Ссылка?` | **P1 — По пользователю** |
| Два реквизита-участника, каждый → свой справочник со встроенным полем `Пользователь` | **P3 — Несколько участников** |
| Реквизит типа `<Справочник>.Ссылка?`, доступ — по роли (нет прямой связи с пользователем) | **P2 — По параметру** |
| Роль без привязки к объекту (все руководители видят всё) | **P2-б — Ключ без параметров** |

Если признак не очевиден — спроси пользователя и объясни разницу:
- **P0**: «Все вошедшие пользователи видят все записи. Никаких обработчиков и ключей.»
- **P1**: «Каждый пользователь видит только свои записи. Не нужно создавать дополнительных объектов.»
- **P2**: «Группа пользователей видит записи по общему контексту (организация, регион). Создаётся собственный КлючДоступа.»
- **P2-б**: «Все пользователи с определённой ролью видят все записи. Собственный ключ, но без параметров.»
- **P3**: «Две роли на один объект с разными правами (например, автор — полные права, соисполнитель — только чтение).»

## Шаг 4: Уточни детали `[только P2, P2-б, P3]`

**P2 и P2-б** — уточни у пользователя:

1. **Имя ключа** — дефолт: `КлючДоступа<ИмяОбъектаРодительный>` (например `КлючДоступаЗадач`).
   Стиль: PascalCase, начинается с `КлючДоступа`, суффикс отражает контекст.

2. **P2**: **Поле-контекст** — реквизит из `fields`, по значению которого группируются строки.
   **P2-б**: поле не нужно — ключ без параметров, выдаётся всем с нужной ролью.

3. **Таблица связи** — справочник или регистр, где хранится связь «пользователь ↔ контекст»
   (P2) или «пользователь ↔ роль» (P2-б).

**P3** — уточни оба поля-участника и какие права у каждого.

**P1** — уточни только **поле-пользователь** из `fields`.

## Шаг 5: Сгенерируй UUID `[только P2, P2-б]`

Для собственного ключа нужен **1 UUID** (на объект; параметры `Ид` не имеют).
Вызови скилл `xbsl-uuid` с числом `1`.

## Шаг 6: Создай файлы ключа `[только P2, P2-б]`

Создай `<ИмяКлюча>.yaml` в `object_path` по шаблону из `references/rls-паттерны.md` (раздел P2).

Создай `<ИмяКлюча>.xbsl` в той же папке — шаблон `ПроверитьНаличиеКлючейДоступа`.
Подставь реальные имена из шага 4; оставь `// TODO` там, где нужна бизнес-логика запроса.

**Проверка межподсистемной видимости**: если тип параметра (`Тип: <Справочник>.Ссылка?`)
относится к объекту из **другой подсистемы** — добавь `Импорт: [<ПодсистемаИсточника>]`
в YAML ключа и убедись, что источник имеет `ОбластьВидимости: ВПроекте`.

## Шаг 7: Обнови YAML объекта

Используй данные из шага 2: `object_path` + `yaml_file`. Состояние `КонтрольДоступа` уже известно из `control_access`.

Добавь или обнови секцию `КонтрольДоступа`. Точный формат — в `references/rls-паттерны.md`.

- `РасчетРазрешенийПо` — укажи поле-пользователь (P1) или поле-контекст (P2)
- `ПоУмолчанию: РазрешенияВычисляютсяДляКаждогоОбъекта`

Если секция уже существует с другим значением — сообщи пользователю и спроси подтверждение.

## Шаг 8: Запиши обработчики в .xbsl объекта

Файл уже известен из шага 2: `xbsl_file` в `object_path`. Наличие обработчиков — в `handlers`.

- Если `handlers.level1 = true` — предложи заменить или пропустить.
- Если `xbsl_exists = false` — создай `<ИмяОбъекта>.xbsl` (новый файл, без суффикса `.Объект`).

Добавь оба обработчика: уровень 1 (`ВычислитьРазрешенияДоступа`) и
уровень 2 (`ВычислитьРазрешенияДоступаДляОбъектов`) из шаблонов в `references/rls-паттерны.md`.

Подставь реальные имена:
- `<Объект>` → имя объекта (например `Задачи`)
- `<ПолеПользователя>` / `<ПолеКонтекста>` → реальное имя реквизита
- `<КлючИмя>` → имя ключа (только P2)

⚠️ **Правило уровней**: все права из уровня 2 обязаны присутствовать и в уровне 1.
Проверь перед записью.

## Шаг 9: Итог и рекомендации

Перечисли созданные/изменённые файлы:

```
Создано:
  <object_path>/<КлючИмя>.yaml   — КлючДоступа с параметром Владелец  [только P2]
  <object_path>/<КлючИмя>.xbsl   — обработчик ПроверитьНаличиеКлючейДоступа  [только P2]

Обновлено:
  <object_path>/<ОбъектИмя>.yaml    — добавлен КонтрольДоступа
  <object_path>/<ОбъектИмя>.xbsl   — добавлены обработчики RLS
```

Добавь рекомендации по пересчёту прав:

**Первый пересчёт после деплоя** — добавь в `Проект.xbsl` метод с аннотацией.
Если объект находится в подсистеме — добавь `импорт <Подсистема>` в начало файла:
```xbsl
импорт <Подсистема>   // если объект в подсистеме, а не в корне проекта

@ОбновлениеПроекта(Ид = "recalc_<Объект>_rls_v1", Номер = N)
метод ПересчитатьПрава<Объект>()
    <Объект>.ПересчитатьРазрешенияДоступа()
    <Объект>.ПересчитатьРазрешенияДоступаДляОбъектов()
;
```

**Своевременный пересчёт при изменении данных** (только P2) — в `ПослеЗаписи` объекта-источника
при изменении поля-контекста:
```xbsl
если До.<ПолеКонтекста> <> Это.<ПолеКонтекста>
    исп КонтекстДоступа.Привилегированный()
        <КлючИмя>.ПересчитатьКлючи(<Параметр> = Это.Ссылка)
;
```

---

## Чеклист перед передачей результата

- [ ] `КонтрольДоступа.Разрешения` обновлено в YAML объекта
- [ ] Для P0: обработчики **не создаются**, шаги 8–9 пропустить
- [ ] Для P1, P2, P2-б, P3: указан обработчик уровня 1 (`ВычислитьРазрешенияДоступа`)
- [ ] Для P1, P2, P2-б, P3: указан обработчик уровня 2 (`ВычислитьРазрешенияДоступаДляОбъектов`)
- [ ] Все права из уровня 2 есть и в уровне 1
- [ ] Добавлена проверка `!= Неопределено` по полю в цикле уровня 2 (не `= Неопределено` — в XBSL `=` только присваивание)
- [ ] Файл обработчика называется `<Имя>.xbsl` (без суффикса `.Объект`)
- [ ] Поле в `РасчетРазрешенийПо` — не коллекция, не строка без ограничения, не stdlib-перечисление
- [ ] Для P2, P2-б: написан `ПроверитьНаличиеКлючейДоступа` с TODO-комментариями
- [ ] Для P2: параметры ключа в YAML **не имеют** поля `Ид`
- [ ] Для P2-б: в YAML ключа раздел `Параметры` отсутствует
- [ ] Для P3: для каждого участника — отдельный запрос и блок `если`
