Впервые в системе? Начните с гайда С чего начать.
Встроенная документация приложения. Читается двумя способами:
docs рендерит эти же файлы
(оглавление: /docs/index), дополняя их подсказками из кода.attributeData()['<attr>']['hint'] - короткая подсказка атрибута
(1–3 предложения, до ~300 символов). Показывается тултипом у поля.
Обязательна для каждого пользовательского атрибута - контролируется
сторожевым тестом. Минимальная HTML-разметка допустима (<br>, <b>,
<i>, muted); структура документа (заголовки, разделы) - признак, что
тексту место в слое 2.typeClass) дают свою часть
подсказки методами inputHint() (как заполнять) и searchHint()
(как искать). Итоговый тултип атрибута = специфичная часть + типовая
(типовая выводится приглушённо).modelDescription() - короткое описание сущности (что это, зачем).
Показывается popover’ом на страницах списка/карточки.Стандарт формулировок (чтобы конкатенация частей читалась естественно):
| Текст | Отвечает на вопрос | Пример |
|---|---|---|
| hint атрибута | что здесь хранится и зачем | “MAC адреса сетевых интерфейсов оборудования” |
inputHint() типа |
как вводить: формат, множественность | “В каждой строке - один адрес или диапазон…” |
searchHint() типа |
как искать: только отличия от общего синтаксиса | “Поиск по диапазону - только полным MAC…” |
Hint атрибута не описывает формат (это даст тип); типовые подсказки не упоминают конкретные модели.
Правило актуальности: изменил семантику поля или модели - обнови hint/описание в том же коммите.
Длинные тексты в коде не живут. Для каждой модели/атрибута/типа может существовать MD-файл, который приложение подтягивает вторым слоем. Из тултипа атрибута ведут раздельные подписанные ссылки - на страницу атрибута (“подробнее: Оборудование → MAC адреса”) и на страницу типа (“подробнее о типе: MAC-адреса”); каждая показывается только если её страница существует:
docs/help/
README.md оглавление и эта конвенция
models/<class-id>.md подробное описание модели/сущности
models/<class-id>/<attr>.md подробное описание атрибута (опционально)
types/<type-id>.md описание типа данных (одно на все модели)
guides/*.md сквозные сценарии работы
admin/*.md установка, обновление, интеграции
img/* изображения (минимум - тяжело поддерживать)
<class-id> - kebab-case идентификатор модели, как у контроллера
(comps, tech-models); <attr> - имя атрибута модели.### Удаление в конце
«Просмотра» (так же «Копирование» и прочие действия карточки).
H2 вне канона оставляем только концепциям (жизненный цикл, связи,
архивность), не привязанным к конкретной странице.models/<class-id>/<attr>.md. Страница
сущности в приложении (/docs/model) собирается без дублей: заголовок
странице даёт код (H1 документа отбрасывается), концепцию - MD-страница
(modelDescription показывается только фолбэком, когда MD нет), ниже -
генерируемый справочник атрибутов, из которого атрибутные страницы
открываются ссылками “подробнее” модалкой - “ссылка вместо пересказа”,
вторым сборником они не разворачиваются. Тултип поля ведёт на то же
фокусное описание атрибута.
Страница модели - только концепция: что это, жизненный цикл, связи,
сценарии.Контроллер docs: оглавление, рендер страниц, отдача картинок.
Заказчик может переопределять и дополнять страницы: каталог с той же
структурой указывается в params['docsOverridePath'] и просматривается
первым.
Слой 1 не “лежит в коде” - он выводится самим интерфейсом: описание атрибута или элемента живёт НА нём (иконка “?” у подписи, тултип объекта), а не пересказывается текстом страницы-описания (принцип element-locality - справка по странице описывает лишь композицию странице не перечисляя атрибуты/поля).
Единая точка вывода - ModelFieldWidget + сборщик тултипов AttributeTooltip.
Инструменты:
- подпись с “?” (renderFieldTitle)
- значение со скрытой до help-mode “?” (renderFieldValueHinted)
- заголовок составного блока с агрегированными hint’ами нескольких атрибутов (renderCompositeTitle)
- цепочка положения (ChainWidget)
- режим help-mode (подсветка всех “?”).
Механизмы описаны в ui-sources.md (§0.1 и §3) - здесь не дублируются.
Правило: составной/нестандартный рендер в карточке делай самодокументируемым этими инструментами, а не текстом-пересказом (или заведи MD слоя 2 и сошлись на него).
Текст, сгенерированный ИИ по коду без вычитки человеком, помечается меткой TODO-REVIEW
(в PHP - комментарием рядом с hint/modelDescription, в MD - строкой > ⚠ TODO-REVIEW: ...).
Найти всё непроверенное: grep -rn "TODO-REVIEW" models modules docs.
После вычитки и правки метка удаляется.
# Заголовок (используется как title страницы
в приложении и в оглавлении).../guides/page.md): работают и на GitHub, и в приложении
(приложение переписывает их на свои маршруты).img/; допустимые форматы:
png, jpg, jpeg, gif, svg, webp. Но их избегаем: не версионируются
осмысленно, устаревают, требуют актуализации после каждого изменения UI.setup.md#авторизация):
приложение проставляет заголовкам те же id, что GitHub (нижний регистр,
пунктуация выброшена, пробелы -> дефисы), поэтому одна ссылка работает
в обоих местах чтения. Свой якорь заголовка задаётся в MD как
## Заголовок {#свой-id}.[Основной документ](models/contracts.md#attr-parent_id). Якоря #attr-<имя>
не пишутся в MD руками - приложение проставляет их само на строках
справочника атрибутов страницы сущности (/docs/model), а такие ссылки
переписывает на неё же (а не на голый MD, где справочника нет). Так
ссылаться можно на любой атрибут - и на тот, у которого нет своей
страницы models/<class-id>/<attr>.md. Латинское имя атрибута
в справочнике - само себе ссылка: адрес якоря видно и можно скопировать.
На GitHub такая ссылка ведёт на страницу модели (якоря там нет -
открывается её начало), поэтому для атрибутов со своей страницей
предпочтительна прямая ссылка на неё.#doc-anchor: (см. ниже).
Ничего дополнительно в MD для этого писать не надо.Когда описание должно указать на конкретный элемент на странице (а перенос текста в тултип элемента неестественен - элемент далеко или описание якорное), свяжите строку описания с элементом по ключу:
[текст](#doc-anchor:КЛЮЧ)
(её якорный href переживает рендер - приложение переписывает только ссылки на
соседние .md/картинки);<a href="#doc-anchor:КЛЮЧ">текст</a> (обработчик делегирован на весь
документ и срабатывает и из всплывающего тултипа) - так подсказка одного
элемента может подсветить связанный элемент;data-doc-anchor="КЛЮЧ".Клик по такой ссылке в инфоблоке документации проскроллит к элементу и на пару
секунд подсветит его. Если элемента на текущей странице нет - ссылка ничего не
делает (ведёт себя как обычный якорь). КЛЮЧ - короткий kebab-slug, уникальный
в пределах страницы. Так подсказка по странице ссылается на элемент,
а не пересказывает его текстом.
В приложении ссылки-подсветки автоматически маркируются (пунктирное подчёркивание + значок-прицел, site.css по префиксу href) - читатель заранее видит, что клик подсветит элемент на этой же странице, а не уведёт с неё. В MD для этого ничего дополнительно писать не надо; на GitHub такие ссылки выглядят обычными и просто ничего не делают.
Когда целей много и размечать каждую атрибутом расточительно (заголовки сортировки, строка фильтров таблицы), элементы ищутся CSS-селектором - подсвечиваются все совпадения, скролл к первому:
[заголовку](<#doc-select:.grid-view th a[data-sort]>)
[полями фильтров](<#doc-select:.grid-view .filters input>)
<угловых скобках> - из-за пробелов в селекторе (это
штатный markdown, GitHub и приложение понимают одинаково); без пробелов
скобки не нужны. Символ > внутри селектора кодируется как %3E.a[data-sort] у Yii-сортировки, .filters у строки фильтров GridView,
Bootstrap-классы), а не по нашей вёрстке: селектор в MD молча умирает при
переименовании класса, и сторожевым тестом это не ловится. Всё специфичное
для одной страницы/формы - по-прежнему #doc-anchor: с меткой на элементе.<a href="#doc-select:СЕЛЕКТОР">текст</a> (пробелы в HTML-атрибуте легальны).models/ - сущности: заполняется по мере миграции контента из wiki.types/ - типы данных.guides/ - сценарии: “как завести рабочее место”, “как оформить закупку”…admin/ - установка, обновление (в т.ч. Docker), интеграции, бэкапы.