# Роль SMALUM — DFD
<!-- smalum-role-version: 1.11.0 -->

Узкая шпаргалка нотации для внешней LLM (ENH-1624). Склейка: [role-core.md](https://docs.smalum.io/role-core.md) + этот файл.
Полный каталог: https://docs.smalum.io/role.md · страница: https://docs.smalum.io/ai · эталоны: https://docs.smalum.io/role-examples.md

Файл: https://docs.smalum.io/role-dfd.md

# Часть B — DFD (Gane–Sarson) → Smalum

> **Канон v0.2 ([ENH-1617](https://redmine.q2t.ru/issues/1617)):** второй заголовок `//smalum/…` → `DFD0038`; `// SM:` не в конце → `DFD0035`; дефис в id → `DFD0011`. Полный синтаксис — [Синтаксис-DFD.md](https://docs.smalum.io/dfd) / RFC `dfd/v0.2`.



DFD показывает **движение данных**, не управление «если/потом». Нет ромбов решений и sequence BPMN.

## B1. Четыре элемента — только они

| Текст | Фигура | Смысл |
|-------|--------|--------|
| `id` или `id = Подпись` | прямоугольник | **внешняя сущность** (человек, орг., смежная ИС) |
| `(id)` или `(id = Подпись)` | скруглённый | **процесс** (преобразование) |
| `id-[process]` / `id-[процесс]` | то же | процесс без обёртки всей строки; дальше голый id |
| `[id]` или `[id = Подпись]` | открытый справа | **хранилище** (пассивно) |
| `id-[store]` / `id-[хранилище]` | то же | хранилище без обёртки всей строки; дальше голый id |
| `Источник - Получатель подпись` | стрелка | **поток данных** |
| `A-[B] подпись` / `[B]-A подпись` | стрелка | компактный поток: `[]` = хранилище на другом конце |
| `A-(B) подпись` / `(B)-A подпись` | стрелка | компактный поток: `()` = процесс на другом конце |
| `Имя {` … `}` / `"Имя" {` … `}` | рамка (пунктир, лёгкое скругление) | **группа** блоков — §B6 |

Id — одно слово: латиница, кириллица, цифры, `_`. **Без** пробелов, дефисов внутри имени и скобок. Подпись с пробелами — только после `=`. **Два и более пробела подряд в подписи** = перенос строки (`user = Клиент  Физлицо`; то же в подписи потока). Тип задают скобки `(id)` / `[id]` **или** суффикс `id-[process]` / `id-[store]`, не слова `entity` / `process` / `store` / `datastore` в начале строки. Дефис только в суффиксе типа.

**Компактный сахар** (без пробелов вокруг `-`): скобки задают **тип другого** конца, id внутри скобок — имя фигуры. Не путать с объявлением `user-[store]` / `pay-[process]` (тег-тип **без** текста после `]` — это объявление id, не поток).

Заголовок обязателен: `//smalum/[каталог/]dfd Название`. Без него редактор уйдёт в PlantUML.

## B2. Правила смысла

1. **Граница системы** фиксируется на контексте / уровне 0 и **копируется** на декомпозиции.
2. Внешняя сущность — за границей **всей** системы; смежная ИС всегда сущность (чёрный ящик).
3. Процесс = глагол + объект, есть вход и выход, **преобразует** данные.
4. Хранилище = долгоживущие данные; само никуда не «течёт».
5. Поток: слева источник, справа получатель. `→` = синоним `-`. Несколько потоков между парой — ок.
6. **Контекст:** 1 процесс, без хранилищ. **Уровень 0:** обычно 3–9 процессов.
7. Детектор: нет `@startuml`, нет `CREATE TABLE`, нет заголовка `…/bpmn` и `…/struct`, первая строка — `//smalum/…/dfd …`. Порядок разбора редактора: SQL → BPMN → **Struct** → **Infra** → DFD → **DMN** → Custom → Mermaid → PlantUML. Стрелки `-->` — это PlantUML, не DFD. Mermaid `flowchart` **не** заменяет DFD: нет хранилищ Gane–Sarson и границы системы.

## B3. Декомпозиция: четыре запрета (брак, если нарушить)

1. **Не объявлять** процесс/хранилище родителя как сущность без `()`/`[]` и без суффикса `-[process]`/`-[store]`. На дочерней секции объявления **не наследуются** — пишите тот же тип снова. Сам декомпозируемый процесс **не рисуется**.
2. **Не вести** поток «хранилище → сосед родителя» с декомпозиции производителя. Выход — через **процесс-шлюз** внутри декомпозиции.
3. **Не раскрывать** внутренности внешней системы (её сканеры, БД, драйверы).
4. **Не сдвигать** границу системы на дочернем уровне (не превращать внутреннее во «внешнее»).

Баланс уровней: входы/выходы декомпозируемого процесса на родителе должны иметь пару на дочерней диаграмме.

## B4. Пример

Контекст — **один** исходник. Уровень 0 — **отдельный** исходник, не второй заголовок в том же файле.

```
//smalum/Библиотека/dfd Контекст
reader = Читатель
librarian = Библиотекарь
(system = Библиотечная система)

reader - system Запрос на книгу
system - reader Ответ о наличии
librarian - system Сведения о выдаче
system - librarian Статус выдачи
```

```
//smalum/Библиотека/dfd Уровень 0
reader = Читатель
librarian = Библиотекарь
(findBook = Поиск книги)
(issueBook = Выдача книги)
[catalog = Каталог книг]

reader - findBook Запрос на книгу
findBook - reader Ответ о наличии
findBook - issueBook Запрос на выдачу
librarian - issueBook Сведения о выдаче
issueBook - catalog Обновление каталога
```

## B5. Чего нет в языке DFD

- подпись через пробел после id (`entity Граббер`, `User Пользователь`);
- слова `entity` / `process` / `store` / `datastore` как тип строки (это не PlantUML и не Visual Paradigm). Тип — скобки `( )` / `[ ]` или суффикс `id-[process]` / `id-[store]`. Слово `entity` в Части C — UML/ER, **не** DFD;
- старые записи `entity()` / `process()` / `store()` и стрелки `-(` / `)-`;
- id с пробелом или дефисом внутри имени (`Backend 059`, `ML-модуль`) — пишите `backend = Backend 059`. Дефис только в `user-[store]`;
- поток `A - подпись - B` (подпись посередине) — канон `A - B подпись` или компакт `A-[B] подпись` / `A-(B) подпись`;
- путать компактный поток `Клиент-[склад] данные` с объявлением `склад-[store]` (у объявления **нет** текста после `]`);
- уровни декомпозиции в одном файле и PlantUML `package` — для логического объединения есть группы `Имя { … }` (§B6);
- поток на группу вместо блока (`user - Склад`, где `Склад` — группа) — ошибка, стрелка не рисуется;
- двунаправленная одна стрелка; цвета; `@startuml` / `-->`;
- Mermaid `flowchart` как «потоки данных» — это не DFD.

## B6. Группы блоков `Имя { … }`

Группа логически объединяет сущности, процессы и хранилища одной рамкой (пунктир, небольшое скругление, обводка светлее). Ставьте группы, когда просят «сгруппируй», «выдели контур / подсистему / отдел» или когда блоки явно делятся на зоны. Группа — не уровень декомпозиции и не отдельная диаграмма: заголовок один, граница системы та же.

| Текст | Что это |
|-------|---------|
| `Имя {` | открыть группу: имя из букв (кириллица, латиница), цифр, `_` и пробелов; `{` в **той же** строке |
| `"Имя" {` | имя с другими знаками (`-`, `/`, скобки, точка) — в двойных кавычках: `"Склад / логистика (СПб)" {` |
| `}` | закрыть группу — **на отдельной строке** |
| `Резерв { }` / `Резерв {}` | пустая группа — рисуется пустой рамкой |

Правила:

- **Имя** — до **120 символов**, без двойных кавычек и `{ }` внутри; пробелы по краям и повторные пробелы схлопываются. Имя группы уникально без учёта регистра (`Склад` и `склад` — одна группа) и **не совпадает с id блока**.
- **Внутри** — обычные строки блоков: `id = Подпись`, `(id = …)`, `[id = …]`, `id-[process]`, `id-[store]`. Блок принадлежит группе, где стоит его **объявление**. **Один блок — одна группа:** повторное объявление того же id в другой группе или вне группы — ошибка. Id, который встречается только в потоках, попадает туда, где упомянут впервые, — поэтому объявляйте блоки явно внутри нужной группы.
- **Вложенность разрешена:** группа внутри группы — рамка в рамке.
- **Потоки — только между блоками**, в том числе через границу группы (блок внутри → блок снаружи или в другой группе). Поток можно писать внутри или вне `{ }`; понятнее — после всех групп. **Поток на саму группу** (`user - Склад Заказ`) — ошибка с номером строки, стрелка не рисуется: ведите поток к конкретному блоку внутри группы (`user - pick Заказ`).
- **Ошибки с номером строки:** незакрытая `{` («Группа «…» не закрыта»), лишняя `}`, `{` без имени, пустое имя `"" {`, повтор имени группы, id блока = имя группы, имя длиннее 120 символов, поток на группу.
- Отступ внутри группы необязателен и не считается продолжением подписи.
- **Оверлей** (только по просьбе про лейаут, Часть D): рамка группы — ref `"group:Имя"` в кавычках, `x y w h`: `// SM: node "group:Склад" 40 300 420 260`. Блоки внутри — обычные `// SM: node id x y w h`. Новая схема с группами — **без** `SM:`: редактор сам разложит блоки по рамкам.

Пример (уровень 0 с группами):

```
//smalum/Магазин/dfd Уровень 0 с группами
customer = Покупатель
courier = Курьер

"Контур продаж" {
  (checkout = Оформление заказа)
  (pay = Оплата)
  [orders = Заказы]
}

Склад {
  (pick = Комплектация)
  [stock = Остатки]
}

customer - checkout Заказ
checkout - pay Счёт
pay - customer Чек
checkout - orders Новый заказ
orders - pick Заказ к сборке
pick - stock Списание
pick - courier Посылка
```

Вложенные группы и пустая группа:

```
//smalum/Сервис/dfd Вложенные группы
user = Пользователь
Компания {
  (front = Витрина)
  Бэкенд {
    (api = API заказов)
    [db = База заказов]
  }
  Резерв { }
}
user - front Запрос
front - api Заказ
api - db Запись заказа
```

---
