docs(handbook): интерактивная карта слоев хранилища
Зачем: путеводитель рассказывает путь данных через слои словами, а карта дает его увидеть и потрогать: у одного смысла в каждом слое свое имя и своя поверхность, а переносят данные три разных механизма — матвью непрерывно, даг пачкой, представление без копии. Постановка — тикет #222, форма — резолюция #208 (один самодостаточный HTML, исходники рядом). Что: docs/handbook/architecture-map.html — готовая карта; исходники в docs/handbook/architecture-map/ (map.yaml — слои, узлы, стрелки, карточки; template.html — разметка, стили, скрипт; render.py — сборка и --check; README.md). Щелчок по узлу открывает карточку и подсвечивает путь, щелчок по стрелке — кто и каким SQL переносит данные; переключатель потока приглушает чужую часть карты. Ссылки карточек ведут в справочники и DDL на Gitea. Путеводитель и глава о хранилище ведут на карту; make lint проверяет ruff для сборщика и свежесть рендера; testing.md и AGENTS.md обновлены. Проверка: uv run docs/handbook/architecture-map/render.py --check и make lint зеленые; внешних запросов в HTML нет; ссылки и якоря карточек сверены с Gitea; карта прощелкана в headless Chromium на ширинах 1280–1920: подсветка пути, фильтр, Esc, карточки узлов и стрелок. Ревью: постановка — Opus; реализация — Codex (Sol), два слепых ревью Opus (уместность и код), вычитка прозы Sol.
This commit is contained in:
1 parent
4995628f2a
commit
466acafce6
10 files changed
+2720
-8
No files matched your search
@@ -0,0 +1,54 @@
|
||||
# /// script
|
||||
# requires-python = ">=3.13"
|
||||
# dependencies = ["pyyaml"]
|
||||
# ///
|
||||
|
||||
"""Собрать интерактивную карту хранилища из YAML и HTML-шаблона."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
ROOT = Path(__file__).parent
|
||||
SOURCE = ROOT / "map.yaml"
|
||||
TEMPLATE = ROOT / "template.html"
|
||||
OUTPUT = ROOT.parent / "architecture-map.html"
|
||||
MARKER = "/*__MAP_DATA__*/"
|
||||
NOTICE = (
|
||||
"<!-- Файл собран автоматически. Правьте architecture-map/map.yaml и "
|
||||
"template.html, затем выполните uv run "
|
||||
"docs/handbook/architecture-map/render.py. -->\n"
|
||||
)
|
||||
|
||||
|
||||
def render() -> str:
|
||||
"""Подставить данные карты в шаблон без изменения порядка ключей."""
|
||||
data = yaml.safe_load(SOURCE.read_text(encoding="utf-8"))
|
||||
payload = json.dumps(data, ensure_ascii=False, indent=2)
|
||||
template = TEMPLATE.read_text(encoding="utf-8")
|
||||
return NOTICE + template.replace(MARKER, payload)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Записать карту или проверить, что готовый файл не устарел."""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--check", action="store_true", help="проверить готовый файл")
|
||||
args = parser.parse_args()
|
||||
rendered = render()
|
||||
if args.check:
|
||||
if not OUTPUT.exists() or OUTPUT.read_text(encoding="utf-8") != rendered:
|
||||
print(f"{OUTPUT} устарел; пересоберите карту")
|
||||
return 1
|
||||
print(f"{OUTPUT} соответствует исходникам")
|
||||
return 0
|
||||
OUTPUT.write_text(rendered, encoding="utf-8")
|
||||
print(f"собрана карта: {OUTPUT}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user