The Problem
Many developers need a self‑hosted resume builder that stores user data locally, offers real‑time editing, and can export to PDF/Docx without third‑party tracking. Existing SaaS tools either lock data behind a service or require heavyweight infrastructure to run a full‑stack app.
What This Does
reactive-resume is a monorepo of five loosely coupled projects that together deliver a privacy‑first resume service.
- Front‑end –
apps/webcontains a React UI built with Vite (apps/web/vite.config.ts). The main entry point isapps/web/src/dialogs/resume/index.tsx, which renders the editor and talks to the back‑end via REST. - Back‑end –
apps/serverruns an Express API (apps/server/src/http/app.ts) started fromapps/server/src/index.ts. It loads feature modules frompackages/api(e.g.,packages/api/src/features/resume/service.ts) and PDF generation frompackages/pdf. - PDF generation –
packages/pdf/src/document.tsxcomposes the final PDF using the semantic model (packages/pdf/src/semantic/*). This module is the most connected hub (32 inbound imports). - AI helpers –
packages/aiwraps OpenAI/Claude/Gemini calls used by the UI for content suggestions. - Schema & migrations –
packages/schemadefines the resume data model;migrationsholds SQL scripts for the optional Postgres store.
All projects share a single pnpm workspace, Docker support (Dockerfile, Dockerfile.dev), and CI via GitHub Actions.
How It Is Wired
Execution begins with the server entry point apps/server/src/index.ts, which creates an Express app (apps/server/src/http/app.ts). The app registers routes from packages/api – for example, the resume CRUD routes are defined in packages/api/src/features/resume/. Those handlers invoke the schema layer (packages/schema/src/resume/data.ts) and, when a PDF export is requested, call packages/pdf/src/document.tsx.
packages/pdf/src/document.tsx imports the template system (packages/pdf/src/templates/*) and the semantic graph (packages/pdf/src/semantic/*). The import graph shows it as a hub module (32 dependents, 9 imports) and participates in a circular dependency with packages/pdf/src/semantic/template-manifest.ts and packages/api/src/features/resume/stylesheet-preflight.ts. The cycle inflates build time and makes refactoring risky.
On the client side, Vite serves the React bundle; the UI boots from apps/web/src/dialogs/resume/index.tsx, which contacts the API endpoints defined above. Authentication, passkey, and 2FA logic live under apps/server/src/mcp/ and are consumed by the UI through token‑based calls.
The blast radius of changes is highest in packages/pdf/src/document.tsx (hub) and in oversized files such as packages/pdf/src/templates/shared/sections.tsx (1,373 lines). Deep nesting (max depth 7) appears in the same PDF modules, adding cognitive load for future contributors.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/reactive-resume.git
cd reactive-resume
# Install dependencies with pnpm (workspace root)
pnpm install
# Copy example env and edit as needed
cp .env.example .env # set DB_URL, JWT secret, OpenAI keys, etc.
# Build and run locally (Docker optional)
pnpm dev # starts both Vite front‑end and Express server
# or, containerised:
docker compose up -d # uses Dockerfile.dev for dev image
The server reads configuration from .env. The front‑end expects the API at http://localhost:3000 (default in apps/web/.env if present). The docker-compose.yml (not listed) orchestrates the services; otherwise pnpm dev runs them concurrently via the workspace scripts.
Real‑World Use
A company can deploy the Docker image (docker build -t reactive-resume .) behind its internal reverse proxy. Employees log in with passkeys, edit their resumes via the React UI, and export PDFs that are generated on‑the‑fly by the PDF hub. Because all data lives in the company’s PostgreSQL instance (migrations in migrations/), no external service ever sees personal information.
Code Health & Issues
- HIGH – GitHub Actions use mutable tags (
@v6,@v2). Pin to commit SHA to avoid supply‑chain risk. - HIGH – CI never runs the test suite (354 test files). Add a test step to existing workflows.
- MEDIUM – No Dependabot/Renovate config; add
.github/dependabot.yml. - MEDIUM – Docker base image (
node:${NODE_VERSION}-slim) is unpinned; use digest. - MEDIUM – No dependency‑vulnerability scan in CI; add
dependency-review-actionorosv-scanner. - MEDIUM – Checkout step keeps token; set
persist-credentials: false. - LOW – No job timeouts; add
timeout-minutes. - LOW – Missing editor/formatter conventions (
.editorconfig,.gitattributes).
Static analysis also flagged import cycles (5 modules), deep nesting (32 occurrences), oversized files (5 files >1k lines), and a hub module with 32 dependents, all of which increase maintenance cost.
The Bottom Line
reactive-resume provides a complete, self‑hostable resume platform with a modern React front‑end and a TypeScript/Express back‑end, but its PDF subsystem is a maintenance hotspot due to cycles and large files. The repo is CI‑ready but needs hardening (pinned actions, test execution, dependency scanning). It is well suited for teams that require full data control and are comfortable managing a monorepo with Docker and pnpm.