> Усі статті WIKI Helomi: /wiki/llms.txt

# Розділ від ШІ: файл розділу

Файл розділу — один файл, яким ШІ (ваш ШІ-співробітник або будь-який чат: Claude, ChatGPT, Gemini) описує цілий новий розділ Helomi: записи з полями й етапами, власний вигляд сторінки і логіку, що працює сама. Людина перетягує файл у прозорий квадрат «+ Додати розділ» у «Власних розділах» (або ШІ-співробітник встановлює його сам), перевіряє, що буде створено, і вмикає розділ у лівому меню. Ця стаття — повна інструкція для ШІ: дайте її своєму ШІ разом з описом розділу, який потрібен.

## Можливості
- Один файл — увесь розділ: дані (поля, етапи, що є в картці, передача в інші розділи), сторінка (HTML + CSS + JS) і агент (JS за розкладом).
- Файл `.json` (пакет) або один `.html` (сторінка, а опис і дані — у блоці `<script id="sg-section">`).
- Перевірка до встановлення: що буде створено, помилки, зауваги стилю. Нічого не пишеться, доки людина не натисне «Встановити».
- Повтор того самого файлу не створює дубль: пропонується «Оновити» наявний розділ.
- Оновлення не видаляє даних: поля додаються й змінюються, записи лишаються; код — нова версія з поверненням попередньої.
- Розділ можна вивантажити тим самим файлом («⋯ → Файл розділу»), дати ШІ доробити й завантажити назад.
- ШІ-співробітник з правом творця встановлює файл сам; у меню зліва розділ ставить людина.

## 1. Налаштування: отримати розділ від ШІ
1. «Налаштування → Типи даних → Власні розділи». Тут галерея ваших розділів і прозорий квадрат «+ Додати розділ».
2. Натисніть «Інструкція для ШІ» — завантажиться ця стаття файлом `.md`. Або «+ Додати розділ» → «Скопіювати завдання для ШІ» — у буфер ляже готове завдання.
3. Дайте інструкцію своєму ШІ й опишіть розділ: що зберігати (поля), які етапи, що показувати, що робити самому (нагадування, підрахунки). Наприклад: «Зроби розділ "Ремонти": пристрій, тип ремонту, вартість, етапи Прийнято → Діагностика → Готово, сторінка з показниками і таблицею, щодня нагадувати про ремонти, що застрягли».
4. ШІ віддає файл `<ім'я>.sgsection.json` (або `.html`). Збережіть його.
5. Перетягніть файл у квадрат «+ Додати розділ» (або натисніть на квадрат → «Вибрати файл»). Відкриється перевірка: що буде створено, зауваги, помилки.
6. «Показати в меню зліва» (і відділ меню) → «Встановити». Розділ з'явиться плиткою в галереї й у лівому меню.

ШІ-співробітник з правом творця «Свої розділи» (дані) і «Свої розширення (код)» (сторінка, агент) робить кроки 3–6 сам інструментами (див. «Для ШІ-співробітників»); людина лише вмикає «У меню зліва».

## 2. Як влаштований розділ: дані, вигляд, логіка
| шар | у файлі | що дає | коли потрібен |
| --- | --- | --- | --- |
| Дані | `data` | записи з полями, етапами, відповідальним, клієнтом, нотатками, файлами; список, дошка, картка, імпорт/експорт, доступ, `records_*` для ШІ | розділ щось зберігає (ремонти, заявки, автопарк, проєкти) |
| Вигляд | `page` | своя сторінка в ізольованому вікні: показники, таблиці, форми, калькулятор, дашборд з кількох розділів | потрібен вигляд, якого нема у стандартному списку |
| Логіка | `agent` | `function run(input)` вручну, зі сторінки або за розкладом (не частіше ніж раз на 5 хв) | щось має відбуватися саме: нагадування, підрахунки, перенесення між розділами |

Можна будь-яку комбінацію. Лише `data` — розділ конструктора (той самий, що створюють вручну). `data` + `page` — свій вигляд над своїми записами (найчастіше). Лише `page` — сторінка-звіт, що читає інші розділи. `agent` без сторінки в меню не ставиться.

Як розділ працює з рештою Helomi: усе — тими самими маршрутами й перевірками, що й у людини. Обов'язкові поля, доступи, журнал змін, тригери спрацьовують самі. Записати можна лише те, що дозволено: свої записи — завжди, інші розділи — лише інструментами з `permissions`. Код Helomi, налаштування компанії, права людей розділ не змінює.

## 3. Формат файлу squaregram-section/1

```json
{
  "format": "squaregram-section/1",
  "slug": "remonty",
  "title": "Ремонти",
  "icon": "flask",
  "description": "Ремонти техніки клієнтів: прийом → діагностика → готово",
  "menu": true,
  "menu_group": "",
  "note": "перша версія",
  "data": { "record_title": "Ремонт", "stages": [], "card": {}, "fields": [], "kanban_field": null, "rules": [] },
  "page": { "html": "<div class=\"sg-sheet\">…</div><style>…</style><script>…</script>" },
  "agent": { "js": "function run(input) { … }", "schedule_minutes": 1440 },
  "permissions": ["tasks_create"]
}
```

### 3.1. Верхній рівень
| поле | обов'язкове | що це |
| --- | --- | --- |
| `format` | так | завжди `squaregram-section/1` |
| `title` | так | назва розділу в меню й галереї: «Ремонти» (множина) |
| `slug` | ні | коротке ім'я в адресі: латиниця, цифри, `_`, до 14 символів (`remonty`). Без нього — з назви |
| `icon` | ні | іконка з набору: folder, clipboard, briefcase, calendar, tasks, documents, products, warehouse, deliveries, clients, structure, star, flag, bulb, gift, card, receipt, map, phone, mail, camera, scale, flask, spark, book. Інша — буде folder |
| `description` | ні | для чого розділ — бачать люди й ШІ |
| `menu` | ні | пропозиція поставити в ліве меню (типово `true`); вирішує людина при встановленні |
| `menu_group` | ні | відділ лівого меню, як він називається в меню («Відділ продажу»); порожньо — верхній список |
| `note` | ні | що змінено в цій версії (журнал версій) |
| `data` | ні* | дані розділу (3.2) |
| `page` | ні* | сторінка (3.3) |
| `agent` | ні* | агент (3.4) |
| `permissions` | ні | інструменти ЗАПИСУ в інші розділи, дозволені сторінці (3.5) |

\* Хоча б одне з `data`, `page`, `agent`.

### 3.2. `data` — записи, поля, етапи
| поле | що це |
| --- | --- |
| `record_title` | назва одного запису: «Ремонт» (у кнопці «+ Ремонт») |
| `stages` | етапи по порядку: `[{"key": "new", "title": "Прийнято", "color": "blue"}, …, {"key": "done", "title": "Готово", "color": "green", "done": true}]`. Кольори: blue, violet, green, yellow, red, gray. `done: true` — завершальний. Без поля — «Нове → В роботі → Готово»; `false` або `[]` — без етапів |
| `card` | що є в картці запису: `{"responsible": true, "client": false, "deal": false, "brand": false, "notes": true, "files": true}` |
| `fields` | поля (нижче), до 60 |
| `kanban_field` | дошка за полем-списком (ключ поля `select`); без нього — за етапом |
| `rules` | передача в інші розділи (нижче) |

Поле: `{"key": "device", "title": "Пристрій", "kind": "text", "required": true, "in_list": true, "on_create": true, "options": [], "block": "Додаткові поля"}`.
- `key` — латиниця, цифри, `_`, з літери, до 40; за ним сторінка й агент читають значення: `record.custom.device`.
- `kind` — text, number, checkbox, date, time, select, multiselect, url, textarea. Для `select` потрібні `options`.
- `required` — без значення запис не збережеться ні людиною, ні сторінкою, ні ШІ. `in_list` — колонка списку. `on_create` — поле у формі створення (обов'язкові — завжди).

Вбудовані поля запису є завжди: `title` (назва), `stage_key` (етап), `responsible_id`, `client_id`, `deal_id`, `brand_id` (якщо увімкнено в `card`). Окремо їх в `fields` не описують.

Правило передачі: `{"title": "Видати клієнту", "when": "stage", "stage": "done", "target": "task", "values": {"title": "Видати клієнту: {title}"}, "link": false}`.
- `when` — `create` (новий запис) або `stage` (запис перейшов на етап `stage`).
- `target` — `deal` (угода), `client` (клієнт), `task` (задача) або `x_<slug>` іншого власного розділу.
- `values` — поле цілі → шаблон з полів запису: `{id}`, `{title}`, `{stage}`, `{stage_key}`, `{responsible_id}`, `{client_id}`, `{custom.<ключ>}`. Поля цілі: угода — title, client_id, funnel_id, stage_id, source_id, responsible_id, comment, deadline_at, important, `custom.<ключ>`; клієнт — company, person, phones, emails, source_id, main_responsible_id, comment, tags; задача — title, description, due_at, assignee_id, deal_id, client_id, priority, important.
- `link: true` — прив'язати створену угоду чи клієнта до запису (якщо в `card` увімкнено `deal` / `client`).

### 3.3. `page` — сторінка
`{"html": "…"}` — розмітка, `<style>` і `<script>` разом, до 400 000 символів. Сторінка живе в ізольованому вікні (iframe без доступу до токена, cookies, мережі й інших сайтів). Оболонку (шрифт Onest, токени й класи NeoHelomi, міст `sg`) дає Helomi — `<html>`, `<head>`, шрифти й бібліотеки не підключайте. Зовнішні `<script src>`, `fetch`, `XMLHttpRequest`, `WebSocket` заблоковані: дані — лише через `sg`.

### 3.4. `agent` — логіка
`{"js": "function run(input) { … }", "schedule_minutes": 60}` — до 120 000 символів, обов'язково `function run(input)`. `schedule_minutes` — запуск за розкладом (не частіше ніж раз на 5 хвилин); без нього — вручну («Запустити агента») і зі сторінки (`sg.runAgent`). Див. розділ 7.

### 3.5. `permissions`
Список інструментів ЗАПИСУ, які дозволено сторінці: `["tasks_create", "deals_add_note"]`. Читати сторінка може й без них. Свої записи (`sg.records.create/update`) — без дозволу. Назви інструментів — з `sections_package_guide.tools` або `describe_section`. Основні: `deals_create`, `deals_update`, `deals_change_stage`, `deals_add_note`, `deals_add_task`, `clients_create`, `clients_update`, `clients_add_note`, `tasks_create`, `tasks_update`, `records_create`, `records_update` (записи інших власних розділів).

### 3.6. Один `.html` замість `.json`
Можна віддати один файл `<ім'я>.html`: сторінка — як є, а опис і дані — у блоці `<script type="application/json" id="sg-section">{"title": "…", "icon": "…", "data": {…}, "permissions": […]}</script>`, агент — у `<script type="text/x-sg-agent" id="sg-agent">function run(input) { … }</script>`. Обидва блоки при встановленні вирізаються зі сторінки. Повний документ (`<!doctype html><html><head>…<body>…`) теж приймається: беруться стилі з `<head>` і вміст `<body>`; `<title>` стає назвою, якщо її нема в описі. Обгортка ```` ```json … ``` ```` з чату теж приймається.

## 4. Стиль NeoHelomi — обов'язково
Сторінка має виглядати як рідний розділ Helomi. Порушення стилю перевірка показує зауваженням — виправляйте наступною версією.

**Головне:** світле полотно дає програма; ваш вміст — шарами прозорого білого скла; тіней і рамок нема; великі радіуси; **чорне на екрані одне** (головна дія); червоне — лише увага (крапка, помилка); статуси — пастельні пігулки; іконки контурні; без смайликів; шрифт Onest (уже підключено).

Заборонено: свої кольори (`#hex`, `rgb()`, `hsl()`), свої тіні й рамки, градієнти, темні панелі, смайлики, `alert/confirm/prompt`, другий чорний елемент, зовнішні шрифти й бібліотеки. Колір, відступ, радіус — лише `var(--sg-…)`.

### 4.1. Шари
| шар | клас | для чого |
| --- | --- | --- |
| лист | `.sg-sheet` | одна робоча область сторінки (відступ 20–24, на телефоні 14) |
| група | `.sg-group` | блок усередині листа: таблиця, форма, колонка дошки, панель фільтрів |
| картка | `.sg-card` | окремий запис, показник; поле вводу вже має цей вигляд |
| рядок | `.sg-row` | пласкі рядки списку всередині групи (фон з'являється при наведенні) |
| суцільне | `.sg-pop` | випадне меню, вікно поверх сторінки |

Не більше трьох рівнів скла: лист → група → картка. Четвертий — рядок `.sg-row`.

### 4.2. Компоненти
- **Шапка:** `<h1 class="sg-title">Назва</h1>` + `<span class="sg-muted">підзаголовок</span>`; праворуч одна головна дія `<button class="sg-btn sg-btn--black">`.
- **Кнопки:** головна `.sg-btn.sg-btn--black` (одна); другорядні `.sg-btn.sg-btn--white` або `.sg-btn.sg-btn--line`; дрібні — `+ .sg-btn--sm`. Кругла кнопка-іконка — `.sg-circ` (44 px) / `.sg-circ.sg-circ--sm` (34 px), всередині `sg.icon("…")`.
- **Вкладки:** `.sg-tabs` → `.sg-tab` (активна `.is-active` — чорна пігулка); дрібний перемикач — `.sg-seg` з кнопками (`.is-active`).
- **Форми:** `.sg-field` → `<label>` + `input.sg-input` / `select.sg-select` / `textarea.sg-input.sg-textarea`; прапорець `input.sg-check`. Висота полів 40 px, пігулки.
- **Таблиці:** `.sg-table-wrap` → `table.sg-table` (щільні рядки, липка шапка); числа й суми — клас `.sg-num` (праворуч, табличні цифри).
- **Статуси:** `.sg-pill` + `--blue | --violet | --green | --yellow | --red | --gray`, дрібні `.sg-pill--sm`. Колір етапу запису — `record.stage.color` → `sg-pill--<color>`.
- **Текст:** `.sg-title` (30/500), `.sg-h2` (20/500), `.sg-h3`; підпис групи `.sg-cap` (великі літери); другорядне `.sg-muted`, `.sg-faint`.
- **Показники:** `.sg-kpi` з `<small>` (підпис) і `<b>` (число); один на екрані може бути `.sg-kpi--black`.
- **Дошка:** `.sg-kanban` → `.sg-kanban-col` (група-колонка) → `.sg-cap` з назвою етапу → `.sg-card` записів.
- **Порожньо й завантаження:** `.sg-empty` з одним реченням, що робити; скелет — `.sg-skeleton`. Помилка — `.sg-error`.
- **Іконки:** лише `sg.icon("назва", розмір)` — SVG-рядок у `innerHTML`. Назви: як у полі `icon` (3.1) і ще plus, minus, close, search, filter, edit, trash, check, chevron-down, chevron-right, refresh, download, export, import, copy, eye, calendar, clock, bell, link, pin, settings, deals, clients, chats, phone, mail, finance, coins, dashboard, agent, alert, more.

### 4.3. Токени (CSS-змінні)
Кольори тексту: `--sg-ink` (основний), `--sg-ink-2`, `--sg-muted` (підписи), `--sg-faint`. Чорне: `--sg-black`, текст на ньому `--sg-on-black`. Увага: `--sg-attention`. Скло: `--sg-sheet`, `--sg-group`, `--sg-card`, `--sg-solid`, розмиття `--sg-blur`, кромка `--sg-glass-edge`. Лінії: `--sg-line` (розділювач), `--sg-outline` (контур кнопки), `--sg-outline-field`, `--sg-outline-focus`. Пастелі статусів: `--sg-pastel-blue|violet|green|yellow|red|gray` і текст `--sg-pastel-<колір>-ink`. Радіуси: `--sg-r-sheet` 34, `--sg-r-group` 26, `--sg-r-card` 20, `--sg-r-row` 16, `--sg-r-pill`. Відступи: `--sg-space-1…8`. Розміри: `--sg-ctl-h` (40), `--sg-circ` (44), `--sg-fs-title`, `--sg-fs-h2`, `--sg-fs-body`, `--sg-fs-sm`, `--sg-fs-xs`, `--sg-fs-cap`. Шрифт: `--sg-font`.

### 4.4. Свій CSS і телефон
- Свій CSS — у `<style>` сторінки, класи з власним префіксом (`.rp-…`), значення лише `var(--sg-…)`. Розкладку (grid, flex) пишіть на своїх класах.
- Телефон від 390 px: сітки `grid-template-columns: repeat(auto-fill, minmax(240px, 1fr))`; на `@media (max-width: 768px)` рядки таблиць стають картками, кнопки й поля — на всю ширину, зони торкання ≥ 44 px, без горизонтальної прокрутки сторінки.
- Висоту вікна Helomi підлаштовує сам за вмістом — не задавайте `height: 100vh` і не робіть внутрішньої прокрутки сторінки.
- Елемент з атрибутом `hidden`, якому ви задали свій `display` (grid, flex), браузер усе одно покаже — допишіть `.ваш-клас[hidden] { display: none; }`.

## 5. Міст sg на сторінці
Усе асинхронне (`await`). Помилка → `throw Error` з реченням українською, показуйте її людині (`sg.toast(e.message)` або `.sg-error`).

| виклик | що робить |
| --- | --- |
| `sg.user` | `{id, name, admin}` — хто відкрив сторінку (є після події `sg:ready` на `document`) |
| `sg.section` | `{slug, title, data_slug}` — цей розділ; `data_slug` — його дані (є одразу) |
| `await sg.records.meta()` | опис даних розділу: етапи, поля (`key`, `title`, `kind`, `options`, `required`), відповідальні |
| `await sg.records.list({q, stage, responsible_id, client_id, archived, sort, dir, page, per_page, f_<ключ>})` | записи: `{items, total, page, pages}`; запис — `{id, title, stage: {key, title, color, done}, stage_key, responsible: {id, name}, client, custom: {ключ: значення}, archived, created_at, updated_at}` |
| `await sg.records.get(id)` | картка запису: поля, нотатки, файли, журнал |
| `await sg.records.kanban({q})` | дошка: колонки етапів (або поля-списку) з записами |
| `await sg.records.create({title, stage_key, responsible_id, client_id, custom: {…}})` | новий запис (обов'язкові поля діють) |
| `await sg.records.update(id, {stage_key, custom: {…}})` | змінити запис (журнал змін, правила передачі) |
| `await sg.read("/api/crm/deals", {q: "Петро", per_page: 20})` | **читання будь-якого розділу CRM** у межах прав людини (розділ 6) |
| `await sg.call("tasks_create", {values: {title: "…"}})` | інструмент (ті самі, що в ШІ): читання — завжди, запис — лише з `permissions` |
| `await sg.data.get(col, key)` / `set(col, key, value)` / `list(col)` / `del(col, key)` | сховище розділу (налаштування, кеш): JSON до 64 КБ на запис |
| `await sg.runAgent(input)` | запустити агента → `{ok, result, error, logs}` |
| `sg.navigate("/crm/deals/123")` | перейти в розділ Helomi |
| `sg.toast("Збережено")` | коротке повідомлення |
| `await sg.confirm("Видалити?")` | підтвердження в стилі програми → `true/false` |
| `sg.icon("plus", 18)` | SVG-рядок фірмової іконки |

## 6. Що можна читати: адреси даних CRM
`sg.read(шлях, параметри)` читає лише `/api/crm/…`, `/api/help/…` і `/api/ai/catalog`; користувачі, ключі інтеграцій і секрети закриті. Права — того, хто відкрив сторінку: чого людина не бачить, сторінка теж не прочитає.

| шлях | що повертає | параметри |
| --- | --- | --- |
| `/api/crm/deals` | угоди: `id, title, stage, funnel, client {company, person}, total_amount, paid_amount, credit_amount, responsible, custom, ordered_at, updated_at` | q, funnel_id, stage_id, source_id, responsible_id, client_id, archived, overdue, date_from, date_to, page, per_page, sort, order |
| `/api/crm/deals/{id}` | картка угоди з позиціями, оплатами, доставкою | — |
| `/api/crm/clients` | клієнти: `id, company, person, phones, emails, source, responsible, custom` | q, source_id, responsible_id, tags, archived, page, per_page |
| `/api/crm/tasks` | задачі: `id, title, status, due_at, assignee, deal, client, done` | q, status, responsible_id, mine, overdue, due_from, due_to, deal_id, client_id |
| `/api/crm/products` | товари: `id, sku, title, price, cost, stock, reserved, free` | q, category_id, in_stock, page, per_page |
| `/api/crm/x/<slug>` | записи будь-якого власного розділу | як у `sg.records.list` |
| `/api/help/<key>` | стаття WIKI | — |

Відповіді списків: `{items, total, page, pages}`. Не більше 200 на сторінку — для великих даних гортайте `page`.

## 7. Агент: логіка за розкладом
```js
function run(input) {                 // input: {trigger: "schedule"} або те, що передала сторінка через sg.runAgent
  var stuck = sg.records.list({ stage: "diag", per_page: 50 });
  stuck.items.forEach(function (r) {
    sg.call("tasks_create", { values: { title: "Ремонт застряг: " + r.title } });
  });
  sg.log("застрягли", stuck.items.length);
  return { stuck: stuck.items.length };
}
```
- У агента виклики **синхронні** (без `await`): `sg.records.list/get/meta/create/update`, `sg.call`, `sg.data.get/set/list/delete`, `sg.log`; `sg.section` — як на сторінці.
- У списках агента значення — короткі: `stage` — назва етапу, `stage_key` — ключ, `client` і `responsible` — імена, `custom` — словник полів.
- Мережі, файлів, таймерів нема; 30 секунд і 300 викликів на прогін; без `while(true)`.
- Агент працює від імені свого ШІ-співробітника «<назва> · агент». Дані свого розділу він бачить одразу; інші розділи (задачі, угоди) людина відкриває йому в «Налаштування → Команда → ШІ-співробітники → <агент> → Доступи». Видалення, гроші, масові дії й відправки чекають підтвердження людини.
- Агент не створює розділів, агентів і розширень — лише працює з даними.

## 8. Повний приклад: розділ «Ремонти»
Файл `remonty.sgsection.json` — дані, сторінка з показниками, формою й таблицею, агент щодня:

```json
{
  "format": "squaregram-section/1",
  "slug": "remonty",
  "title": "Ремонти",
  "icon": "flask",
  "description": "Ремонти техніки клієнтів: прийом → діагностика → готово",
  "menu": true,
  "data": {
    "record_title": "Ремонт",
    "stages": [
      {"key": "new", "title": "Прийнято", "color": "blue"},
      {"key": "diag", "title": "Діагностика", "color": "yellow"},
      {"key": "done", "title": "Готово", "color": "green", "done": true}
    ],
    "card": {"responsible": true, "client": true, "deal": false, "brand": false, "notes": true, "files": true},
    "fields": [
      {"key": "device", "title": "Пристрій", "kind": "text", "required": true},
      {"key": "kind", "title": "Тип ремонту", "kind": "select", "options": ["Гарантія", "Платний"]},
      {"key": "price", "title": "Вартість", "kind": "number"}
    ],
    "rules": [
      {"title": "Видати клієнту", "when": "stage", "stage": "done", "target": "task",
       "values": {"title": "Видати клієнту: {title}"}, "link": false}
    ]
  },
  "page": {"html": "<div class=\"sg-sheet rp\"><header class=\"rp-head\"><div><h1 class=\"sg-title\">Ремонти</h1><span class=\"sg-muted\">техніка клієнтів у роботі</span></div><button class=\"sg-btn sg-btn--black\" id=\"add\">+ Ремонт</button></header><div class=\"rp-kpis\" id=\"kpis\"></div><form class=\"sg-group rp-form\" id=\"form\" hidden><div class=\"sg-field\"><label>Назва *</label><input class=\"sg-input\" name=\"title\" required placeholder=\"Ноутбук Петра\"></div><div class=\"sg-field\"><label>Пристрій *</label><input class=\"sg-input\" name=\"device\" required></div><div class=\"sg-field\"><label>Тип ремонту</label><select class=\"sg-select\" name=\"kind\"><option>Гарантія</option><option>Платний</option></select></div><div class=\"sg-field\"><label>Вартість, грн</label><input class=\"sg-input\" name=\"price\" type=\"number\" min=\"0\"></div><div class=\"rp-foot\"><button class=\"sg-btn sg-btn--white\" type=\"button\" id=\"cancel\">Скасувати</button><button class=\"sg-btn sg-btn--line\" type=\"submit\">Створити</button></div></form><div class=\"sg-group\"><div class=\"sg-table-wrap\"><table class=\"sg-table rp-table\"><thead><tr><th>Ремонт</th><th>Пристрій</th><th>Етап</th><th class=\"sg-num\">Вартість</th></tr></thead><tbody id=\"rows\"><tr><td colspan=\"4\"><div class=\"sg-skeleton\" style=\"height: 40px\"></div></td></tr></tbody></table></div></div></div><style>.rp { padding: 24px; display: grid; gap: 14px; } .rp-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; } .rp-kpis { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; } .rp-form { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; padding: 16px; } .rp-form[hidden] { display: none; } .rp-foot { display: flex; gap: 8px; align-items: end; } @media (max-width: 768px) { .rp { padding: 14px; } .rp-head .sg-btn, .rp-foot .sg-btn { flex: 1 1 auto; } .rp-table thead { display: none; } .rp-table tr { display: grid; grid-template-columns: 1fr auto; gap: 4px; padding: 10px 0; } .rp-table td { border: 0; padding: 0 10px; } }</style><script>function esc(v) { return String(v == null ? '' : v).replace(/[&<>\"']/g, function (c) { return {'&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;'}[c]; }); } async function load() { try { var r = await sg.records.list({ per_page: 100 }); var work = r.items.filter(function (x) { return !(x.stage && x.stage.done); }); var sum = work.reduce(function (s, x) { return s + (Number(x.custom.price) || 0); }, 0); document.getElementById('kpis').innerHTML = '<div class=\"sg-kpi\"><small>У роботі</small><b>' + work.length + '</b></div><div class=\"sg-kpi\"><small>Готово</small><b>' + (r.items.length - work.length) + '</b></div><div class=\"sg-kpi\"><small>Сума в роботі, грн</small><b>' + sum.toLocaleString('uk-UA') + '</b></div>'; document.getElementById('rows').innerHTML = r.items.length ? r.items.map(function (x) { return '<tr><td>' + esc(x.title) + '</td><td>' + esc(x.custom.device) + '</td><td>' + (x.stage ? '<span class=\"sg-pill sg-pill--sm sg-pill--' + esc(x.stage.color) + '\">' + esc(x.stage.title) + '</span>' : '') + '</td><td class=\"sg-num\">' + esc(x.custom.price) + '</td></tr>'; }).join('') : '<tr><td colspan=\"4\"><div class=\"sg-empty\">Ремонтів поки немає — натисніть «+ Ремонт»</div></td></tr>'; } catch (e) { sg.toast(e.message); } } var form = document.getElementById('form'); document.getElementById('add').onclick = function () { form.hidden = false; form.title.focus(); }; document.getElementById('cancel').onclick = function () { form.hidden = true; }; form.onsubmit = async function (ev) { ev.preventDefault(); try { await sg.records.create({ title: form.title.value, custom: { device: form.device.value, kind: form.kind.value, price: form.price.value ? Number(form.price.value) : null } }); form.reset(); form.hidden = true; sg.toast('Ремонт додано'); load(); } catch (e) { sg.toast(e.message); } }; load();</script>"},
  "agent": {"js": "function run(input) { var stuck = sg.records.list({ stage: 'diag', per_page: 50 }); stuck.items.forEach(function (r) { sg.call('tasks_create', { values: { title: 'Ремонт застряг: ' + r.title } }); }); sg.log('застрягли', stuck.items.length); return { stuck: stuck.items.length }; }", "schedule_minutes": 1440},
  "permissions": []
}
```

Агенту прикладу потрібен доступ до «Завдань»: після встановлення людина відкриває його в «Доступах» агента «Ремонти · агент».

## 9. Те саме одним файлом .html
```html
<div class="sg-sheet rp">
  <header class="rp-head">
    <div><h1 class="sg-title">Ремонти</h1><span class="sg-muted">техніка клієнтів у роботі</span></div>
    <button class="sg-btn sg-btn--black" id="add">+ Ремонт</button>
  </header>
  <div class="sg-group"><div class="sg-table-wrap"><table class="sg-table"><tbody id="rows"></tbody></table></div></div>
</div>
<style>.rp { padding: 24px; display: grid; gap: 14px; } .rp-head { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }</style>
<script>
  sg.records.list({ per_page: 100 }).then(function (r) {
    document.getElementById("rows").innerHTML = r.items.map(function (x) { return "<tr><td>" + x.title + "</td></tr>"; }).join("");
  });
</script>
<script type="application/json" id="sg-section">
{"format": "squaregram-section/1", "slug": "remonty", "title": "Ремонти", "icon": "flask",
 "data": {"record_title": "Ремонт", "fields": [{"key": "device", "title": "Пристрій", "kind": "text", "required": true}]}}
</script>
<script type="text/x-sg-agent" id="sg-agent">
function run(input) { return { total: sg.records.list({}).total }; }
</script>
```
(У справжньому файлі екрануйте значення від людей, як `esc()` у розділі 8.)

## 10. Оновити розділ
1. «Власні розділи» → плитка → «⋯» → «Файл розділу» — завантажиться поточний файл.
2. Дайте його ШІ: «Додай поле "Майстер" і колонку на сторінці».
3. Перетягніть новий файл у квадрат «+ Додати розділ». Перевірка побачить, що такий розділ уже є, і запропонує «Оновити «Ремонти»» (або «Окремий розділ»).
4. Що станеться: нові поля додаються, наявні змінюють назву й прапорці (тип поля зі значеннями не змінюється); поля, яких нема у файлі, лишаються — видаляє людина в «Типах даних»; записи не чіпаються; сторінка й агент — нова версія, попередню повертає «Налаштування → Типи даних → Розширення → Версії».

## 11. Меню зліва і доступ
- Кожна плитка в галереї має перемикач «У меню зліва» і вибір відділу. Ставить і знімає лише людина з доступом до «Налаштувань CRM»; порядок пунктів — перетягуванням плиток. Кожен ще може сховати пункт лише для себе в «Моє меню».
- Пункт бачать ті, кому розділ доступний: розділ з даними — галочка «x:<slug>», сторінка без даних — «xe:<slug>» (людям типово відкрито, ШІ — лише відкритий явно).
- Окремого пункту «Розділи» в меню нема: розділ, якого нема в меню, відкривається з галереї, за адресою або кнопкою на панелі швидкого доступу.

## 12. Чеклист ШІ перед тим, як віддати файл
- [ ] `format` — `squaregram-section/1`, є `title`, `slug` латиницею до 14 символів, `icon` з набору.
- [ ] Ключі полів латиницею; у `select` є `options`; обов'язкові — лише справді обов'язкові.
- [ ] Сторінка: один `.sg-sheet`, групи `.sg-group`, одна чорна кнопка, лише `var(--sg-…)` і класи `sg-*`, без смайликів і своїх кольорів.
- [ ] Значення від людей екрануються перед `innerHTML`.
- [ ] Порожньо, завантаження (`.sg-skeleton`) і помилка (`sg.toast(e.message)`) продумані.
- [ ] Сховані `hidden` елементи зі своїм `display` мають правило `[hidden] { display: none; }`.
- [ ] Телефон 390 px: без горизонтальної прокрутки, кнопки на всю ширину, таблиця → картки.
- [ ] Дані — лише через `sg.records` / `sg.read` / `sg.call`; запис в інші розділи — інструменти в `permissions`.
- [ ] Агент: `function run(input)`, без нескінченних циклів, до 300 викликів, розклад ≥ 5 хв.
- [ ] Ви (ШІ-співробітник) спершу викликали `sections_package_check` і виправили помилки.

## Можливі помилки
| Що ви бачите | Чому | Що зробити |
| --- | --- | --- |
| «Файл не є JSON: …» | Пошкоджений JSON (кома, лапки) | Попросіть ШІ віддати файл заново або вставити як `.html` |
| «Не впізнаю файл: потрібен .json або .html» | Інший формат | Попросіть у ШІ файл розділу за цією інструкцією |
| «Назвіть розділ: поле title» | Нема назви | Додайте `title` |
| «Файл нічого не створює…» | Нема ні `data`, ні `page`, ні `agent` | Додайте хоча б одне |
| «Поле «…» (список): потрібні варіанти options» | `select` без варіантів | Додайте `options` |
| «Поле «…»: тип має бути одним із …» | Невідомий `kind` | Візьміть тип з розділу 3.2 |
| «Агент має оголосити function run(input) { … }» | Нема функції `run` | Оголосіть її |
| «Розклад агента — не частіше ніж раз на 5 хвилин» | Замалий `schedule_minutes` | 5 або більше |
| «Невідомий інструмент у permissions: …» | Такого інструмента нема | Назва з `sections_package_guide.tools` |
| «Розділ «…» уже є (e:…) — передайте update…» | Такий розділ уже встановлено | «Оновити» або «Окремий розділ» |
| «У меню зліва ставиться розділ зі сторінкою…» | Лише агент | Додайте сторінку або лишіть поза меню |
| «Дані розділу ШІ створює з правом творця «Свої розділи»» / «Сторінку й агента … «Свої розширення (код)»» | У ШІ нема права | Адміністратор видає право в «Доступах» ШІ |
| «Цей розділ створив не цей ШІ…» | ШІ оновлює чужий розділ | ШІ змінює лише свої розділи |
| «Власні розділи налаштовує людина з доступом до «Налаштувань CRM»» | Немає доступу | Попросіть адміністратора |
| На сторінці «Немає доступу до розділу …» | Галочку розділу закрито | Адміністратор відкриває доступ |
| Зауваги «Стиль: …» | Свої кольори, смайлики, alert, тіні | Не блокують; виправте наступною версією |

## Для ШІ-співробітників
Права: дані (`data`) — право творця «Свої розділи»; сторінка й агент — «Свої розширення (код)». Змінювати можна лише свої розділи. У меню зліва ставить людина.

| Інструмент | Що робить |
| --- | --- |
| `sections_package_guide` | СПОЧАТКУ ПРОЧИТАЙТЕ: ця стаття і живі довідники — іконки, типи полів, кольори етапів, інструменти для `permissions` |
| `sections_gallery` | Розділи організації плитками: `id` (`e:<n>` — з кодом, `t:<n>` — конструктор), `mine`, дані, меню |
| `sections_package_check` | Перевірити файл без запису: `values: {package: {…}}` або `{content: "<текст .json/.html>"}`, `update?` → `ok`, `actions`, `errors`, `warnings`, `conflict` |
| `sections_package_install` | Встановити: `values: {package, file_name?, update?, as_new?}` → `{id, url, created, warnings}` |
| `sections_package_export` | Мій розділ файлом (`tile_id`) — доробити й встановити з `update` |

Порядок: `sections_package_guide` → (`sections_gallery`, чи нема вже такого) → `sections_package_check` → виправити `errors` і по змозі `warnings` → `sections_package_install` → сказати людині: «Розділ «…» встановлено, увімкніть його в лівому меню: Налаштування → Типи даних → Власні розділи → «У меню зліва»». Після встановлення з даними — `records_meta`, `records_list`, `records_create`, `records_update` зі `slug` розділу. Конфлікт (`conflict`) — свій розділ оновлюйте `update: "<id>"`, чужий не чіпайте: запропонуйте людині `as_new`.

Чого не робити:
- Не вигадувати іконки, типи полів, назви інструментів — брати з `sections_package_guide`.
- Не ставити `update` на чужий розділ і не видаляти поля через файл (поля, яких нема у файлі, лишаються).
- Не писати своїх кольорів, смайликів, мережевих запитів; не просити людину вимкнути перевірки.

## Додаткова інформація
- Пов'язані статті: [Власні розділи](custom-sections.md), [Розширення (код)](extensions.md), [ШІ-творець](ai-creator.md), [Моє меню](my-menu.md).
