Skip to content

Раздел «Документация» в админ-панели — контракт интеграции

Handoff команде админ-панели. Готовность со стороны Wiki по трём пунктам, которые вы запрашивали: (1) манифесты, (2) wiki за авторизацией + чистый mkdocs.yml без CDN, (3) service_connect.data.docs. Спецификация структуры — ../projects/_STRUCTURE.md.

Статус готовности (со стороны Wiki)

# Что требовалось Статус Где
1 Манифесты сгенерированы ✅ генерируются на сборке hook material/overrides/hooks/manifests.py
2 Из mkdocs.yml убраны Google Analytics / внешние шрифты ✅ сделано mkdocs.yml (font: false, блок analytics удалён)
2 Wiki за авторизацией ⛔ инфра-задача (reverse-proxy/forward-auth) — вне репозитория, нужно поднять перед публикацией см. «Приватность и CSP»
3 service_connect.data.docs заполнен 🟡 SQL готов (ниже) — применить на admin_api_test этот документ

После этого со стороны админки: раздел «Документация» (per-project, по манифесту, гейт projectDocsView).

1. Манифесты

На каждой сборке сайта hook генерирует:

  • /projects/<slug>/manifest.json — дерево документации проекта;
  • /projects/manifest.index.json — реестр проектов.

path в дереве = реальный served-URL MkDocs (use_directory_urls), напр. projects/teslapay/scenarios/payment/topup/. Узлы-каталоги без своего index.md имеют path: null — это нелистаемые заголовки групп (рендерить как раскрывающийся узел без ссылки).

Схема manifest.json (на проект)

{
  "slug": "teslapay",
  "title": "TeslaPay",
  "path": "projects/teslapay/",
  "category": null,
  "children": [
    {
      "category": "scenarios",
      "title": "Бизнес-сценарии",
      "path": "projects/teslapay/scenarios/",
      "children": [
        {
          "title": "Пополнение счёта",
          "path": "projects/teslapay/scenarios/payment/topup/",
          "children": []
        }
      ]
    }
  ]
}
Категории (L2, фиксированный порядок): business-analytics, system-analytics, tech-info, scenarios. Узел: { title: string, path: string|null, children: Node[] }; у категорийного узла дополнительно category: string.

Схема manifest.index.json

{
  "schema": 1,
  "projects": [
    { "slug": "teslapay", "title": "TeslaPay", "manifest_path": "/projects/teslapay/manifest.json" },
    { "slug": "trientes", "title": "Trientes", "manifest_path": "/projects/trientes/manifest.json" }
  ]
}

Путь манифеста — /projects/<slug>/manifest.json (рядом с контентом проекта), а не /<slug>/.... Это уточнение к раннему черновику спеки; именно этот путь кладите в service_connect.data.docs.manifest_path.

Как получить тело документа

GET {base_url}{path} отдаёт готовую HTML-страницу MkDocs. Два варианта встраивания (на ваш выбор):

  • iframe с приватного wiki-origin + origin-проверка (как у DrawioEditor), узкий frame-src;
  • прокси через admin-api (admin-api ходит на wiki по внутреннему адресу, отдаёт HTML фронту) — не расширяет CSP фронта.

2. Приватность и CSP (инфра, до публикации)

  • Wiki закрыть авторизацией (reverse-proxy / forward-auth) — публиковать для встраивания только за аутентификацией.
  • CSP: узкий frame-src на один доверенный wiki-origin (при iframe), либо проксирование HTML через admin-api без расширения CSP фронта.
  • mkdocs.yml очищен от внешних CDN: font: false (системные шрифты, без fonts.gstatic.com), убран Google Analytics. Emoji/иконки рендерятся инлайн на сборке (Twemoji-SVG), рантайм-запросов наружу нет.
  • ⚠️ Раздел tech-info содержит креды к TEST-БД и карту портов (по решению владельца — это допустимо для wiki, т.к. доступ к разделам ограничен и креды нужны допущенным для получения доступа к БД). Следствие для админки: доступ к tech-info должен быть под тем же (или более строгим) гейтом, что и весь раздел документации — projectDocsView. Не отдавать tech-info пользователям без права.

2.1 Маскирование секретов в документах (требуется от команды Wiki)

Двухуровневая модель доступа:

  • projectDocsView — видеть раздел «Документация» и читать документы (включая tech-info).
  • projectDocsSecretsдополнительно видеть секреты (пароли/креды) в открытом виде. У кого права нет — секреты заменяются маской •••••• на стороне admin-api до отдачи фронту (оператор без права физически не получает значение секрета — маскирование серверное, не CSS).

Что нужно сделать в документах: обернуть каждое секретное значение маркером, который попадёт в итоговый HTML как элемент с классом secret или атрибутом data-secret. admin-api при отсутствии права заменяет всё содержимое такого элемента маской.

Примеры в Markdown (инлайн-HTML работает в MkDocs):

Пароль БД: <span class="secret">lt6eTQiB6EhWOqwe</span>
DSN: postgres://admin_api:<span class="secret">lt6eTQiB6EhWOqwe</span>@10.8.0.11:15405/admin_api_test

В таблице кредов — оборачивать значение в ячейке:

| Сервис | Пользователь | Пароль |
|--------|--------------|--------|
| users  | users_test   | <span class="secret">kvPfwLp3MkAbqWrK</span> |

Рекомендации: - Маркировать только само значение, не подпись («Пароль:» оставлять видимым). - Можно добавить в extra.css темы стиль .secret { … } (например моноширинный фон) — для операторов с правом значение видно как обычно; маскирование значения не зависит от CSS. - Вложенная разметка внутри .secret допустима — маскируется весь элемент целиком. - Если значение не обёрнуто маркером — оно не маскируется (виден всем с projectDocsView). Поэтому для tech-info важно покрыть маркером все креды.

3. service_connect.data.docs

Платформенное правило: базовый URL/слаг/путь манифеста — не env и не хардкод, а в service_connect.data per-project. Ключ docs добавляется к существующему data (не перезаписывая service_hosts / flat-адреса).

Таблица service_connect(id UUID PK, project_name TEXT, data JSONB, project_id UUID FK), БД admin_api_test (10.8.0.11:15405). Существующие строки: TeslaPay 0e1c7f6b-9439-4cc0-b2a9-c10330efd09d, Trientes 8557fd43-07da-41c1-aa1d-c37bb0e3515a.

-- TeslaPay: добавить ключ docs к существующему data
UPDATE service_connect
SET data = (data::jsonb || '{
  "docs": {
    "base_url": "https://wiki.gsmsoft.eu",
    "project_slug": "teslapay",
    "manifest_path": "/projects/teslapay/manifest.json"
  }
}'::jsonb)::json,
    update_date = NOW()
WHERE id = '0e1c7f6b-9439-4cc0-b2a9-c10330efd09d';

-- Trientes: то же (flat-адреса в data сохраняются)
UPDATE service_connect
SET data = (data::jsonb || '{
  "docs": {
    "base_url": "https://wiki.gsmsoft.eu",
    "project_slug": "trientes",
    "manifest_path": "/projects/trientes/manifest.json"
  }
}'::jsonb)::json,
    update_date = NOW()
WHERE id = '8557fd43-07da-41c1-aa1d-c37bb0e3515a';

-- Проверка:
-- SELECT project_name, data->'docs' FROM service_connect ORDER BY project_name;

Автоматизация «новый проект → docs»

  1. Админка при POST /project/v1 дополняет service_connect.data.docs (project_slug, manifest_path = /projects/<slug>/manifest.json) — обязательный шаг создания проекта.
  2. Скелет папки в common_docs: CI-джоба scaffold копирует _TEMPLATE<slug>/, добавляет проект в реестр и открывает MR (запуск вручную командой Wiki или pipeline-trigger из admin-api). Рантайм-запись сервиса в git не делаем.

Чек-лист включения раздела

  • Wiki закрыта авторизацией (forward-auth).
  • Применён SQL service_connect.data.docs (teslapay, trientes).
  • Право projectDocsView добавлено и навешено на раздел (включая tech-info).
  • Секреты в документах обёрнуты маркером class="secret" / data-secret (маскируются для операторов без projectDocsSecrets) — см. §2.1.
  • Выбран способ встраивания (iframe+origin-check / прокси admin-api) и настроен CSP.
  • Админка читает manifest.index.json → per-project manifest.json → строит дерево → грузит тело по path.