master-zapier-plan-draft/research/zapier/scripts/generate-diagrams-pdf.py
George Lambert b4150c8250 Milestone 0: import zappier billing, Verae middleware, and Zapier research
Compose-ready workspace: packages/zappier (rate card, portal, Stripe),
packages/verae-zapier-middleware (timestamp + NATS), packages/verae-zapier
(CLI app), vendor/zapier-platform, and research/zapier vendor corpus.

Gate 0 structure checks pass. Product code and research are not yet wired.
2026-09-09 02:37:36 -04:00

122 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""One-page-per-figure atlas of docs/diagrams/*.svg → docs/architecture-diagrams.pdf."""
from __future__ import annotations
import subprocess
import tempfile
from pathlib import Path
from reportlab.lib import colors
from reportlab.lib.enums import TA_CENTER
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.lib.units import inch
from reportlab.platypus import Image, PageBreak, Paragraph, SimpleDocTemplate, Spacer
ROOT = Path(__file__).resolve().parents[1]
DIAG = ROOT / "docs" / "diagrams"
OUT = ROOT / "docs" / "architecture-diagrams.pdf"
NAVY = colors.HexColor("#0F2744")
TEAL = colors.HexColor("#1A6B6B")
TITLES = {
"01-high-level-architecture.svg": "High-level architecture",
"02-security-boundaries.svg": "Security boundaries",
"03-auth-two-hop.svg": "Two-hop authentication",
"04-flow-async-timestamp.svg": "Create Timestamp (async + hook)",
"05-flow-wait.svg": "Create Timestamp and Wait",
"06-nats-topology.svg": "NATS subject topology",
"07-operations-map.svg": "Operations map",
"08-middleware-internals.svg": "Middleware internals",
"09-phase-roadmap.svg": "Phase roadmap",
"10-workspace-integration.svg": "Workspace integration",
"11-zapier-billing.svg": "Zapier and Verae billing layers",
"12-peergos-ipfs-tiered-storage.svg": "Peergos / IPFS / cold retrieve",
}
def header_footer(canvas, doc):
canvas.saveState()
w, h = letter
canvas.setFillColor(NAVY)
canvas.rect(0, h - 28, w, 28, fill=1, stroke=0)
canvas.setFillColor(colors.white)
canvas.setFont("Helvetica", 8)
canvas.drawString(0.7 * inch, h - 18, "Verae Time x Zapier")
canvas.drawRightString(w - 0.7 * inch, h - 18, "Architecture diagrams")
canvas.setFillColor(TEAL)
canvas.rect(0, 0, w, 22, fill=1, stroke=0)
canvas.setFillColor(colors.white)
canvas.setFont("Helvetica", 8)
canvas.drawString(0.7 * inch, 8, "Internal · 18 August 2026 · SVG sources in docs/diagrams/")
canvas.drawRightString(w - 0.7 * inch, 8, str(doc.page))
canvas.restoreState()
def main():
base = getSampleStyleSheet()
title_s = ParagraphStyle(
"t", parent=base["Title"], fontName="Helvetica-Bold", fontSize=22,
textColor=NAVY, alignment=TA_CENTER, spaceAfter=10,
)
cap = ParagraphStyle(
"c", parent=base["Normal"], fontName="Helvetica", fontSize=10,
textColor=NAVY, alignment=TA_CENTER, spaceBefore=6, spaceAfter=4,
)
body = ParagraphStyle(
"b", parent=base["Normal"], fontName="Helvetica", fontSize=10,
textColor=colors.HexColor("#334155"), alignment=TA_CENTER, leading=14,
)
tmp = Path(tempfile.mkdtemp(prefix="diag-pdf-"))
svgs = sorted(DIAG.glob("*.svg"))
usable_w = letter[0] - 1.2 * inch
usable_h = letter[1] - 1.6 * inch
story = [
Spacer(1, 2.2 * inch),
Paragraph("Architecture diagram atlas", title_s),
Paragraph(
"Vector sources live in docs/diagrams/. This PDF is a print/review pack "
"of the same figures used in getting-started.pdf.",
body,
),
PageBreak(),
]
for svg in svgs:
png = tmp / (svg.stem + ".png")
subprocess.run(
["rsvg-convert", "-w", "1800", "-f", "png", "-o", str(png), str(svg)],
check=True,
)
# keep aspect, fit page
# unknown px size: use viewBox from svg
text = svg.read_text(encoding="utf-8", errors="ignore")
import re
m = re.search(r'viewBox="0 0 (\d+) (\d+)"', text)
vw, vh = (int(m.group(1)), int(m.group(2))) if m else (1100, 620)
scale = min(usable_w / vw, usable_h / vh)
iw, ih = vw * scale, vh * scale
story.append(Paragraph(TITLES.get(svg.name, svg.stem), cap))
story.append(Image(str(png), width=iw, height=ih))
story.append(Paragraph(svg.name, body))
story.append(PageBreak())
if story[-1].__class__.__name__ == "PageBreak":
story.pop()
doc = SimpleDocTemplate(
str(OUT),
pagesize=letter,
leftMargin=0.6 * inch,
rightMargin=0.6 * inch,
topMargin=0.5 * inch,
bottomMargin=0.4 * inch,
title="Verae Time x Zapier — architecture diagram atlas",
author="Verae / Zapier research workspace",
)
doc.build(story, onFirstPage=header_footer, onLaterPages=header_footer)
print(f"wrote {OUT} ({OUT.stat().st_size} bytes, {len(svgs)} figures)")
if __name__ == "__main__":
main()