CraftWeb
Loader image Loader image Loader image Loader image Loader image Loader image Loader image
0 %
Loading

ZłóżCV

From a job offer link to a tailored CV in 60 seconds

AI SaaS Next.js 16 React 19 Drizzle
SQLite Gemini 3 Pro Puppeteer

/ Overview

An AI CV generator that turns a job offer link into a tailored PDF in 60 seconds. One source-of-truth database, infinite per-offer variants. If it isn't in the database, it isn't in the CV.

See it live

/ Project Details

Category: AI SaaS · own product · PL market

Engagement: In-house product — CraftWeb Labs

Role: Full-stack · AI · PDF pipeline

Timeline: 2026

Live: zlozcv.pl

/ Problem

Every senior dev edits the same CV_v4_final_REAL_FINAL.docx for every offer. ATS-friendly + visually readable + persona-appropriate — three goals that fight each other. Generic builders ignore matching. "Rewrite my CV" prompts hallucinate skills you don't have.

/ TL;DR

60 s end-to-end

Parse → match → render → PDF. Average run: 56.4 s, exit 0, no hallucinations.

94% match

Average AI match score across 418 generations.

418 CVs

Generated to date. Build-in-public counter.

29 PLN/mo

Pro plan flat price for PL market, no per-CV fees.

/ Vision

One source of truth. Matching is the product. 60 seconds or it's broken. Three principles that survive every prompt revision.

/ Principles

One source of truth

Projects, experience, skills, personas live in one SQLite database. Every CV is a projection.

Matching is the product

The headline number is % match, not "PDF downloaded". Gemini 3 Pro picks the persona, scores every project, renders a bio in your tone.

60 seconds or it's broken

Any longer and the user is back to copy-pasting in Word.

/ Engineering challenges

Puppeteer /dev/shm in Docker. Multi-tenant SQLite slug collisions. LinkedIn 1-click import that survives the next redesign. Five challenges, five named commits.

/ 01 — 05

01 — Puppeteer /dev/shm hang in Docker

PDF export hung after ~30 s — default 64 MB /dev/shm exhausted. Fix: shm_size: "2gb" + --disable-dev-shm-usage + 400 ms CSS-settle wait.

02 — Multi-tenant slug collision

Global unique constraint on personas.slug broke for second user. Fix: composite per-user constraint uniqueIndex(...).on(table.userId, table.slug).

03 — Structured AI output without function-calling SDK

Function-calling API is ceremonial. Fix: one mega-prompt, raw JSON with strict shape, extractJson() fallback parser, Zod validates post-parse. Full control over retries.

04 — LinkedIn 1-click import that survives the next redesign

Two paths in onboarding-scan.ts — try API first, fall back to a textarea where the user pastes raw profile. Same parser handles both. Extension uses Better Auth bearer.

05 — Stripe webhook idempotency on single-VPS

No Redis, no distributed dedup. Fix: SQLite table stripe_webhook_events with event_id as PK. INSERT OR IGNORE on every event. Doesn't scale past one server — at current scale that's a feature.

/ Stack

Next.js 16 + React 19 + TypeScript strict + Zod 4. SQLite via Drizzle, Better Auth (cookies + bearer), Gemini 3 Pro, Puppeteer for PDF. One Docker box. Backups = cp.

/ Tech

Next.js 16 + React 19

App Router. Server Actions cut API-route ceremony. Route groups split marketing / dashboard / print.

SQLite + Drizzle ORM

One file in Docker volume. $inferSelect + Zod at AI boundary = one schema end-to-end.

Better Auth

Email/pwd + bearer plugin. Same auth table powers web app (cookies) and Chrome extension (bearer tokens).

Google Gemini 3 Pro

Fast, cheap, returns strict JSON. Anthropic SDK pinned as one-line failover.

Puppeteer + system Chromium

Renders real React Server Component at /cv/print/{id}. WYSIWYG with the dashboard.

Docker + Caddy on VPS

One docker compose up -d. Caddy handles TLS. shm_size: 2gb learned the hard way.

/ Results

Sustainable Pro tier for PL market. Public SaaS + personal cv.kawalec.pl sharing one database. The thing actually ships.

/ Numbers

94% avg match

Across 418 generations to date.

< 60 s pipeline

Full latency — parse, match, render, PDF.

29 PLN/mo

Sustainable Pro tier vs $20/mo US tools.

2 surfaces

Public SaaS + personal cv.kawalec.pl sharing one DB.

AI CV
Next.js 16
Drizzle
SQLite
Gemini 3 Pro
Puppeteer
Better Auth
Stripe
Docker
Resend