Central Documentation Factory
Multi-tenant document generation, conversion & billing worker for four brand portals
From converter to factory
What started as a single-tenant PDF/DOCX converter for Lasanta India has matured into a private, multi-tenant document factory sitting behind four production brand portals — Lasanta India, Narven Group, Vin Precast, and Pryde Ergon. The rebrand is structural, not cosmetic: one service now owns document generation, format conversion, and centralized billing for the whole estate.
The portals stay snappy on Vercel; the heavy compute runs scale-to-zero on Cloud Run; the contract between them is one HMAC handshake away.
The multi-pass best mode
PDF↔DOCX is the workload that needed the most engineering. A naive libreoffice --convert-to mangles tables, forms, and image-anchored layouts. The factory now runs a multi-pass best mode for PDF→DOCX: three candidates in parallel — a native cleanup pass, a structured-fidelity pass, and a visual-replica pass — and keeps whichever produces the strongest editable result. PDF→TXT runs through Docling for structure-aware extraction.
- Source formats — DOCX, PDF, MD, TXT, PNG, JPG, plus ZIP for batched jobs.
- Compression modes —
off · balanced · maxper request, applied per target format. - OCR pass — image-to-text via Tesseract for scanned PDFs and signed LOIs.
Tenant matrix
Each consuming portal registers as a caller with its own shared secret — LASANTA_SHARED_SECRET, NARVEN_SHARED_SECRET, VINPRECAST_SHARED_SECRET, PRYDEERGON_SHARED_SECRET — and signs every request with an X-Converter-Caller + X-Converter-Shared-Secretheader pair. The worker verifies, scopes the job to that tenant, and records the conversion against the tenant’s wallet.
Adding a fifth tenant is a one-line registration plus a secret rotation — no per-app API key churn.
API surface
GET /api/health— production-gated truthiness so load balancers don’t flap on cold start.POST /api/convert— multipart synchronous path for files that fit under the request budget.POST /api/jobs— async path. Worker writes input to GCS, returns a job id, posts result back to the tenant on completion. Backed by Firestore + Cloud Tasks (M4).- Per-job options — compression mode, target format, OCR flag, ZIP bundling, brand-specific template id for generated quotations / invoices / work orders.
Roadmap
- M1 — baseline port from the single-tenant Conversion Studio (done).
- M2 — staging validation against real Lasanta + Narven traffic (done).
- M3 — quality regression pack covering every source→target pair, run on every deploy.
- M4 — async job flow via Firestore + Cloud Tasks; GCS-routed lifecycle for large inputs.
- M5 — Lasanta integration on the new tenant header contract; deprecate the legacy single-tenant path.
- M6 — hardening pass: dead-letter queues, tenant wallet alerts, signed audit log shipping.
What I learned
- Caller-scoped secrets beat per-app API keys once you cross three consumers. Rotation, audit, and registration all collapse into one place.
- PDF parity is bounded. Editable fidelity is the right north star, not pixel parity — fight for the right one.
- Scale-to-zero + headless LibreOffice is a research project the first time and a copy-paste the second. Bake the deps into a single base image and reuse across workloads.
- Multi-pass
bestmode trades a few extra seconds for editable output that real users actually keep — worth it for trade docs that get countersigned.
