Free-cv

Free-CV is a full-stack CV builder that helps users create professional resumes in minutes.

Technologies

  • Next.js
  • Tailwind CSS
  • Nest.js
  • MongoDB
  • Firebase
  • Redux Toolkit
  • Redis
  • Puppeteer
  • Polar.sh
  • Motion
  • Vercel
  • PostHog
  • PWA

Overview

Free-CV is a full-stack resume builder designed to provide a fast, flexible, and production-grade experience for creating professional resumes with 40+ customizable templates.

The platform enables users to build, customize, and export resumes with real-time feedback, an AI-powered writing assistant, and reliable PDF generation across every device, while handling complex structured data, template rendering, and authentication at scale.

The Problem

Resume builders are deceptively hard to build well. The data is deeply nested, the preview must stay perfectly in sync with edits, and PDF generation from web layouts is notoriously unreliable - especially across mobile browsers. Add AI-assisted writing, cross-origin authentication, and payments on top, and you've got a real full-stack challenge.

System Design & Architecture

Free-CV follows a state-driven frontend with a service-oriented backend:

Client (Next.js)

  • Centralized state management using Redux Toolkit
  • Real-time preview rendering based on state changes
  • Client-side A4 pagination using ResizeObserver and a greedy bin-packing algorithm
  • Template abstraction layer for reusable layouts
  • Optimistic UI for smooth editing experience
  • PWA support for installability

Backend (Nest.js)

  • Modular architecture for:
    • User management
    • Resume persistence
    • Payment workflows
    • AI Assistance
  • API-driven communication with the frontend

PDF Export Service (Puppeteer)

  • A standalone Node/Express service running headless Chrome via Puppeteer
  • Renders a dedicated, chrome-less "print view" of the resume - reusing the existing UI components - and exports it to PDF server-side

Data Layer

  • MongoDB for storing structured resume data and user profiles
  • Redis for rate limiting and caching
  • Designed schema to support flexible sections (experience, education, etc.)

Storage & Payments

  • Firebase Storage for assets (images, generated PDFs)
  • Polar.sh integration for handling payments and premium features (one-time upgrade, not subscription-based)

Key Engineering Decisions

1. Centralized State Management

Decision: Use Redux Toolkit for managing resume state.

Why:

  • Resume data is deeply nested and frequently updated
  • Multiple components depend on shared state (editor + preview)

Outcome:

  • Predictable state updates
  • Easier debugging and extensibility

2. Real-Time Preview Architecture

Decision: Derive preview directly from application state.

Why:

  • Ensures consistency between user input and rendered output
  • Avoids duplication of logic between editor and preview

Challenge:

  • Frequent updates can cause performance issues

Mitigation:

  • Component-level memoization
  • Selective re-rendering strategies

3. Server-Side PDF Rendering with Puppeteer

Decision: Move PDF export from client-side browser printing to a dedicated Puppeteer service running headless Chrome.

Why:

  • The client-side react-to-print approach relied on window.print() and CSS print rules, which all mobile browsers handle inconsistently - the entire page would print instead of just the resume
  • A real Chrome rendering engine on the server guarantees pixel-consistent output regardless of the device the user exports from
  • Reuses the existing UI components as-is

Outcome:

  • Consistent, reliable PDF export across desktop, mobile, and tablet
  • No rewrite of resume template components required

4. Multi-Provider AI Writing Assistant

Decision: Build an AI content-generation chain that uses multiple LLM providers to provide AI-powered resume assistance.

Why:

  • LLM APIs carry per-minute and per-day rate limits
  • A single point of failure on one provider would degrade the writing assistant for all users during a rate-limit window

Implementation:

  • A configurable fallback chain tries several models/providers in order, skipping any model currently rate-limited
  • Redis tracks per-model cooldowns, parsed directly from provider rate-limit errors
  • A concurrency-aware request queue caps in-flight requests per model and gracefully rejects with a clear message when saturated

Outcome:

  • The writing assistant, JD-matching, resume review, and cover-letter generation features degrade gracefully instead of failing outright under rate-limit pressure

5. Template Abstraction System

Decision: Design templates as reusable, configurable components.

Why:

  • Enables adding new templates without changing core logic
  • Supports different layout structures

Outcome:

  • Scalable template system
  • Faster iteration for new designs

Challenges

Synchronizing Editor and Preview

Ensuring that every user input reflects instantly and accurately in the preview.

Solution:

  • Single source of truth via Redux
  • Derived UI rendering from state

Generating Pixel-Perfect, Cross-Device PDFs

Getting pixel-perfect PDFs is more art than science - different browsers render shadows, fonts, and spacing slightly differently, and mobile browsers handle print contexts inconsistently.

Solution:

  • Moved PDF generation server-side to a Puppeteer-based microservice running real Chrome, decoupling export quality from the exporting device's browser
  • Explicit readiness signaling (font loading + layout pagination stability) before the PDF snapshot is taken, avoiding races with custom web fonts

Managing Complex Nested Data (10+ dynamic sections)

Resume structures vary significantly across users.

Solution:

  • Flexible schema design in MongoDB
  • Normalized and predictable state structure in frontend

A frontend and backend on separate origins, combined with modern browsers blocking third-party cookies by default, silently broke authenticated actions for a meaningful slice of users.

Solution:

  • Migrated to a first-party httpOnly cookie held by the frontend's own API layer, with a Backend-for-Frontend proxy pattern forwarding requests server-to-server

Impact

  • Preview latency under 100ms for most edits
  • Supports 10+ resume sections without UI lag
  • Reliable, pixel-consistent PDF export across desktop, mobile, and tablet
  • AI writing assistant remains available even under individual provider rate limits

Learnings

This project was a strong exercise in building state-heavy, real-time applications with a genuine production surface area:

  • Designing scalable state management for complex UIs
  • State management for real-time document editors is its own discipline
  • Structuring applications for extensibility (templates, features)
  • Building production-ready flows involving authentication and payments
  • Cross-origin cookie behavior is no longer a safe default to build on - first-party, explicit token handling is more resilient
  • Multi-provider AI chains are essential once a feature depends on external LLM APIs in production