Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/CristianParadaLopez/cv-builder/llms.txt

Use this file to discover all available pages before exploring further.

Skillara AI is composed of two independent, separately deployable services: a React single-page application that handles the user interface and a Node.js/Express API server that handles AI routing, prompt construction, and PDF rendering. The two services communicate exclusively over HTTP and can be hosted on different platforms — the production deployment runs the frontend on Vercel and the backend on Render.

Frontend

The frontend is a React 19 application built with Vite and TypeScript, styled with Tailwind CSS, and deployed on Vercel. It is a single-page app with client-side routing managed by React Router v7. Application routes:
PathPage
/Home / landing page
/builderCV form and preview builder
/guiaUsage guide
/aboutAbout the project
/atsATS mode explainer
/plataformasJob platforms guide
/seguridadPrivacy and security information
/faqFrequently asked questions
/loginGoogle OAuth login
/dashboardSaved CVs (protected — requires authentication)
Authentication and storage: The frontend uses Firebase Authentication with GoogleAuthProvider to implement Google OAuth sign-in. Authenticated users’ generated CVs are stored in Firestore via the db client exported from firebase/config.ts. The /dashboard route is wrapped in a ProtectedRoute component that redirects unauthenticated users to /login. Local persistence: Form data is persisted to localStorage through a usePersistCV hook so that in-progress CVs survive page refreshes. This works for both authenticated and anonymous users and requires no backend involvement.

Backend

The backend is an Express 5 server written in TypeScript, running on port 3001 by default (configurable via the PORT environment variable). It is deployed on Render and configured to accept CORS requests from the two Vercel frontend domains and any URL set in the FRONTEND_URL environment variable. API routes:
MethodPathDescription
POST/api/cv/generateGenerate a new CV from form data. Requires name and email in formData.
POST/api/cv/editEdit an existing CV HTML string using a natural-language prompt (max 1000 characters).
POST/api/cv/suggestImprove a single form field value using AI. Accepts userText, context, and optional systemPrompt / examples.
Database schema (Prisma / PostgreSQL): The backend includes a Prisma schema with three models for server-side persistence:
  • User — stores user accounts with optional googleId for Firebase Auth linkage, photoURL, and emailVerified state.
  • CV — stores the full HTML output (html), an optional ATS variant (htmlATS), the original formData as JSON, the style and mode used, a title, a last-edit prompt, and visibility/view-count fields.
  • FormCache — caches form data for anonymous sessions identified by a sessionId UUID, allowing server-side persistence without requiring login.

AI routing

All AI calls are handled by the callWithFallback function in claude.service.ts. Rather than relying on a single API key or model, the system maintains a pool of OpenRouter API keys and a list of model identifiers, then tries every key–model combination in sequence until one succeeds. Key pool: Up to five OpenRouter API keys can be configured via environment variables (OPENROUTER_API_KEY_1 through OPENROUTER_API_KEY_5), each optionally named (DEV1_NAME through DEV5_NAME). Keys with empty values are filtered out at startup. The order is DEV2 → DEV3 → DEV4 → DEV5 → DEV1. Model list: The models to try are read from the AI_MODELS environment variable as a comma-separated list. The default is:
meta-llama/llama-3.1-8b-instruct:free,deepseek/deepseek-r1-0528:free,google/gemini-2.0-flash-exp:free
All requests are sent to the OpenRouter API (https://openrouter.ai/api/v1) using the standard OpenAI SDK with a custom baseURL. Fallback logic: For each request, callWithFallback iterates over the key pool and, for each key, iterates over the model list. If a request fails with HTTP status 429, 402, or 503 (rate limit, quota, or service unavailable), or if the returned content is empty or shorter than 100 characters, the function logs a warning and moves to the next combination. Only if every combination fails does it throw an error to the caller.
If all configured API keys and models are exhausted — for example because all free-tier quotas have been consumed — the /api/cv/generate endpoint returns a 500 error with the message “Error al generar el CV. Por favor intentá de nuevo.” Adding additional keys or upgrading to paid tiers on OpenRouter eliminates this risk.

Data flow

The following sequence describes the complete path from user input to downloaded PDF:
  1. User fills the form in the React frontend at /builder and selects a template style and mode.
  2. Frontend sends POST /api/cv/generate with a JSON body containing formData, style, and mode.
  3. Backend validates the request — it checks that name and email are present and normalises style and mode to allowed values.
  4. Backend builds a prompt by combining the candidate’s form data with the detailed styleGuide string for the selected template (or the ATS guide for mode: "ats"). If a profile photo was included, it is stripped from the data sent to the AI and a PHOTO_PLACEHOLDER instruction is injected instead.
  5. callWithFallback selects a key + model combination and calls the OpenRouter API. On success it returns the raw model output.
  6. AI returns complete HTML for the styled CV document. The backend extracts the HTML (stripping any markdown fences), then re-injects the base64 photo at the PHOTO_PLACEHOLDER src attribute if a photo was provided.
  7. Backend returns { html } to the frontend, which renders it inside the preview iframe.
  8. User optionally edits the result by typing a natural-language instruction into the PromptBar. The frontend sends POST /api/cv/edit with the current HTML and the instruction; the backend repeats the AI call and returns updated HTML.
  9. User clicks “Descargar PDF”. The frontend generates the PDF entirely in the browser using html2canvas and jsPDF — no additional request is made to the backend. The file is saved locally as mi-cv-skillara.pdf.

Frontend source

Explore the builder form, PromptBar, preview panel, and PDF download flow.

API Reference

Full request and response schemas for every backend endpoint.

AI Keys config

How to configure OpenRouter API keys and choose which models to enable.

Database setup

Provisioning a PostgreSQL database and running Prisma migrations.

Build docs developers (and LLMs) love