Loading repository data…
Loading repository data…
jamaljm / repository
SnapCV is an AI-driven tool that turns resumes into professional portfolios with ease. Just upload your resume, and our AI handles the rest.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
Turn your résumé into a portfolio site in about 20 seconds.
Free, open source, and yours to edit. Every portfolio lives at yourname.snapcv.me.
Live demo · Contribute · Report an issue
Upload a résumé (or paste a LinkedIn URL) → an AI backend structures it → you get a hosted portfolio and a clean résumé page. No blank canvas, no paywall, no template smell.
Coming from read.cv or Bento (both shutting down)? SnapCV is a free, open-source home for your profile.
If SnapCV is useful to you, a ⭐ helps other people find it.
name.snapcv.me.pdf-parsesnapcv/
├─ src/ # Next.js frontend (app, components, lib)
├─ backend/ # Node/Express service: résumé PDF → structured JSON (see backend/README.md)
├─ .env.example # frontend env template
└─ README.md
git clone https://github.com/jamaljm/snapcv.git
cd snapcv
Create a Supabase project. From Project Settings → API, copy the project
URL and the anon key.
Auth → Providers → Google: enable Google sign-in.
SQL editor: create the users table (portfolios are public read; owners
write their own row):
create table public.users (
id uuid primary key, -- Supabase auth user id
"userId" uuid, -- auth user id (used by some queries)
"userName" text unique not null, -- the subdomain / slug
"userEmail" text,
"resumeJson" jsonb,
"metaJson" jsonb,
"githubWrap" jsonb,
"updatedAt" timestamptz default now()
);
alter table public.users enable row level security;
create policy "public read" on public.users for select using (true);
create policy "owner insert" on public.users for insert with check (auth.uid() = id);
create policy "owner update" on public.users for update using (auth.uid() = id);
Storage: create two buckets — resume (uploaded PDFs) and snapcv
(portfolio images). Make them public-read for local dev.
cd backend
npm install
cp .env.example .env # set OPENAI_KEY
npm run dev # http://localhost:5000
See backend/README.md for details.
# from the repo root
npm install
cp .env.example .env.local # fill in Supabase + backend URL
npm run dev # http://localhost:3000
Local note: portfolios render by subdomain (
name.snapcv.me). Onlocalhostyou'll see the landing/marketing site; use the editor at/createand/home.
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | yes | Supabase project URL. |
NEXT_PUBLIC_SUPABASE_ANON_KEY | yes | Supabase anon key (client). |
SUPABASE_ANON_KEY | yes | Key used by server-side API routes. |
NEXT_PUBLIC_API_BASE_URL | yes | Base URL for the app's own /api routes. |
NEXT_PUBLIC_BACKEND | yes | URL of the résumé-extraction backend (/backend). |
GITHUB_TOKEN | no | Server-side token for the GitHub Wrapped feature. |
next build + next lint should pass).staging.Bugs and ideas: open an issue.
AGPL-3.0. Network use is distribution — if you run a modified version as a service, you must make your source available under the same license.
Questions? Email jamalvga2002@gmail.com.