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.
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.
Free-CV follows a state-driven frontend with a service-oriented backend:
- 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
- Modular architecture for:
- User management
- Resume persistence
- Payment workflows
- AI Assistance
- API-driven communication with the frontend
- 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
- MongoDB for storing structured resume data and user profiles
- Redis for rate limiting and caching
- Designed schema to support flexible sections (experience, education, etc.)
- Firebase Storage for assets (images, generated PDFs)
- Polar.sh integration for handling payments and premium features (one-time upgrade, not subscription-based)
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
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
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
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
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
Ensuring that every user input reflects instantly and accurately in the preview.
Solution:
- Single source of truth via Redux
- Derived UI rendering from state
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
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
- 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
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