#!/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()