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.
122 lines
4.5 KiB
Python
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()
|