Works·launched

Assembly

Turning documents into one report

A web app that assembles formal client reports.

A study in Assembly: five appendix sections, each with its files and page counts, beside a preview of the merged report open at the end of Appendix A, where the footer reads Riverbend Office, Page 7 of 39, and Appendix B's cover begins
A study and its preview. Every page carries one footer, and each appendix opens on its own cover.
The template editor in Assembly: five sections with uploaded covers, section numbering set to A, B, C with the label Appendix, and the footer settings for every cover, with placeholders and a live example
The template editor. Sections, covers, numbering and footer rules are set once per kind of report.
Version history in Assembly: three published versions of the Building Condition Assessment template, each with a note; the latest shows its footer, numbering and cover thumbnails
Version history. Studies stay on the version they were built from.

The problem

The team at a consulting firm assembled every formal client report by hand: a cover page, then appendix dividers, then the documents for each appendix, merged into one PDF. The same nine report structures, over and over, with different content each time.

Done by hand, it was slow and easy to get wrong: pages out of order, numbering that restarted halfway through, an appendix missing. Every project deliverable paid that cost again.

What I built

A web app that turns report assembly into a short flow:

Set up template → Publish version → Create study → Add files → Preview → Export

Each kind of report is a template: its sections, a cover for each, how sections are lettered, and what the footers say. Publishing a template freezes it as a version. After that, someone creates a study from a version, drops PDFs or Word documents into its sections, picks the pages they need, previews the whole thing, and exports one PDF with continuous page numbering, or a ZIP with a folder per section.

How it works

Three services: a Next.js front end, a FastAPI back end, and Gotenberg, a document-conversion service that runs LibreOffice behind an HTTP API. The work happens in three flows, at three different times:

Assembly architecture, top to bottom. A report author creates a study pinned to one template version and uploads documents through the study page to the study API, which keeps the originals on a file volume and the metadata in SQLite. A template owner edits a template and publishes it as a version, which freezes and fingerprints its covers and footer rules. The pipeline converts Word files to PDF with Gotenberg, keeps the chosen pages, cleans old footers, adds the version's covers, merges and stamps every page with a bookmark per section, and compresses the result with Ghostscript. Previews are cached under a hash of every input; exports are built fresh and returned as a PDF or ZIP.NEXT.JS FRONT ENDFASTAPISTORAGEPIPELINEOUTPUTReport authorbuilds one reportTemplate ownersets up each kind of reportStudy pagefiles, pages, previewTemplate editorsections, covers, footersStudy APIpinned to one versionTemplate APIpublishes versionsFile volumeoriginals, as uploadedSQLitemetadataVersionsfrozen, fingerprintedWord → PDFGotenbergPick pagesthe author's choiceClean footerspreviewed firstAdd coversfrom the versionMerge + stampfooters, bookmarksCompressGhostscriptPreview cachekeyed by every inputPDF · ZIP exportbuilt freshuploadsoriginalsreturnseditspublishesmetadatacoverspreviews

The highlighted path follows a document from upload to the finished report.

A few of the decisions:

What was hard

Footers. Page numbering sounds trivial until the source documents already have their own, so cleaning exists as its own step, with a preview. Then covers needed different footers from pages, one appendix needed different ones from the rest, and one study needed to override its template. The fix was to name five levels and one rule: the most specific setting wins.

What I learned

Assembly does one narrow job for one team, and it removed a task people repeated on every project. Understanding that job precisely was the real work; the build was small.