Two-package monorepo template editor — build A4 pages from text, table, image, and shape elements, save them as reusable templates, and export to PDF entirely client-side.
A4 drag-and-drop editorMulti-page documentsClient-side PDF exportExpress + MongoDB templates API
Summary
Template Management App is a visual, drag-and-drop document editor built as a two-package monorepo — a Next.js 16 App Router frontend and an Express 4 + MongoDB API. Pages render on an interactive A4 canvas (794 × 1123 px) at 0.5–1.5 zoom, where text, table, image, and shape elements are dragged, resized through eight handles, and edited inline without leaving the surface.
Three client-side Zustand stores keep the editor honest: one owns tabs and the document, one owns ephemeral view state like zoom and save status, and one derives undo/redo from per-tab history. Each tab carries its own dirty flag, selection, and 50-step history, so several documents stay open at once. Table rows reorder with @dnd-kit sortable, a quotation-style table renumbers its “#” column automatically, and a read-only preview renders the clean document before export.
Saving goes through an Express API backed by MongoDB Atlas — one document per template with pages and elements embedded, so a save is a single atomic write. Zod validates every request body at the boundary, ObjectIds are checked before queries, and responses share one success/error envelope with a stable error code. A template named template1 is restored on the next visit, and PDF export runs entirely in the browser through @react-pdf/renderer — there is no server rendering anywhere in the flow.
The Challenge
Client Objectives
Provide a visual editor for reusable business documents like quotations, invoices, and reports.
Support multi-page A4 documents built from text, table, image, and shape elements.
Persist templates through an Express + MongoDB API and restore template1 automatically.
Export the active canvas state to PDF without a server round trip.
Core Challenges
Keeping dragging, resizing, and inline text editing from fighting over the same canvas.
Separating editor document state from server cache without duplicating the source of truth.
Making undo/redo feel right across rapid edits and discrete table operations.
Exporting a faithful PDF when the renderer ships only standard fonts.
My Solution
I designed and built the app as a two-package monorepo. The frontend is a Next.js 16 App Router editor where Zustand owns the document, TanStack Query owns server state, and pure geometry modules handle drag deltas and resize math — every delta divided by zoom so the model stays in unscaled A4 coordinates. The backend is a layered Express 4 API (routes → controller → service → mapper) with Zod validation, a central error taxonomy, and an embedded Mongoose schema. PDF export is a lazy dynamic import that collects image data URLs and renders each page in order, keeping the PDF engine off the critical path.
Key Highlights
Two-package monorepo: the Next.js 16 App Router editor and the Express 4 + MongoDB Atlas API deploy separately — Vercel for the UI, Render for the API — with a /api/health probe that reports Mongo readiness, not just process liveness.
A4 canvas at 794 × 1123 px with 0.5–1.5 zoom, drag-to-move, and eight resize handles; every pointer delta is divided by zoom so the stored model never inherits the canvas scale.
Text, table, image, and shape elements with per-type property panels; text areas and table cells edit in place because the DnD sensor refuses to start a drag from inputs, textareas, selects, and contenteditable nodes.
Per-tab undo/redo, 50 snapshots deep, with rapid edits coalesced inside a 500 ms window and discrete operations like adding a table row forcing a fresh entry — history stays in client state, so no server request per keystroke.
Templates persist as one embedded MongoDB document each with a unique name index, so the by-name route resolves the template1 autoload and PDF export runs via a lazily imported @react-pdf/renderer.