Правила для редактирования apps/docs (MDX-контент + компоненты),
которые не видны из кода и уже не раз нас кусали.
У сайта два пути рендеринга: Next.js рендерит MDX через React, и
scripts/generate-llms.ts уплощает MDX в Markdown для /llms-full.txt
и постраничных .md. Компонент, добавленный для сайта, о котором
flattener не знает, утекает сырым тегом <Component> в AI-facing
Markdown.
Добавляя компонент, регистрируй его во всех трёх:
apps/docs/components/mdx/mdx-components.tsx— определение + добавить вcustomMdxComponents.apps/docs/components/api/markdown-content.tsx— импорт + добавить в объектcomponents, который передаётся вMDXRemote(без этого — runtime-ошибка «component is not defined»).apps/docs/lib/mdx-expander.ts— обработчик вexpandMdxComponents(), который превращает JSX в обычный Markdown (или раскрывает внутренний контент для layout-обёрток вроде<CardRow>/<ParamsTable>). Без этого сырые теги утекают вpublic/**/*.mdиpublic/llms-full.txt.
Проверка: после npx turbo build команда
grep -n "ComponentName" apps/docs/public/llms-full.txt apps/docs/public/api/*.md
должна ничего не вернуть. То же правило для HTML-entity типографики
( , ­, …) — заменяй/убирай в expander'е, в AI-facing Markdown
они попадать не должны.
Не делай export { X } from '...' в mdx-components.tsx — Turbopack
может не зарезолвить компонент в runtime. Вместо этого: в
mdx-components.tsx — import для customMdxComponents, в
markdown-content.tsx — импорт напрямую из файла-источника
(@/components/mdx/steps и т.п.).
turbo checkловит ошибки типов, но не проблемы резолва модулей Turbopack — всегда тестируй в runtime (bun turbo dev) после добавления / регистрации компонента.- После изменения регистраций компонентов или добавления TS/TSX-файлов —
перезапусти dev-сервер (
pkill -f "next dev",rm -rf apps/docs/.next, потомbun turbo dev). Turbopack HMR часто их пропускает. - Next.js: оставаться на 16.0.x (16.0.10). 16.1.x ломает
next dev --turbopack(server-external-packages.jsonпереименован в.jsonc, Turbopack всё ещё ждёт.json). Build работает, ломается только dev. Перепроверять перед апгрейдом. - Middleware Next 16 живёт в
apps/docs/proxy.ts(Next переименовалmiddleware.ts→proxy.ts). Если оба файла присутствуют — build падает.
В MDX-заголовках (##, ###) и в <Step title="..."> нельзя
использовать: em dash —, стрелки → ← ⇒, плюс +, латинизм vs и
inline-код / backticks (`guest`, `chat_ids`). Заголовки
попадают в боковой TOC и там смотрятся как шум; backticks в заголовке
не рендерятся как код — отображаются сырые символы. Называй сущность
словами («гостевая роль», «чаты»), а идентификатор раскрывай в тексте
под заголовком. Скобки (...) и дефис в составных словах
(webhook-слот) — нормально.
Переписывай в чистую фразу:
| Плохо | Хорошо |
|---|---|
### Execute Step — запуск одного узла |
### Запуск одного узла через Execute Step |
<Step title="Деактивировать → протестировать → активировать"> |
<Step title="Временная деактивация продакшен-workflow"> |
## Роль "guest" и "chat_ids" при создании (backticks в заголовке) |
## Гостевая роль и чаты при создании сотрудника |
Проверка перед коммитом:
grep -En '^#{2,3}.*( — | → | \+ |)' apps/docs/content/**/*.mdx`
text-[11px] допустим только с uppercase / capitalize (мелкие
ярлыки). Для обычного текста минимум — text-[12px]. Не «чини»
12-пиксельные подсказки до 11 — 11px нормальным начертанием слишком
мелко.
@opExampleне работает сHttpPart<T>(multipart) — строковые значения нельзя присвоитьHttpPart<string>. Multipart-примеры обрабатывай в генераторах.@encodedName("multipart/form-data", ...)не генерирует OpenAPI- секциюencoding— имена свойств схемы остаются camelCase; мэппинг wire-имён надо делать отдельно.Schema.properties— этоRecord<string, Schema> | undefined, передObject.entries()нужно сузить тип.- После правки
typespec.tspобязательно пересобирать:npx turbo build --filter=@pachca/spec --force— иначеopenapi.yamlостанется устаревшим и доки не отразят изменение. @docполей моделей: коротко, без markdown bold. Таблица параметров рендерит описание поля как текст: inline`code`превращается в чип, а**bold**показывается как литерал**. Одно- два коротких предложения, самодостаточно, без cross-ref'ов типа «см. описание метода». Не выдумывай уточнения — используй ровно те термины, которые уже есть в доках. Подробные правила / списки ошибок / edge-case'ы — в@doc("""...""")операции (рендерится как полный markdown над таблицей; там много абзацев — ок). Эталон длины:User.skip_email_notify(2 коротких предложения).- Используй уже существующую в spec лексику — не выдумывай синонимы.
Перед тем как добавить новое слово в
@doc,grepего вpackages/spec/typespec.tspиapps/docs/content/api/**/*.mdx. Ноль попаданий — значит ты придумываешь термин. Найди слово, которым другие эндпоинты уже описывают ту же сущность, и используй его. Одна и та же идея, выраженная двумя разными словами в разных местах API, читается как две разные идеи у того, кто открыл доки впервые. @docметодов — нейтральный голос, без перечисления аудитории. Описывай что метод делает, а не кто его вызывает. Пользовательские и ботовые токены ходят в одни и те же эндпоинты с одинаковой семантикой доступа — формулировка «доступных пользователю или боту» расщепляет одну идею на два клауса без причины. Используй второе лицо («у которых вы состоите») или безличную конструкцию («список доступных тредов»).- Без per-method исключений в
@docshared-моделей. Поля общих моделей (PaginationMeta,Message,Chat,User, …) рендерятся на каждом эндпоинте, который их использует. Если в описании есть «хвост» про то, как один конкретный эндпоинт ведёт себя иначе, этот хвост вылезает в таблице параметров у всех остальных эндпоинтов как шум. Особенности конкретного метода живут в (а) его собственном@doc("""..."""), и (б) в гайде, где эта особенность уже описана. В@docполя shared-модели — никогда. - Терминальная точка в
@doc— по числу предложений. Сложившаяся конвенция (≈863 однострочных@doc: ≈825 без точки, ≈38 с ней): одна фраза / одно предложение (label вроде@doc("Тип файла")) — без терминальной точки; многопредложное описание (два и больше предложений) — с точкой в каждом, включая последнее (живые примеры:User.email,User.phone_number). Та же логика, что и в пунктуации changelog'ов — updates-format §3. Когда разбиваешь точкой с запятой на два предложения, результат — многопредложный, последнее тоже должно заканчиваться точкой. - Синхронность EN overlay с описаниями операций.
$.paths[...].<method>.update.descriptionвpackages/spec/overlay.en.yaml— это полная замена описания. Если добавил абзац в@docрусской операции, но не добавил в её overlay- таргет, английская версия молча теряет абзац (overlay:applyне падает — кириллицы не осталось). Редактируешь русское описание операции — одновременно правь и её EN overlay-таргет.
См. также: CONTRIBUTING · формат обновлений · API-аудит