Сверка синхронизации между бэкендом Пачки (приватный репозиторий,
клонируется локально) и TypeSpec-спецификацией этого репозитория
(packages/spec/typespec.tsp).
Триггер — фраза агенту «Проверь API» / «Запусти аудит API».
Точка отсчёта — последняя дата среди файлов
apps/docs/content/updates/<YYYY-MM-DD>.md (имя файла = дата). Аудит
просматривает изменения публичного API бэкенда начиная с этой даты
включительно. Уже отражённое в spec / уже выпущенное агент видит и
повторно не вносит.
Точка отсчёта — последняя дата среди файлов
apps/docs/content/updates/<YYYY-MM-DD>.md (имя файла = дата). Аудит
просматривает изменения публичного API бэкенда начиная с этой даты
включительно. Отдельный чекпоинт по коммиту не ведётся.
- Перейти в локальный клон репозитория бэкенда Пачки
- Взять последнюю дату из имён файлов
apps/docs/content/updates/*.md - Сравнивать ТОЛЬКО с основной (дефолтной) веткой бэкенда, не с HEAD/--all:
НЕ использовать
git fetch origin <основная-ветка> git log --since="YYYY-MM-DD" origin/<основная-ветка> --oneline
git log --all— он показывает коммиты со stage и фича-веток, которых на проде нет. Документация = основная ветка, иначе ставите в spec несуществующее поведение. - Если изменений публичного API с этой даты нет — пропустить, перейти к шагу 1
- Если есть — просмотреть изменения через
git log/diff --since="YYYY-MM-DD" origin/<основная-ветка>, ограничившись публичным API:- контроллеры публичного API бэкенда
- сериализаторы ответов публичного API и сериализаторы исходящих вебхуков
- интеракторы/бизнес-логика, вызываемые из публичного API
- определение роутов бэкенда
- Перед записью каждой находки в spec — двойная проверка, что коммит реально в основной ветке (не stage/фича-ветка):
git merge-base --is-ancestor <sha> origin/<основная-ветка> - Захват «уже сделанного» — это нормально: если изменение уже отражено в spec / уже вышло в релиз, агент это видит и повторно не вносит. Дублирования не будет, поэтому брать дату с запасом (включительно) безопасно.
- Зафиксировать найденные расхождения и учесть их в дальнейших шагах аудита
- По возможности — валидировать API-запросом против прода после внесения правок (особенно для новых полей в ответах). Можно попросить у пользователя read-only токен.
- По завершении — новые user-facing изменения попадут в новый файл
apps/docs/content/updates/<текущая-дата>.md. Эта дата станет точкой отсчёта для следующего аудита. Хранить отдельный коммит/дату сверки не нужно.
Сверить определение роутов бэкенда (только публичный API) с интерфейсами в typespec.tsp:
- Новые эндпоинты в бэкенде → задокументировать в TypeSpec
- Удалённые эндпоинты → убрать из TypeSpec
- Обновить Таблицу покрытия API ниже
Для каждого эндпоинта сверить метод strong-params соответствующего контроллера публичного API с Request-моделями в typespec.tsp:
- Новые параметры в контроллере → добавить в TypeSpec
- Удалённые параметры → убрать из TypeSpec
- Проверить обязательность (
?vs required) - Обновить Таблицу параметров запросов ниже
Для каждого эндпоинта сверить сериализатор ответа публичного API с response-моделями в typespec.tsp:
- Новые поля в сериализаторе → добавить в модель
- Удалённые поля → убрать из модели
- Nullable: для каждого поля свериться со схемой БД бэкенда И с валидациями модели:
- Колонка в схеме без
NOT NULL(допускаетNULL) + нет presence-валидации →type | nullв TypeSpec - Метод сериализатора явно может вернуть
null(например, сериализатор сотрудника, скрывающий персональные данные — email/телефон — для чужих профилей у ботов без соответствующих прав) →type | null - Тесты публичного API — если фикстура содержит
field: nullдля штатного сценария → точно nullable - Не доверять только схеме на уровне кода: даже у
NOT NULL-колонки колбэк перед валидацией может присвоить значение, и тогда поле не nullable в API
- Колонка в схеме без
Сверить сериализаторы исходящих вебхуков с моделями *WebhookPayload в typespec.tsp:
| Источник payload в бэкенде (по назначению) | Модель в TypeSpec |
|---|---|
| Сериализатор/триггер вебхука сообщения (payload может собираться inline) | MessageWebhookPayload |
| Сериализатор вебхука реакции | ReactionWebhookPayload |
| Обработчик нажатия кнопки (payload собирается inline) | ButtonWebhookPayload |
| Обработчик отправки формы (payload собирается inline) | ViewSubmitWebhookPayload |
| Сериализаторы вебхука членства в чате | ChatMemberWebhookPayload |
| Сериализаторы вебхука членства в компании | CompanyMemberWebhookPayload |
| Сериализаторы вебхука «поделились ссылкой» | LinkSharedWebhookPayload |
Проверять:
- Новые поля в payload → добавить в TypeSpec и в
WebhookPayloadUnion - Удалённые → убрать
- При добавлении поля учесть TTL хранилищ (например, хранилище сохранённых форм держит view ограниченное время — поле может вернуться
nullдля старых сохранённых view)
Источник истины: коммиты, относящиеся к вебхукам/изменениям API — всегда сверять с сериализаторами исходящих вебхуков и с обработчиками button/view payload в бэкенде.
Для каждого эндпоинта сверить обработку ошибок в контроллерах и интеракторах публичного API с описанием ошибок в typespec.tsp.
Важно: при каждом аудите активно искать новые code-значения в бэкенде. Источники кодов:
- Интеракторы/бизнес-логика — кастомные хеши ошибок и явные вызовы добавления ошибки
- Библиотека валидации параметров — автоматические коды
required,in,min_length,max_lengthиз деклараций обязательных параметров - Контроллеры публичного API — явная сериализация ошибок с
{code: ...} - Модели и их валидации — валидации на уровне модели
- Политики доступа — кастомные коды ошибок авторизации
- Базовый контроллер публичного API — глобальные обработчики (не найдена запись, нет обязательного параметра, отказ авторизации, ошибки валидатора параметров)
Если найден новый code в бэкенде, которого нет в TypeSpec — сразу добавить в enum ValidationErrorCode и обновить таблицы.
Конкретные проверки:
- HTTP-коды ошибок: Какие статус-коды (400, 401, 402, 403, 404, 409, 410, 422) возвращает бэкенд → все ли объявлены в TypeSpec для данного эндпоинта
- Модели ошибок: Правильный ли тип используется (ApiError для бизнес-ошибок, OAuthError для 401)
- Коды валидации (ValidationErrorCode): Какие значения
codeбэкенд возвращает вerrors[].code→ все ли есть в enumValidationErrorCode - Коды валидации по эндпоинтам: Для каждого эндпоинта собрать конкретные
code-значения, которые он может вернуть (из контроллера, интерактора, модели) → обновить таблицу - Обновить Таблицу ошибок по эндпоинтам, Таблицу кодов валидации и Таблицу
errors[].codeпо эндпоинтам ниже
Если в результате аудита появляются изменения в OpenAPI-спецификации, влияющие на пользователей публикуемых пакетов — нужно поднять версии и записи в changelog'ах. Иначе изменения уйдут в публикацию без указания в release notes, и пользователи не узнают о них.
| Пакет | Файлы версии и changelog | Когда обновлять |
|---|---|---|
| n8n | integrations/n8n/package.json (version), integrations/n8n/CHANGELOG.md (вручную), apps/docs/data/releases.json (product: n8n) |
Любые изменения в моделях ответа (User, Message, Chat и т.д.), новые/изменённые webhook payloads (Trigger выводит их пользователю), новые/изменённые эндпоинты, изменения в form blocks, изменения в n8n-node build-скриптах |
| CLI | packages/cli/src/data/changelog.json (источник, генерирует CHANGELOG.md), packages/cli/package.json (фактически 0.0.0 — версия публикации берётся из changelog.json), apps/docs/data/releases.json (product: cli) |
Изменения моделей ответа (новые поля в users/chats/messages и т.д. видны в JSON-выводе), новые/удалённые/переименованные команды, изменения параметров команд, исправления багов |
| SDK (Go, Python, TS, Kotlin, Swift, C#) | sdk/<lang>/package.json, apps/docs/data/releases.json (product: sdk — единая запись на все языки) |
Любые изменения OpenAPI-спецификации (модели запросов/ответов, эндпоинты, enum'ы, ошибки) — SDK генерируются из OpenAPI |
| Generator | packages/generator/package.json, apps/docs/data/releases.json (product: generator) |
Изменения шаблонов генерации, новые языки, исправления генератора |
| Docs (обновления) | apps/docs/content/updates/<дата>.md (один файл на дату) |
Любые user-facing изменения API: новые методы, новые поля моделей, изменения nullable-типов, изменения вебхуков |
changelog.json/releases.json/CHANGELOG.md могут содержать ещё не выпущенную версию: отдельный chore(release)-коммит готовит запись заранее, а CI публикует позже. Прежде чем поднимать версию — проверить публикацию для каждого пакета отдельно (статусы независимы):
npm view @pachca/cli version # CLI
npm view n8n-nodes-pachca version # n8n
git tag --list 'v*' --sort=-v:refname | head -1 # SDK (CI публикует по тегам)
git tag --list 'n8n-v*' --sort=-v:refname | head -1Если верхняя запись в changelog новее опубликованного (npm/тег latest < changelog top) — релиз ещё не вышел. Тогда новое изменение вкладывается в эту pending-запись (дату при необходимости сдвинуть на дату изменения), новую версию НЕ создавать: иначе в releases.json/changelog окажется версия, которую gate не сможет опубликовать (она должна быть точным следующим шагом от latest dist-tag — см. docs/releases.md). Если опубликовано — новая версия корректна.
То же правило для обновлений: если файл apps/docs/content/updates/<дата>.md за прошлую дату относится к ещё не выпущенному релизу — дописать в него и при необходимости переименовать на дату релиза (см. updates-format §1, §10), не плодить второй файл-дату.
- Изменения внесены в
typespec.tspи скомпилированы - Файл обновления
apps/docs/content/updates/<дата>.md(если файл с этой датой уже есть — дописать в него, иначе создать новый) - Если затронуты модели ответа → bump n8n + CLI + SDK
- Если затронуты только webhook payloads → bump n8n
- Если затронут процесс генерации → bump generator
- Соответствующие записи в
apps/docs/data/releases.json(по продукту) — CI не обновляет этот файл, добавлять вручную - Соответствующие записи в
*/CHANGELOG.mdили*/changelog.jsonпакета - Версия в
package.jsonпакета поднята согласно semver:+(новый функционал, обратно совместим) → minor~(изменение существующего поведения, обратно совместим) → minor-(фикс) → patch- Breaking change → major
Эти файлы не регенерируются автоматически и часто забываются:
| Файл | Что обновлять | Триггер |
|---|---|---|
integrations/n8n/README.md |
URL releases/download/n8n-vX.X.X/... (wget install) |
Каждый bump n8n |
integrations/n8n/docs/DEVELOPMENT.md |
Текст «current: X.X.X» | Каждый bump n8n |
apps/docs/content/guides/cli.mdx |
Пример вывода pachca doctor (строка # ✔ CLI v2026.X.X) |
Каждый bump CLI (исторически часто пропускают) |
apps/docs/data/releases.json |
Новая запись {product, version, date, changes} |
Каждая публикация любого пакета (CI это НЕ делает) |
Эти файлы перегенерируются при npx turbo build — править руками не нужно:
apps/docs/public/updates.mdиpublic/updates/<дата>.md— изcontent/updates/*.mdapps/docs/public/llms-full.txt,llms-en.txt— изcontent/apps/docs/public/guides/*.md— изcontent/guides/*.mdxapps/docs/public/skills/*— копии скилловpackages/cli/CHANGELOG.md— изsrc/data/changelog.json(черезpatch-manifest.js)apps/docs/sitemap.xml,feed.xml— динамические роуты
После bump'а пакета прогнать npx turbo build и проверить diff этих файлов: если там «зависшая» старая версия — значит регенерация не сработала, нужно дебажить.
Версия больше не считается авто-инкрементом из npm. Её объявляем мы:
запись в apps/docs/data/releases.json (для CLI/n8n — продублировать в
собственном changelog), а scripts/check-release.mjs валидирует её на
публикации. Полные правила и алгоритм шага — docs/releases.md.
| Пакет | Источник версии | Что от нас требуется |
|---|---|---|
| n8n | releases.json (product n8n) + integrations/n8n/CHANGELOG.md |
Указать следующую semver-версию (patch+1 / minor+1.0 / major+1.0.0 от latest dist-tag) в обоих местах |
| CLI | releases.json (product cli) + packages/cli/src/data/changelog.json |
Указать следующую CalVer-версию (ГГГГ.М.патч+1 в том же месяце или .0 в новом) в обоих местах. package.json остаётся 0.0.0 (версию на публикации проставляет CI из changelog) |
| SDK | releases.json (product sdk, одна запись на все языки) |
Указать следующую semver-версию в releases.json (как у всех; от latest dist-tag @pachca/sdk = 1.0.19 → 1.0.20). Per-language package.json не трогать (placeholder 0.0.0). Публикуются все 6 языков вместе. typespec.tsp — источник спеки, не версии SDK |
| Generator | releases.json (product generator) |
Указать следующую semver-версию |
- В тот же аудит добавлять запись в
apps/docs/data/releases.jsonдля каждой публикации (CI это не делает) — версия = точный следующий шаг отlatestdist-tag. - Версия в
releases.jsonи в собственном changelog пакета (CLI/n8n) обязаны совпадать — иначе сборка упадёт наcheck-changelog-sync. - Менять код пакета без записи в changelog (и наоборот) нельзя — сборка упадёт.
- При каждом bump'е n8n сверять install URL в
integrations/n8n/README.mdс актуальной версией. - Один файл
apps/docs/content/updates/<дата>.mdна дату; дубликаты дат запрещены. - Dev-only фиксы (
prebuild-скрипты для локальных E2E, чистка артефактов разработки, фиксы CI/линтеров без эффекта на пользователя) не попадают ни в один changelog — ни вapps/docs/data/releases.json, ни вintegrations/<pkg>/CHANGELOG.md, ни вpackages/cli/src/data/changelog.json. Контрольный вопрос перед добавлением: «Заметит ли это пользователь, который скачал пакет из npm?» — если нет, не пишем нигде.
| Пакет | Схема | Пример |
|---|---|---|
| n8n | semver | 2.0.6 |
| CLI | calver YYYY.M.PATCH |
2026.5.0 |
| SDK | semver (общий для всех языков) | 1.0.14 |
| Generator | semver | 1.1.3 |
Запись описывает изменение на языке поверхности своего продукта, а не сырыми
путями API. Не писать (POST /bots), (PUT /bot/webhook) и т.п. в тексте записи —
у каждого пакета своя система имён:
| Продукт | Где | Как писать | Пример |
|---|---|---|---|
| CLI | releases.json |
`pachca <команда>` — суть + флаги --flag |
`pachca bots create` — создание бота и получение его `access_token` |
| CLI | packages/cli/src/data/changelog.json |
поле command = команда; в description суть (без пути), для новой команды — «Новая команда — …» |
command: "bots create", description: "Новая команда — создание бота…" |
| SDK | releases.json |
Метод `Русское-название` (`METHOD /path`) либо «поле field» |
Метод `Саморегистрация вебхука бота` (`PUT /bot/webhook`) |
| n8n | releases.json + integrations/n8n/CHANGELOG.md |
`Resource`: операция `Create`/`Get Many`/`Update Webhook` + параметры в коде; без сырых API-путей |
Bot: новая операция `Update Webhook` — саморегистрация вебхука бота |
Сырой METHOD /path уместен только у SDK в скобках после названия метода (SDK
оперирует методами API напрямую). У CLI поверхность — команды и флаги, у n8n —
ресурсы и операции; пути в их записи — стилевая ошибка.
Сверить список event_key в бэкенде с документацией в apps/docs/content/guides/audit-events.mdx:
- Найти все вызовы регистрации аудит-события (
audit_event(key: '...')/perform_audit_event(key: '...')и аналогичные) в бэкенде — искать во всех директориях бэкенда, не только в коде публичного API: сервисы, интеракторы/бизнес-логика, контроллеры, модели, вспомогательные библиотеки, конфигурация - Сравнить с разделом «Реализованные типы событий» в
audit-events.mdx - Новые event_key в бэкенде → добавить в MDX (решить, документировать или игнорировать)
- Удалённые event_key → убрать из MDX
- Обновить Таблицу типов аудит-событий ниже
Важно: event_key — свободные строки (нет enum), разбросаны по всему бэкенду (не только по коду публичного API). Проверять все вызовы регистрации аудит-события.
Часть публичного контракта API живёт не в REST-эндпоинтах, а в фичах, которыми пользователь управляет через интерфейс, но структуру и поведение которых мы документируем. Главный пример — DLP-система: правила не создаются через публичный эндпоинт, поэтому шаги 1–4 их не покрывают. При этом структура правила (наборы типов условий и действий, параметры контекста применения, обязательность полей, значения по умолчанию) и порядок обработки — это публичный контракт, который пользователь пишет руками. Такие фичи легко выпадают из аудита — проверять их нужно отдельно при каждом аудите.
Ключевое отличие от обычного эндпоинта: источник истины для этих схем — не
typespec.tsp. Схемы лежат в apps/docs/lib/schemas/guides/*.json и
рендерятся в гайдах через <SchemaBlock>. Они не генерируются из TypeSpec и в
шагах 1–4 не участвуют, поэтому правки при изменении бэкенда могут затронуть
не .tsp, а .json-схему и текст .mdx-гайда.
DLP документирован в трёх местах — при изменении бэкенда сверять каждое:
| Что меняется в бэкенде | Где править в репозитории |
|---|---|
| Структура правила: наборы типов условий и действий, параметры контекста, поля, их обязательность и дефолты | apps/docs/lib/schemas/guides/DlpRule.json (рендерится в гайде через <SchemaBlock>) |
| Поведение: порядок обработки правил, семантика действий, ограничения движка условий, что видит пользователь | apps/docs/content/guides/dlp.mdx (текст, таблицы, примеры) |
| Состав полей в деталях записи журнала аудита при срабатывании правила | модель деталей DLP-события в packages/spec/typespec.tsp + соответствующий event_key (см. §5) |
Что сверять с логикой обработки правил в бэкенде:
- Появились/исчезли типы действий правила → обновить и таблицу действий в гайде, и enum действия в JSON-схеме
- Появились/исчезли типы условий или их параметры (включая ограничения и значения по умолчанию) → JSON-схема + соответствующий раздел гайда
- Изменились параметры контекста применения или их допустимые значения → JSON-схема + гайд
- Изменился порядок или семантика обработки правил → текст гайда
- Изменился состав полей в деталях аудит-события → модель деталей в TypeSpec (§5)
Тот же подход применять к остальным схемам из каталога
apps/docs/lib/schemas/guides/*.json: при изменении соответствующей логики
бэкенда сверять и JSON-схему, и текст гайда — они вне TypeSpec и в шагах 1–4
не видны.
Если найдены расхождения:
- Внести правки в
typespec.tsp(см. Справочник TypeSpec ниже) - Обновить примеры в
@opExampleесли затронуты - Если найдены новые
codeв ошибках бэкенда — добавить в enumValidationErrorCode - Если найдены новые HTTP-коды ошибок — добавить в union ответа операции
- Если изменились скоупы токенов (новые скоупы, изменение набора bot-скоупов) — обновить
apps/docs/content/guides/authorization.mdx: секции «Скоупы персональных токенов», «Скоупы токенов ботов» и Warning-блок с перечнем недоступных ботам скоупов - Проверить страницу «Модели» (
apps/docs/content/api/models.mdx) — страница содержит справочник всех моделей API. Таблицы свойств моделей (<ModelSchema>) генерируются из OpenAPI автоматически, но остальное прописано вручную:- Список моделей в
<CardGroup>— если появилась новая модель или удалена старая, обновить список карточек (title, href, methods) - Списки методов под каждой моделью — если добавлен/удалён/переименован метод, обновить соответствующий список ссылок
[Название](METHOD /path) - Атрибут
methodsв<Card>— если у модели изменился набор HTTP-методов (например, добавился DELETE), обновить атрибут - Info-блок в начале — если появился новый метод, не возвращающий модель данных, добавить его в список исключений
- Список моделей в
- Добавить файл обновления
apps/docs/content/updates/<дата>.md(формат — updates-format) - Запустить
cd packages/spec && bun run generate - Запустить
bun turbo check - Обновить таблицы в этом документе
- Проверить скиллы — если затронуты API-методы, перейти к шагу ниже
После внесения изменений в TypeSpec/docs — проверить, нужно ли обновить скиллы.
ОБЯЗАТЕЛЬНО оценить необходимость нового сценария. Если изменение вводит неочевидный / многошаговый / ограниченный флоу — обязательные связки параметров, предусловия, порядок вызовов, специфичные ошибки — недостаточно того, что метод попал в
endpoints.md: обязательно вынести его в workflow (packages/spec/workflows.ts). Контрольный вопрос: «сможет ли агент выполнить это с первого раза только по описанию метода, или ему нужен пошаговый сценарий с предусловиями и обработкой ошибок?» Если второе — workflow обязателен.
typespec.tsp → openapi.yaml → generate.ts + config.ts + workflows.ts → SKILL.md + endpoints.md
Автогенерируемые файлы (НИКОГДА не редактировать вручную):
skills/*/SKILL.md— генерируется из config + workflows + OpenAPIskills/*/references/endpoints.md— генерируется из OpenAPI (параметры, схемы, примеры curl)skills/pachca-bots/references/webhook-events.md— генерируется из generate.ts (хардкод)apps/docs/public/.well-known/skills/*— копии вышеуказанных файлов
Файлы-источники (редактировать для изменения скиллов):
| Файл | Что содержит | Когда редактировать |
|---|---|---|
apps/docs/scripts/skills/config.ts |
Определения скиллов: теги, триггеры, описания, ошибки | Новый скилл, новый тег OpenAPI, изменение описания, новые специфичные ошибки |
packages/spec/workflows.ts |
Пошаговые сценарии (title, steps, notes, curl) | Новый/изменённый workflow, новый параметр влияющий на шаги |
apps/docs/scripts/skills/generate.ts |
Логика генерации, хардкод вебхук-событий | Новый тип скилла, изменение формата вывода |
packages/spec/typespec.tsp |
Эндпоинты, параметры, схемы, описания | Любые изменения API (отражаются в endpoints.md автоматически) |
Команда регенерации: npx turbo build (компилирует TypeSpec И генерирует скиллы)
Привязка работает через OpenAPI-теги (@tag в TypeSpec) → config.ts: SKILL_TAG_MAP[].tags + исключения в COMMON_ENDPOINT_MAP.
| Скилл | Теги в config.ts | Доп. маппинг (COMMON_ENDPOINT_MAP) | Эндпоинты |
|---|---|---|---|
pachca-profile |
Profile |
/custom_properties → pachca-profile |
GET /profile, GET/PUT/DELETE /profile/status, GET /custom_properties |
pachca-users |
Users, Group tags |
— | CRUD /users, GET/PUT/DELETE /users/{id}/status, CRUD /group_tags, GET /group_tags/{id}/users |
pachca-chats |
Chats, Members |
/chats/exports → pachca-chats |
CRUD /chats, archive/unarchive, CRUD members, tags, leave, exports |
pachca-messages |
Messages, Thread, Reactions, Read member |
/uploads, /direct_url → pachca-messages |
CRUD /messages, pin, reactions, read_members, threads, uploads |
pachca-bots |
Bots, Link Previews |
— | PUT /bots/{id}, POST /messages/{id}/link_previews, GET/DELETE /webhooks/events |
pachca-forms |
Views |
— | POST /views/open |
pachca-tasks |
Tasks |
— | CRUD /tasks |
pachca-search |
Search |
— | GET /search/users, GET /search/chats, GET /search/messages |
pachca-security |
Security |
— | GET /audit-events |
| Тип изменения в бэкенде | Что обновить | Файл |
|---|---|---|
| Новый эндпоинт в существующем ресурсе | 1) Добавить в TypeSpec (→ попадёт в endpoints.md автоматически). 2) Если нужен новый workflow — добавить в workflows.ts. 3) Если тег эндпоинта не совпадает с существующим — добавить в COMMON_ENDPOINT_MAP | typespec.tsp, workflows.ts, config.ts |
| Новый ресурс (совсем новый API) | 1) Добавить в TypeSpec с @tag("NewTag"). 2) Решить: новый скилл или расширить существующий. 3) Добавить скилл в SKILL_TAG_MAP (config.ts): name, tags, description, triggers, negativeTriggers. 4) Добавить workflows в workflows.ts. 5) Обновить CLAUDE.md — таблицу скиллов |
typespec.tsp, config.ts, workflows.ts, CLAUDE.md |
| Удалённый эндпоинт | 1) Убрать из TypeSpec. 2) Удалить workflow, если он полностью завязан на этот эндпоинт. 3) Обновить шаги в других workflow, если они ссылались на этот эндпоинт | typespec.tsp, workflows.ts |
| Новый параметр запроса | 1) Добавить в TypeSpec (→ endpoints.md обновится). 2) Если параметр важный для сценариев — обновить steps/notes в workflows.ts (например, новый фильтр) | typespec.tsp, workflows.ts |
| Удалённый параметр | 1) Убрать из TypeSpec. 2) Убрать из шагов/notes в workflows.ts, если упоминается | typespec.tsp, workflows.ts |
| Новое поле в ответе | 1) Добавить в TypeSpec (→ endpoints.md обновится). 2) Если поле полезно для workflow — обновить notes | typespec.tsp, workflows.ts |
| Новый код ошибки (специфичный для скилла) | 1) Добавить в enum ValidationErrorCode (TypeSpec). 2) Если ошибка важна для пользователя — добавить в config.ts → errors[] соответствующего скилла (отображается в секции «Ограничения и gotchas» SKILL.md) |
typespec.tsp, config.ts |
| Изменение скоупа/тарифа | 1) Обновить в TypeSpec. 2) Если скилл стал botOnly или перестал — обновить botOnly в config.ts |
typespec.tsp, config.ts |
| Новый тип вебхук-события | 1) Обновить хардкод в generate.ts (функция generateWebhookEventsMd). 2) Если нужен новый workflow — добавить в workflows.ts для pachca-bots |
generate.ts, workflows.ts |
| Изменение описания/триггеров скилла | Обновить в config.ts: description, triggers, negativeTriggers, nearestAlternatives |
config.ts |
Понимание структуры SKILL.md помогает определить, какой файл редактировать:
| Секция в SKILL.md | Источник данных | Файл-источник |
|---|---|---|
| Frontmatter (name, description) | config.ts → SKILL_TAG_MAP |
config.ts |
| Заголовок (Base URL, авторизация, botOnly) | config.ts → botOnly + хардкод |
config.ts |
| «Когда НЕ использовать» | config.ts → negativeTriggers, nearestAlternatives |
config.ts |
| «Пошаговые сценарии» | workflows.ts → WORKFLOWS[skillName] |
workflows.ts |
| «Ограничения и gotchas» | OpenAPI-схемы (enum, maxLength, maximum) + config.ts → errors[] |
typespec.tsp, config.ts |
| Таблица эндпоинтов | OpenAPI-эндпоинты (метод, путь, скоуп, тариф) | typespec.tsp |
| Ссылка на references/endpoints.md | Автогенерация | — |
| Секция в references/endpoints.md | Источник данных | Файл-источник |
|---|---|---|
| Описание эндпоинта | @doc() в TypeSpec |
typespec.tsp |
| Параметры (query, path) | Параметры операции в TypeSpec | typespec.tsp |
| Тело запроса (schema) | Request-модель в TypeSpec (рекурсивно до глубины 3) | typespec.tsp |
| Пример curl | Автогенерация из @opExample |
typespec.tsp |
| Ответ (schema) | Response-модель в TypeSpec (рекурсивно до глубины 3) | typespec.tsp |
- Определить затронутые скиллы по таблице привязки выше
- Оценить необходимость нового сценария (см. callout в начале §6a): изменение вводит неочевидный/многошаговый/ограниченный флоу (обязательные связки параметров, предусловия, порядок вызовов, специфичные ошибки)? Если да — workflow обязателен, не ограничиваться
endpoints.md - Если новый эндпоинт с новым тегом — добавить тег в
config.ts→SKILL_TAG_MAP[].tagsили вCOMMON_ENDPOINT_MAP - Если нужен новый workflow — добавить в
packages/spec/workflows.ts→WORKFLOWS[skillName] - Если изменились шаги существующего workflow — обновить
steps[]иnotesвworkflows.ts - Если появилась специфичная ошибка — добавить в
config.ts→errors[]соответствующего скилла - Запустить
npx turbo buildдля регенерации - Источник истины:
packages/spec/openapi.yaml(генерируется изtypespec.tsp)
ОБЯЗАТЕЛЬНО при каждом аудите — проверить все workflows.ts на соответствие openapi.yaml/typespec.tsp. Нельзя придумывать параметры, методы или значения enum'ов.
Что проверять в steps[], notes и curl каждого workflow:
- Названия query-параметров совпадают с реальными в спецификации (пример ошибки:
created_at[from]вместоstart_time) - Значения enum'ов совпадают с реальными (пример ошибки:
user_signed_inвместоuser_login) - Curl-примеры используют правильные параметры и пути
- Имена полей в body совпадают с request-моделями в TypeSpec
- Лимиты и дефолты (
limitдо 50/100/200/300) совпадают с@maxValueв спецификации - HTTP-методы в шагах (
GET,POST,PUT,DELETE) совпадают с реальными - Пути эндпоинтов корректны (например,
/audit_events, не/audit-events)
Как проверять:
- Открыть
workflows.tsи для каждого скилла пройтись по всемsteps[],notesиcurl - Каждый упомянутый параметр, значение или путь — сверить с определением в
typespec.tsp(илиopenapi.yaml) - Исправления вносить только в
workflows.ts— SKILL.md генерируется автоматически
При создании новых workflow можно ориентироваться на типовые агентские и automation-сценарии, распространённые на рынке dev-инструментов — но только как источник идей для workflow (какие задачи агент может решать). Реализовывать только то, что реально поддерживает Пачка API: если сценарий требует параметров, которых нет в нашем API — не добавлять.
Обновить Таблицу скиллов и workflow в конце этого документа
Запись обновления — это отдельный файл apps/docs/content/updates/<дата>.md
с YAML-frontmatter (date, title) и markdown-телом. Полные правила
(структура, ссылки на методы, поведенческие нюансы в гайд, якоря-транслит,
даты в <Info>/<Warning>) — в updates-format.
Кратко: один файл на дату, title в frontmatter (не ## в теле), ссылки
на методы [Название](METHOD /path).
Вывести краткий отчёт:
- Что нового найдено
- Что задокументировано
- Что игнорируется
- Текущее покрытие
| Что | Где в бэкенде (по роли) |
|---|---|
| Контроллеры | Контроллеры публичного API — ТОЛЬКО публичный namespace |
| Сериализаторы | Только сериализаторы ответов публичного API |
| Роуты | Определение роутов бэкенда → только публичный namespace |
| Интеракторы/бизнес-логика | Только вызываемые из контроллеров публичного API (проверять по вызовам) |
| Модели | Только валидации, затрагивающие поля публичного API |
| Базовый контроллер | Базовый контроллер публичного API — глобальные обработчики ошибок |
| Error codes | Только коды, реально попадающие в ответы эндпоинтов публичного API |
| Что | Причина |
|---|---|
| Внутренний (непубличный) API | Не документируется |
| Старый внутренний API | Старая версия, не документируется |
| Внутренние (не относящиеся к публичному API) сериализаторы | Используются только внутренним API |
| Интеракторы только для внутреннего API | Не вызываются из публичного API |
| Push-уведомления | Error codes в push-уведомлениях — НЕ API-ответы |
| Внутренние коды ошибок непубличного API | Не документируются |
| Внутренние, бета- и служебные эндпоинты | Не входят в публичный API; в область аудита не входят и не документируются |
Не помечать как расхождения:
| Элемент | Причина |
|---|---|
| GET /files/{id} | Не публичный эндпоинт — нигде не возвращаются ID файлов, пользователи не смогут воспользоваться |
| Внутренние, бета- и служебные эндпоинты | Не входят в публичный API; в область аудита не входят и не документируются |
POST /messages — uuid |
Подставляется автоматически (генерируется случайно на бэкенде) |
POST /messages — created_at |
Внутренний параметр, не для публичного API (создание сообщений в прошлое) |
POST /messages — files[].blurhash, files[].thumbhash, files[].thumb_key |
Внутренние параметры файлов |
PUT /messages — files[].id |
Не документируется |
| POST /messages — 409 Conflict | Детектор дублей запросов (короткий TTL) — из публичного API маловероятен, т.к. uuid каждый раз новый |
Message — display_avatar_url/display_name conditional |
Сериализатор включает эти поля только для ботов. Текущая документация: string | null (всегда). Решено: бэкенд поправит, чтобы поля были всегда |
UserStatus.away_message — markup |
Поле markup (массив rich text разметки) есть только в непубличном сериализаторе. Сериализатор публичного API не включает markup |
SearchController — search[query] |
Альтернативный вложенный параметр (legacy), не документируем |
Бэкенд → TypeSpec (packages/spec/typespec.tsp) → OpenAPI YAML → Next.js docs (автоматически).
Всё описание API находится в одном файле: packages/spec/typespec.tsp. После внесения изменений компилятор генерирует openapi.yaml, а docs-сайт автоматически подхватывает новые страницы, навигацию и поиск.
| Что искать | Где в бэкенде (по роли) |
|---|---|
| HTTP-метод, путь, параметры | Определение роутов бэкенда и контроллер публичного API |
| Strong params (что принимает) | Метод strong-params соответствующего контроллера |
| Обязательность полей | Валидации в модели и в интеракторе/бизнес-логике |
| Поля ответа | Сериализатор ответа публичного API |
| Пагинация (page/per или limit/cursor) | Контроллер — смотреть, какой механизм пагинации используется (постраничный или курсорный пагинатор) |
| Коды ошибок (ValidationErrorCode) | Контроллер, интерактор, модель — места добавления/возбуждения ошибок |
| Структура ошибок (ApiError/OAuthError) | Базовые обработчики ошибок публичного API |
| Примеры запросов/ответов | Тесты публичного API |
Важно: не доверяй только названиям параметров — проверяй обязательность по валидациям модели и интерактора/бизнес-логики.
| Тип операции | Пример-шаблон в typespec.tsp |
|---|---|
| CRUD (list, get, create, update, delete) | UserOperations, GroupTagOperations |
| Список с page/per пагинацией | listChatMessages, listReadMembers |
| Список с cursor пагинацией | listUsers, listChats |
| Удаление (204 No Content) | deleteUser, deleteTag |
| Вложенные ресурсы (/{id}/sub) | ChatMemberOperations |
Добавлять в секцию моделей (~строки 400-800):
@doc("Описание сущности")
model EntityName {
@doc("Описание поля")
@example(123)
id: int32;
@doc("Nullable поле")
@example(utcDateTime.fromISO("2020-01-01T00:00:00.000Z"))
some_date: utcDateTime | null;
@doc("Enum поле")
@example("value1")
@extension("x-enum-descriptions", #{
value1: "Описание значения 1",
value2: "Описание значения 2"
})
status: "value1" | "value2";
}Правила:
- Nullable поля:
type | null - Enum-описания через
@extension("x-enum-descriptions", ...) - Каждое поле —
@doc()+@example() - Склонения описаний enum должны согласовываться с сущностью (напоминание → «Выполнено», задача → «Выполнена»)
- Точки в
@docполя — всё или ничего. Однострочное описание-фрагмент пишем без завершающей точки (как большинство полей: «Идентификатор сообщения»). Но если описание из двух и более предложений, точка должна стоять в конце каждого предложения, включая последнее. Типичная ошибка (возникает постоянно): первое предложение с точкой, последнее — без («…в текст.null, пока не готова» → правильно «…в текст.null, пока не готова**.**»). То же — в EN-переводе вoverlay.en.yaml.
Добавлять рядом с другими Request-моделями (~строки 1000-1400):
@doc("Запрос на создание/обновление сущности")
model EntityCreateRequest {
@doc("Объект параметров")
entity: {
@doc("Обязательное поле")
field1: string;
@doc("Опциональное поле")
field2?: int32;
@doc("Поле с дефолтом")
field3?: int32 = 1;
};
}Важно:
- Обязательные поля — без
? - Опциональные — с
? - Дефолтные значения —
= value
Добавлять в секцию enum'ов (~строки 30-380):
@doc("Описание enum")
@extension("x-enum-descriptions", #{
value1: "Описание 1",
value2: "Описание 2",
})
enum EnumName {
@doc("Описание 1")
value1: "value1",
@doc("Описание 2")
value2: "value2",
}ОБЯЗАТЕЛЬНО — описание у каждого значения enum. Страница «Возможные
значения» в доке рендерится из @extension("x-enum-descriptions", …), а не
из @doc на членах enum (member-@doc — декоративный, в x-enum-descriptions
не попадает). Поэтому:
- У каждого значения нового enum должна быть строка в
x-enum-descriptions— иначе значение покажется без описания. - При добавлении нового значения в существующий enum — дописать его и в
x-enum-descriptions(легко забыть: правишь тело enum, а блок@extensionвыше остаётся со старым набором). - Для EN: добавить те же ключи в
x-enum-descriptionsсоответствующегоtargetвpackages/spec/overlay.en.yaml(иначеoverlay:validateупадёт).
Добавлять внутри соответствующего interface или создать новый:
@route("/entities")
@tag("TagName")
interface EntityOperations {
@doc("""
Заголовок
Описание метода. Поддерживается markdown.
""")
@get
@route("/{id}")
@opExample(#{
parameters: #{
id: 123
},
returnType: #{
_: 200,
body: #{
data: #{ /* пример объекта */ }
}
}
})
operationName(
@doc("Описание параметра")
@path id: int32
): {
@statusCode _: 200;
@body body: DataResponse<Entity>;
} | {
@statusCode _: 401;
@body body: OAuthError;
} | {
@statusCode _: 404;
@body body: ApiError;
};
}Список с page/per:
listEntities(
@doc("Количество возвращаемых сущностей за один запрос")
@query @minValue(1) @maxValue(50)
per?: int32 = 50,
@doc("Страница выборки")
@query page?: int32 = 1
): {
@statusCode _: 200;
@body body: DataResponse<Entity[]>;
} | { ... };Список с cursor:
listEntities(
@doc("Количество возвращаемых сущностей за один запрос")
@query @minValue(1) @maxValue(50)
limit?: int32 = 50,
@doc("Курсор для пагинации (из meta.paginate.next_page)")
@query cursor?: string
): {
@statusCode _: 200;
@body body: PaginatedDataResponse<Entity[]>;
} | { ... };Удаление:
@delete
deleteEntity(@doc("Идентификатор") @path id: int32): {
@statusCode _: 204;
@body body: EmptyResponse;
} | {
@statusCode _: 401;
@body body: OAuthError;
} | {
@statusCode _: 404;
@body body: ApiError;
};| Код | Когда использовать | Тип |
|---|---|---|
| 400 | Невалидный запрос | ApiError |
| 401 | Не авторизован (токен отсутствует/невалидный) | OAuthError |
| 402 | Требуется оплата | ApiError |
| 403 | Недостаточно прав OAuth-скоупа | OAuthError |
| 403 | Нет доступа (бизнес-логика, политика) | ApiError |
| 404 | Не найдено | ApiError |
| 409 | Конфликт | ApiError |
| 410 | Ресурс удалён | ApiError |
| 422 | Ошибка валидации | ApiError |
Важно про 403: Любой эндпоинт может вернуть 403 в формате OAuthError ({"error": "insufficient_scope", "error_description": "..."}) если у токена бота нет нужного скоупа. Дополнительно некоторые эндпоинты (экспорт) могут вернуть 403 в формате ApiError (бизнес-логика запрета). В TypeSpec используется ApiError | OAuthError для таких случаев.
- Одиночный объект:
DataResponse<Entity> - Массив (page/per):
DataResponse<Entity[]> - Массив (cursor):
PaginatedDataResponse<Entity[]> - Пустой ответ (204):
EmptyResponse
Отдельный файл apps/docs/content/updates/<ГГГГ-ММ-ДД>.md с frontmatter
(date, title) и markdown-телом:
---
date: "ГГГГ-ММ-ДД"
title: "Заголовок обновления"
---
Описание изменений.
- [Название метода](HTTP_МЕТОД /путь)
- [Название метода](HTTP_МЕТОД /путь/{id})Правила:
- Дата = имя файла и поле
dateв frontmatter;title— в frontmatter, не##в теле - Ссылки на методы в формате
[Текст](МЕТОД /путь)— автоматически становятся кликабельными ссылками на страницы документации - Обновления с датой < 7 дней назад получают badge «Новое» на сайте (порог —
isNewUpdate()вapps/docs/lib/updates-parser.ts) - Допустимые HTTP-методы в ссылках:
GET,POST,PUT,DELETE - Полные правила — updates-format
# Компиляция TypeSpec в openapi.yaml
cd packages/spec && bun run generate
# Все проверки (lint, typecheck, knip, prettier)
bun turbo check
# Если prettier ругается:
cd apps/docs && bunx prettier --write <файлы из вывода ошибки>- Изучены контроллер, модель, сериализатор, интерактор/бизнес-логика и тесты в бэкенде
- Проверена обязательность каждого поля (валидации модели + интерактор)
- Проверена nullable полей в ответе (сериализатор)
- Определён тип пагинации (page/per или limit/cursor)
- Добавлена/обновлена response-модель (если нужно)
- Добавлена request-модель (для POST/PUT)
- Проверены все HTTP-коды ошибок бэкенда (400, 401, 403, 404, 409, 410, 422) — все объявлены в TypeSpec
- Проверены значения
codeв ошибках бэкенда — все есть в enumValidationErrorCode - Добавлены операции в interface с
@doc,@opExampleи кодами ошибок - Примеры в
@opExampleсодержат все обязательные поля модели - Добавлен файл
apps/docs/content/updates/<дата>.mdсо ссылками на новые/обновлённые методы -
bun run generateпроходит без ошибок -
bun turbo checkпроходит без ошибок (lint, typecheck, knip, prettier) - Новые страницы отображаются на docs-сайте