System Overview
The local-first architecture, the optional cloud layer, the client-side export pipeline, and the full technology stack.
System Overview
VeriWorkly is a monorepo of four Next.js frontends, a documentation site, a blog, and one Express API. Document editing runs local-first in the browser, with an optional cloud layer for sync, sharing, AI, ATS scoring, and portfolio publishing.
Local-First Engine
By default the document builder is a client-side application.
- Client storage — resumes, cover letters, workspace settings, and the cached Master Profile are
written to the browser's
localStorage. - Service independence — you can create, edit, preview, and export a document without ever calling the backend.
- Guest sessions — logged-out users get a 30-day HttpOnly guest cookie
(
veriworkly-guest-mode), so work survives reloads without an account.
Optional Cloud Layer
Signing in adds a background sync engine on top of local storage.
- Synchronisation — local documents are pushed to PostgreSQL through the Express API, authorised by a Better-Auth session cookie.
- Conflict management — each
Documentrow carries arevisioncounter for optimistic concurrency, plus per-document sync states (local-only, pending, syncing, synced, conflicted) and a conflict-resolution view. - Per-document opt-out — any single document can be marked "keep local only" and excluded from sync entirely.
Server-Side Capabilities
Some features are inherently server-side and require an account:
- AI generation and ATS analysis — resume rewriting, cover letter generation, job tailoring, portfolio copy, and ATS deep analysis all run on the server against external LLM providers.
- File extraction — PDF, DOCX, TXT, MD, and JSON resume uploads are parsed server-side
(
pdf-parseandmammoth), not in the browser. - Portfolio rendering and publishing — published portfolios are server-rendered from stored snapshots.
- Sharing — public share links are backed by a server-side snapshot of the document.
Client-Side Export Pipeline
All six export formats are produced in the browser. Nothing in the export path shells out to a headless browser — there is no Puppeteer anywhere, and the one Playwright dependency in the repository belongs to Studio's dev-only preview/PDF parity test harness, not to any runtime code.
- Normalisation — the current document state is read from its Zustand store and normalised (dates, rich-text fragments, hidden sections).
- Dispatch —
exportDocumentByTypeswitches on the document'stype(RESUMEorCOVER_LETTER) and then on the requested format. - Generation — PDF via
@react-pdf/renderer, DOCX via thedocxpackage, and HTML/Markdown/ text/JSON via dedicated serialisers. All produce aBloblocally. - Delivery — the
Blobbecomes a temporary object URL and downloads directly. Document content is never uploaded to a server to produce an export.
See Export Pipeline for the dual-engine template model.
Technology Stack
Frontend stack
| Layer | Technology | Purpose |
|---|---|---|
| Framework | Next.js 16 (App Router) | React meta-framework with SSR and route handlers |
| UI library | React 19 | Component runtime |
| Styling | Tailwind CSS 4 | Utility-first CSS using the CSS-native @theme API |
| Design system | @veriworkly/ui | In-house shared component library (no Radix or MUI) |
| PDF generation | @react-pdf/renderer | Client-side, high-fidelity PDF rendering |
| DOCX generation | docx | Client-side Word document generation |
| State management | Zustand | Lightweight stores, persisted to localStorage |
| Validation | Zod | Schema validation for imported and synced data |
| Theming | next-themes | Light / dark / system theme switching |
| Icons | Lucide React | Shared icon set |
| Notifications | Sonner | Toast notifications in Studio |
| Docs & blog | Fumadocs + MDX | Content platform for docs and blog |
Backend stack
| Layer | Technology | Purpose |
|---|---|---|
| Runtime | Node.js 20+ | Server runtime, clustered via throng in production |
| Framework | Express 4 | HTTP server |
| Language | TypeScript (strict) | Type safety across the backend |
| Database | PostgreSQL | Primary relational store |
| ORM | Prisma 7 | Type-safe database access and migrations |
| Cache & counters | Redis | Sessions, rate limiting, quotas, view buffers, locks |
| Authentication | Better-Auth | Email OTP plus Google, GitHub, and LinkedIn OAuth |
| Object storage | Cloudflare R2 (S3-compatible) | Portfolio image uploads via presigned URLs |
| Payments | Dodo Payments | Subscriptions, one-off purchases, billing portal |
| AI | OpenAI-compatible client | Routed across Anthropic Claude and OpenAI GPT models |
| File parsing | pdf-parse, mammoth | Server-side PDF and DOCX text extraction |
| Nodemailer (SMTP) | Transactional email; console provider in dev | |
| Scheduling | node-cron | Five background jobs, guarded by Redis locks |
| Validation | Zod | Request payload validation |
| Testing | Vitest | Unit and integration tests |
| Security | Helmet | HTTP security headers |
AI provider routing
AI requests are routed dynamically across Anthropic Claude and OpenAI GPT models to balance quality against cost. The routing policy is loaded from private configuration at boot and is not a user-facing setting.
Reference Guides
- Monorepo Architecture — the six applications and shared packages.
- State Management — stores, persistence, and the sync engine.
- Resume Schema —
ResumeDataandMasterProfileData. - Database Schema — the Prisma data model.
- Export Pipeline — the dual-engine template system.
- Local Setup — configuring a development environment.