diff --git a/README.md b/README.md index 913c917..8236340 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # CV Builder -**Paste a job description + your CV. Get a scored evaluation, specific rewrites, and a tailored PDF.** +**Paste your CV and an optional job description. Get a 0–5 evaluation across six dimensions, with a prioritised list of issues and fixes.** -An open source, privacy-first CV builder for tech professionals. Built by the [Tech Immigrants](https://youtube.com/c/TechImmigrants) community. +This is the **first community MVP**: it scores an existing resume, it does not generate, tailor, or rewrite one. An open source, privacy-first CV evaluator for tech professionals. Built by the [Tech Immigrants](https://youtube.com/c/TechImmigrants) community. [![CI](https://github.com/TechImmigrants/cv-builder/actions/workflows/ci.yml/badge.svg)](https://github.com/TechImmigrants/cv-builder/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) @@ -75,9 +75,30 @@ Clone the repo, open [Claude Code](https://claude.com/claude-code) at the root, See [apps/cli/README.md](apps/cli/README.md) for the full guide. -### Web UI (coming soon) +### Web UI (MVP — local only) -A browser-based interface where you paste your CV and JD, get instant feedback, and export a tailored PDF. No sign-up required, no data leaves your browser. +```bash +pnpm dev # boots at http://localhost:3000 +``` + +A browser-based interface where you paste your CV and JD, get instant +feedback, and read the full dimension breakdown. No sign-up, no data leaves +your browser. PDF upload is not supported yet — use `.txt` or `.md`. + +Full guide: [docs/LOCAL_DEMO.md](docs/LOCAL_DEMO.md). + +--- + +## Privacy + +- The web UI runs entirely in your browser. Nothing is sent to a server. +- The CLI reads files locally and prints to stdout. Nothing is uploaded. +- There is no telemetry, no analytics, no cookies. +- Results in the web UI are stored in your browser's `localStorage` only. + +**Do not paste your real CV into GitHub issues.** Issues are public. Before +sharing an example, anonymize it first — see +[docs/FEEDBACK_GUIDE.md](docs/FEEDBACK_GUIDE.md). --- @@ -158,13 +179,17 @@ Currently built-in: ## Roadmap -### v0.1 (Current Sprint) +### v0.1 (Current Sprint — MVP) - [x] Core evaluation engine with 6 dimensions - [x] 8 role archetypes - [x] Universal anti-pattern detection - [x] CLI: basic evaluate command +- [x] Web UI: paste and score screen (local demo) +- [x] Eval harness with golden fixtures +- [x] Localization-ready code structure (no strings in wrong place) +- [x] Privacy model: no telemetry, no upload - [ ] Unit tests for scoring logic -- [ ] Web UI: paste and score screen +- [ ] PDF text extraction ### v0.2 - [ ] LLM-enhanced mode (rewrite suggestions) diff --git a/apps/web-ui/src/app/components/EvaluateForm.tsx b/apps/web-ui/src/app/components/EvaluateForm.tsx index 92fd453..34c0da8 100644 --- a/apps/web-ui/src/app/components/EvaluateForm.tsx +++ b/apps/web-ui/src/app/components/EvaluateForm.tsx @@ -61,7 +61,7 @@ export function EvaluateForm() { /> - setCv(content)} /> + setCv(content)} />
@@ -78,7 +78,7 @@ export function EvaluateForm() { /> - setJd(content)} /> + setJd(content)} />
diff --git a/apps/web-ui/src/app/components/FileUpload.tsx b/apps/web-ui/src/app/components/FileUpload.tsx index 298f2f3..dc0b080 100644 --- a/apps/web-ui/src/app/components/FileUpload.tsx +++ b/apps/web-ui/src/app/components/FileUpload.tsx @@ -3,35 +3,38 @@ import { type DragEvent, useRef, useState } from "react"; interface FileUploadProps { + inputId: string; onContentLoaded: (content: string) => void; } -export function FileUpload({ onContentLoaded }: FileUploadProps) { - const [fileName, setFileName] = useState(""); +export function FileUpload({ inputId, onContentLoaded }: FileUploadProps) { const inputRef = useRef(null); + const [status, setStatus] = useState(""); async function processFile(file: File) { + setStatus(""); const extension = file.name.split(".").pop()?.toLowerCase() || ""; if (extension === "txt" || extension === "md") { try { const text = await file.text(); onContentLoaded(text); - setFileName(file.name); + setStatus(`Loaded ${file.name}`); } catch (error) { console.error("Failed to read file:", error); - alert("Failed to read file. Please try again."); - setFileName(""); + setStatus("Failed to read file. Please try again."); } return; } if (extension === "pdf") { - alert("PDF text extraction is not yet supported. Please use .txt or .md files."); + setStatus( + "PDF text extraction isn't supported yet. Please paste the content or upload a .txt or .md file." + ); return; } - alert("Unsupported file type."); + setStatus("Unsupported file type. Please use .txt or .md."); } async function handleFiles(files: FileList | null) { @@ -65,13 +68,21 @@ export function FileUpload({ onContentLoaded }: FileUploadProps) {

Supports .txt and .md

- {fileName &&

Loaded: {fileName}

} +

+ {status} +

handleFiles(e.target.files)} /> diff --git a/apps/web-ui/src/app/feedback/page.tsx b/apps/web-ui/src/app/feedback/page.tsx new file mode 100644 index 0000000..05665f2 --- /dev/null +++ b/apps/web-ui/src/app/feedback/page.tsx @@ -0,0 +1,147 @@ +import Link from "next/link"; +import { Header } from "../components/layout/Header"; + +export default function FeedbackPage() { + return ( +
+
+ +
+

+ Feedback Guide +

+ +

+ Tell us what worked and what didn't. +

+ +

+ This MVP is the first cut. Real-world feedback is the only thing that gets us to + a useful tool. Skim this page before you open an issue so your feedback lands in + the right place. +

+ +
+
+

Where to send feedback

+ +
    +
  • + Open a{" "} + + new GitHub issue + {" "} + with the feedback label. +
  • +
  • + Use the{" "} + + feedback + {" "} + channel in the Tech Immigrants community. +
  • +
  • + If something is broken, use a{" "} + + bug report + {" "} + instead. +
  • +
+
+ +
+

What to include

+ +
    +
  • What you were testing (web UI, CLI, eval harness).
  • +
  • What you expected vs. what happened.
  • +
  • The role or archetype you were aiming for.
  • +
  • Your browser / OS / Node version (for web UI / CLI bugs).
  • +
+
+ +
+

+ ⚠ Privacy: don't paste your real CV +

+ +

+ GitHub issues are public. Before sharing an example,{" "} + anonymize it: +

+ +
    +
  • Replace your name with "Candidate A".
  • +
  • Replace company names with "Company X".
  • +
  • Remove phone, address, and email.
  • +
  • Keep the bullet structure and metrics — that's what we need to see.
  • +
+ +

+ If you accidentally paste a real CV, edit or delete the comment immediately. + We can't un-share what you post on GitHub. +

+
+ +
+

Sample anonymized feedback

+ +
+              {`Browser: Chrome 124 on macOS 14
+What I tried: A 1-page SWE CV against a Python backend JD
+Result: Score 2.1/5
+Surprise: Keyword Match scored 5/5 but Tooling Visibility scored 1/5,
+even though I named every tool in the CV. The two should agree.
+Anonymized snippet:
+  - "Built Candidate A service in Company X serving 50M requests/day"
+  - "Migrated Postgres to a sharded cluster, scaling writes 5x"
+Suggestion: weight Tooling Visibility by exact JD keywords, not just
+archetype keywords.`}
+            
+
+ +
+

Five questions that help

+ +
    +
  1. Was the feedback useful?
  2. +
  3. Was the score understandable?
  4. +
  5. What was missing from the result?
  6. +
  7. Would you trust this for your own CV today?
  8. +
  9. What role or archetype should we support next?
  10. +
+
+
+ +
+ + ← Back to evaluator + + + + Open a feedback issue ↗ + +
+
+
+ ); +} diff --git a/apps/web-ui/src/app/page.tsx b/apps/web-ui/src/app/page.tsx index ad86d88..d9f7b6d 100644 --- a/apps/web-ui/src/app/page.tsx +++ b/apps/web-ui/src/app/page.tsx @@ -1,3 +1,4 @@ +import Link from "next/link"; import { EvaluateForm } from "./components/EvaluateForm"; import { Header } from "./components/layout/Header"; @@ -8,40 +9,64 @@ export default function Home() {
-

CV Builder

+

+ CV Builder · MVP +

+

- Tailor your resume to the role without starting from scratch. + Score your resume against the role before you apply.

-

- Paste a job description, highlight the experience that matters, and shape - a cleaner CV for tech roles in a few quick steps. + +

+ Paste your CV and an optional job description. CV Builder runs six quality + checks — Shipped Evidence, Quantified Impact, Tooling Visibility, ATS + Compatibility, Keyword Match, Public Proof — and shows you what to fix + first. Everything runs in your browser; nothing is uploaded. +

+ +

+ This is a community MVP. It scores an existing resume — it does not + generate, tailor, or rewrite one. Feedback and bug reports are welcome at + the bottom of{" "} + + a results page + {" "} + after you evaluate.

-

1. Paste the job post

-

- Start with the exact role description so the app can focus the CV around - the right skills, tools, and experience. +

1. Paste a CV

+ +

+ Plain text or Markdown works best. Most real-world resumes can be pasted + directly from your editor.

-

2. Shape the story

-

- Refine summaries, impact statements, and project bullets to match the role - while keeping your background clear and honest. +

+ 2. Add a job description (optional) +

+ +

+ If you add a JD, the Keyword Match dimension becomes active and you get a + focused score against that specific role.

-

3. Export a focused CV

-

- End with a cleaner resume that is easier to review and more aligned with - the position you are targeting. +

3. Read the result

+ +

+ Overall score, per-dimension bars, the issues worth fixing first, and a + list of strengths you can lean into in the interview.

@@ -49,10 +74,23 @@ export default function Home() {
-

- This starter page is intentionally simple. It gives the web package an - app-specific home screen instead of the default Next.js template and leaves - room for the real workflow to grow from here. +

Privacy

+ +

+ The web app runs entirely in your browser via{" "} + + @cv-builder/core + + . Nothing is sent to a server. Local demo only — no telemetry, no analytics, + no cookies. Do not paste real personal information (phone, address) into + GitHub issues; see{" "} + + feedback guide + + .

diff --git a/apps/web-ui/src/app/results/page.tsx b/apps/web-ui/src/app/results/page.tsx index f4d5663..9d69f99 100644 --- a/apps/web-ui/src/app/results/page.tsx +++ b/apps/web-ui/src/app/results/page.tsx @@ -1,60 +1,234 @@ "use client"; import type { EvaluationResult } from "@cv-builder/core"; +import Link from "next/link"; import { useEffect, useState } from "react"; +import { Header } from "../components/layout/Header"; import { ScoreCard } from "../components/ScoreCard"; import { getEvaluationResult } from "../lib/evaluation-storage"; +const SEVERITY_STYLES = { + critical: "border-red-500 bg-red-50 text-red-900 dark:bg-red-950/40 dark:text-red-200", + major: + "border-amber-500 bg-amber-50 text-amber-900 dark:bg-amber-950/40 dark:text-amber-200", + minor: "border-zinc-400 bg-zinc-50 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-200", +} as const; + export default function ResultsPage() { const [result, setResult] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const data = getEvaluationResult(); - setResult(data as EvaluationResult | null); setLoading(false); }, []); if (loading) { - return
Loading...
; + return ( +
+
+ +
+

Loading your evaluation…

+
+
+ ); } if (!result) { - return
No evaluation found
; + return ( +
+
+ +
+

No evaluation found

+ +

+ It looks like you landed on this page directly. Run a CV through the evaluator + first — your last result is stored in this browser only. +

+ + + ← Back to evaluator + +
+
+ ); } + const issues = result.issues ?? []; + const strengths = result.strengths ?? []; + const dimensions = result.dimensions ?? []; + return ( -
-

Evaluation Results

+
+
- +
+
+
+

Evaluation Results

-
-

Strengths

+ {result.archetype && ( +

+ Detected archetype:{" "} + + {result.archetype.name ?? result.archetype.id ?? "Unknown"} + +

+ )} +
+ + + Evaluate another CV + +
-
    - {result.strengths.map((strength: string) => ( -
  • • {strength}
  • - ))} -
- +
+
+ +
-
-

Dimensions

+
+

ATS readiness

- {result.dimensions.map((dimension) => ( -
-
- {dimension.name} +

+ {result.atsCompatible ? "✓ ATS compatible" : "✗ ATS blockers detected"} +

- - {dimension.score}/{dimension.maxScore} - -
+

+ {result.atsCompatible + ? "No tables, no smart quotes — applicant tracking systems should parse this CV cleanly." + : "Your CV contains formatting (tables or smart quotes) that many ATS tools can't parse. Plain text or Markdown works best."} +

- ))} -
-
+
+ +
+

Dimensions

+ +
+ {dimensions.map((dimension) => { + const ratio = + dimension.maxScore > 0 + ? Math.max(0, Math.min(1, dimension.score / dimension.maxScore)) + : 0; + const widthPct = `${ratio * 100}%`; + + return ( +
+
+ {dimension.name} + + + {dimension.score}/{dimension.maxScore} + +
+ +
+
+
+ + {dimension.feedback && ( +

{dimension.feedback}

+ )} +
+ ); + })} +
+
+ + {issues.length > 0 && ( +
+

+ Issues to fix ({issues.length}) +

+ +
    + {issues.map((issue) => { + const style = + SEVERITY_STYLES[issue.severity as keyof typeof SEVERITY_STYLES] ?? + SEVERITY_STYLES.minor; + + return ( +
  • +
    + {issue.element} + + + {issue.severity} + +
    + +

    {issue.why}

    + +

    + Fix: {issue.fix} +

    +
  • + ); + })} +
+
+ )} + +
+

+ Strengths{strengths.length > 0 && ` (${strengths.length})`} +

+ + {strengths.length === 0 ? ( +

+ No specific strengths detected yet. As your CV adds quantified outcomes, + public links, and shipped work, more bullets will appear here. +

+ ) : ( +
    + {strengths.map((strength: string) => ( +
  • + ✓ {strength} +
  • + ))} +
+ )} +
+ +
+

+ Was this useful? +

+ +

+ This is the first community MVP. Feedback shapes what we build next. See the{" "} + + feedback guide + {" "} + for what to share and how to share it without exposing your CV. +

+
+
+ ); } diff --git a/docs/COMMUNITY_ANNOUNCEMENT.md b/docs/COMMUNITY_ANNOUNCEMENT.md new file mode 100644 index 0000000..f0c4b66 --- /dev/null +++ b/docs/COMMUNITY_ANNOUNCEMENT.md @@ -0,0 +1,157 @@ +# Community Announcement — CV Builder MVP + +> Ready-to-post announcements for the Tech Immigrants community. +> Pick the version that fits the channel. Personalize the closing line. + +--- + +## Short — Persian (Telegram) + +```text +🚀 اولین MVP ابزار CV Builder آماده‌ی تست شد. + +چی هست؟ +ابزاری برای ارزیابی رزومه. رزومه‌ات رو paste می‌کنی (به‌علاوه‌ی آگهی شغلی اختیاری)، +ابزار در ۶ بُعد امتیاز می‌ده و مشکلات مهم رو با راه‌حل نشون می‌ده. + +چی نیست؟ +سازنده‌ی رزومه نیست. رزومه رو نمی‌نویسه و بازنویسی نمی‌کنه. فقط ارزیابی می‌کنه. + +حریم خصوصی: +همه‌چیز توی مرورگر خودت اجرا می‌شه. چیزی به سرور فرستاده نمی‌شه. + +نصب و اجرا: +docs/LOCAL_DEMO.md رو بخون. کل فرایند کمتر از ۵ دقیقه‌ست. + +نظر و فیدبک: +اگه تست کردی، توی issues گیت‌هاب بگو چی دیدی. +⚠️ رزومه‌ی واقعی‌ات رو paste نکن — اول بی‌نامش کن (راهنما: docs/FEEDBACK_GUIDE.md). + +تشکر از همه‌ی کسانی که توی این نسخه مشارکت کردن. +``` + +--- + +## Longer — Persian (Telegram / LinkedIn) + +```text +🎉 اولین نسخه‌ی MVP پروژه‌ی CV Builder آماده‌ی تست توسط جامعه‌ی Tech Immigrants شد. + +📌 این ابزار چی هست؟ +CV Builder یک ارزیاب رایگان و open-source برای رزومه‌ست. +- رزومه‌ات رو paste می‌کنی (متن ساده یا Markdown)، اختیاری هم آگهی شغلی رو اضافه می‌کنی. +- ابزار شش بُعد رو بررسی می‌کنه: + Shipped Evidence، Quantified Impact، Tooling Visibility، ATS Compatibility، + Keyword Match، Public Proof. +- یک امتیاز کلی از ۰ تا ۵ می‌ده، به‌علاوه‌ی لیستی از مشکلات با اولویت بالا و + راه‌حل پیشنهادی برای هرکدوم. +- archetype (نقش) شما رو هم تشخیص می‌ده (Backend Engineer، Frontend Engineer، + AI Product Manager و ...). + +🔐 حریم خصوصی +همه‌چیز توی مرورگر خودت یا روی کامپیوترت اجرا می‌شه. هیچ داده‌ای به سرور +فرستاده نمی‌شه. هیچ telemetry یا analytics نداریم. هیچ cookie نمی‌گذاریم. +نتایج فقط توی localStorage مرورگر ذخیره می‌شن. + +⚠️ این ابزار چی نیست؟ +- سازنده‌ی رزومه نیست — رزومه‌ی موجودت رو ارزیابی می‌کنه، نمی‌سازه. +- بازنویسی یا tailor نمی‌کنه. +- PDF رو پشتیبانی نمی‌کنه (فقط .txt و .md). +- هنوز hosted version نداره. فقط لوکال. + +🚀 چطور تست کنم؟ +کل فرایند کمتر از ۵ دقیقه‌ست: +1. مخزن رو clone کن: github.com/TechImmigrants/cv-builder +2. pnpm install +3. pnpm dev → http://localhost:3000 +راهنمای کامل: docs/LOCAL_DEMO.md + +همچنین می‌تونی CLI رو امتحان کنی: +node packages/cli/dist/cli.js evaluate path/to/cv.md +(بعد از pnpm --filter @cv-builder/cli build) + +📝 فیدبک +از همه‌ی تست‌کننده‌ها می‌خوایم که بعد از امتحان کردن، توی issues گیت‌هاب +بنویسن. این پنج سوال بیشترین کمک رو می‌کنه: +1. آیا فیدبک‌ها مفید بودن؟ +2. آیا امتیاز قابل‌فهم بود؟ +3. چه چیزی از نتیجه کم بود؟ +4. آیا برای رزومه‌ی خودت به این ابزار اعتماد می‌کنی؟ +5. چه نقش / archetype دیگه‌ای باید اضافه کنیم؟ + +⚠️ نکته‌ی مهم: لطفاً رزومه‌ی واقعی‌ات رو توی issues گیت‌هاب paste نکن. +Issues عمومی هستن. اول بی‌نامش کن: +- اسم خودت → "Candidate A" +- اسم شرکت‌ها → "Company X" +- شماره تماس، ایمیل، آدرس → حذف +راهنمای کامل: docs/FEEDBACK_GUIDE.md + +🙏 تشکر +این نسخه حاصل کار جمعی از اعضای جامعه‌ی Tech Immigrants و contributorهای +open-source هست. تشکر ویژه از همه‌ی کسانی که PR، rule، archetype، skill، یا +doc اضافه کردن. مشارکت شما دلیل اینکه این پروژه به اینجا رسیده. + +منتظر فیدبک‌هاتون هستیم. 🙌 +``` + +--- + +## Short — English (Telegram / Discord) + +```text +🚀 First MVP of CV Builder is ready for community testing. + +What it is: an open-source CV evaluator. Paste a CV (and optionally a JD), +get a 0–5 score across six dimensions, plus a prioritised list of issues +with concrete fixes. + +What it isn't: it does not generate, tailor, or rewrite a CV. It scores +what you have. + +Privacy: everything runs in your browser or on your machine. No server, +no telemetry, no analytics, no cookies. + +How to test: +1. Clone github.com/TechImmigrants/cv-builder +2. pnpm install +3. pnpm dev → http://localhost:3000 +Full guide: docs/LOCAL_DEMO.md + +Feedback welcome. Please anonymize your CV before sharing examples in +GitHub issues (see docs/FEEDBACK_GUIDE.md). + +Thanks to every contributor who made this possible. 🙌 +``` + +--- + +## How to personalize + +Replace the closing line with one of: + +- "Sahar از Tech Immigrants" — for a maintainer-signed post +- Your handle + "Tech Immigrants community manager" — for a community-manager post +- Nothing — for an automated bot announcement + +If posting on LinkedIn, add a short paragraph about why this matters to +immigrant tech professionals (English-language CVs are an uneven playing +field; a privacy-first local tool lowers the bar to getting useful feedback +on a CV). + +## Posting checklist + +Before posting: + +- [ ] Confirm `pnpm install && pnpm dev` works on a fresh clone +- [ ] Confirm `pnpm test && pnpm lint && pnpm build` all pass +- [ ] Confirm the home page copy is honest (matches docs/MVP_DEMO_PLAN.md) +- [ ] Confirm the `/feedback` page exists and renders correctly +- [ ] Confirm the privacy note is visible on the home page +- [ ] Pick the announcement length that fits the channel +- [ ] Replace the closing line with your sign-off + +After posting: + +- [ ] Pin the announcement in the channel +- [ ] Link to docs/LOCAL_DEMO.md and docs/FEEDBACK_GUIDE.md +- [ ] Watch the issues feed for the first 24 hours \ No newline at end of file diff --git a/docs/FEEDBACK_GUIDE.md b/docs/FEEDBACK_GUIDE.md new file mode 100644 index 0000000..7657e6b --- /dev/null +++ b/docs/FEEDBACK_GUIDE.md @@ -0,0 +1,119 @@ +# Feedback Guide + +> How to send useful feedback without exposing your CV. + +GitHub issues are public. Before you open one, read this page so your +feedback lands in the right place and doesn't leak personal information. + +## Where to send feedback + +- **General feedback:** open a GitHub issue with the `feedback` label. +- **Bug reports:** use the **Bug report** issue template (it asks the right + questions). +- **Feature requests:** use the **Feature request** issue template. +- **New archetype / role:** use the **New archetype** issue template. +- **New rule:** use the **New rule** issue template. + +Links: + +- New issue: https://github.com/TechImmigrants/cv-builder/issues/new +- Templates: https://github.com/TechImmigrants/cv-builder/issues/new/choose + +## What to include + +For feedback that helps us improve: + +- **What you were testing** (web UI, CLI, eval harness) +- **What you expected vs. what happened** +- **The role or archetype you were aiming for** +- **Your browser / OS / Node version** for web UI / CLI bugs + +For bug reports, the template will ask for additional details (reproduction +steps, expected vs. actual output). + +## What NOT to include + +This is the most important section. **Do not paste your full CV into a GitHub +issue.** + +Why: + +- GitHub issues are public. They show up in search engines. +- Your CV contains your name, your work history, contact details, sometimes + your address and phone number. +- Once posted, the only way to remove it is to edit or delete the comment — + but anyone who saw it can save a copy. +- Your current / past employers can find it. + +## How to anonymize a CV before sharing + +Before you paste anything, do this: + +1. **Replace your name** with `Candidate A`. +2. **Replace company names** with `Company X`, `Company Y`, etc. +3. **Remove phone numbers, addresses, and emails.** +4. **Keep the bullet structure and the metrics.** That's what we need to + see to improve the evaluator. A line like + `"Migrated Postgres to a sharded cluster, scaling writes 5x"` is exactly + what we want — there's no PII in it. + +## Sample anonymized feedback + +```text +Browser: Chrome 124 on macOS 14 +What I tried: A 1-page SWE CV against a Python backend JD +Result: Score 2.1/5 +Surprise: Keyword Match scored 5/5 but Tooling Visibility scored 1/5, +even though I named every tool in the CV. The two should agree. +Anonymized snippet: + - "Built Candidate A service in Company X serving 50M requests/day" + - "Migrated Postgres to a sharded cluster, scaling writes 5x" +Suggestion: weight Tooling Visibility by exact JD keywords, not just +archetype keywords. +``` + +This is the shape we want — concrete observation, anonymized evidence, +actionable suggestion. We can act on this without ever seeing who you are. + +## If you accidentally paste your real CV + +Edit or delete the comment immediately. Then: + +1. Open the comment, click the three-dot menu, choose **Edit** or **Delete**. +2. If a screenshot of the issue has already been taken (e.g. shared in + Discord), let us know in the issue and we'll add a pinned note saying it + should be ignored. + +We can't un-share what gets posted on GitHub, so please anonymize **before** +you post. + +## Five questions that help + +If you only have two minutes, answer these in any order: + +1. Was the feedback useful? +2. Was the score understandable? +3. What was missing from the result? +4. Would you trust this for your own CV today? +5. What role or archetype should we support next? + +The first four help us judge what to invest in next. The fifth helps us +prioritize the archetype backlog. + +## Other ways to give feedback + +- **Tech Immigrants community:** the `#feedback` channel in the Tech Immigrants community. +- **Code review:** if you're a developer, the easiest way to influence the + product is to open a PR. See [CONTRIBUTING.md](../CONTRIBUTING.md). +- **Email:** if GitHub feels too public, ping a maintainer through the + community channels first to find a private path. + +## Privacy promise + +This MVP runs entirely in your browser for the web UI, and entirely on your +machine for the CLI. We have no server-side log of your CV. We have no +telemetry. We have no analytics. + +When a hosted version eventually lands, the privacy posture will be +documented before launch. Don't trust a hosted version that doesn't tell +you what it does with your data. \ No newline at end of file diff --git a/docs/LOCAL_DEMO.md b/docs/LOCAL_DEMO.md new file mode 100644 index 0000000..dd2e9a4 --- /dev/null +++ b/docs/LOCAL_DEMO.md @@ -0,0 +1,272 @@ +# Local Demo Guide + +> For testers who want to run the MVP locally without deploying anything. + +## What this MVP does + +CV Builder is a privacy-first CV evaluator. You give it a resume (and +optionally a job description). It scores the resume across six dimensions and +surfaces the most impactful issues to fix: + +1. **Shipped Evidence** — does the CV show shipped work? +2. **Quantified Impact** — are outcomes measured (numbers, percentages, + scale)? +3. **Tooling Visibility** — are the right tools named for the role? +4. **ATS Compatibility** — will applicant tracking systems parse it cleanly? +5. **Keyword Match** — when a JD is provided, does the CV mention the role's + keywords? +6. **Public Proof** — does the CV link to verifiable work (GitHub, blog, + portfolio)? + +You get: + +- An overall score from 0 to 5 +- A bar for each dimension +- A list of issues with severity, the why, and a concrete fix +- A list of strengths you can lean into in the interview +- An ATS verdict (compatible or blockers detected) +- The detected role archetype (e.g. Backend Engineer, AI Product Manager) + +## What this MVP does NOT do (yet) + +- **It does not generate a CV.** No rewriting, no tailoring, no autofill. +- **It does not parse PDFs.** Paste plain text or Markdown. Upload `.txt` or + `.md` only. +- **It does not have a hosted version.** You run it locally. +- **It does not store anything on a server.** Results live in your browser's + `localStorage` only. +- **It does not cover every role.** Eight archetypes are built-in (Backend + Engineer, AI Engineer, AI Product Manager, Frontend Engineer, QA, DevOps, + Data Engineer, plus a default). If your role isn't there, the detector + falls back to Backend Engineer. + +If any of the above is what you came looking for, see the [Roadmap](../ROADMAP.md) +or open a [feedback issue](https://github.com/TechImmigrants/cv-builder/issues/new). + +## How to install + +### Prerequisites + +- **Node.js 20 or newer** (matches `package.json`) +- **pnpm 9.15 or newer** (`npm install -g pnpm@9.15.0`) +- **git** + +### One-time setup + +```bash +git clone https://github.com/TechImmigrants/cv-builder +cd cv-builder +pnpm install +``` + +`pnpm install` resolves all 9 workspaces and downloads dev dependencies +(Next.js, Vitest, Biome, TypeScript). Takes about 30–60 seconds. + +## How to run the web UI + +```bash +pnpm dev +``` + +This boots Next.js at **http://localhost:3000**. Open it in your browser. + +The home page shows two textareas: + +- **CV** — paste your resume. Plain text or Markdown. +- **Job Description** — optional. Paste the JD here to activate the Keyword + Match dimension. + +Click **Evaluate**. The evaluator runs in your browser (no server roundtrip). +The results page shows your score, dimension breakdown, issues, and +strengths. Click **Evaluate another CV** to start over. + +### File upload + +Below each textarea is a drag-and-drop area. You can drop a `.txt` or `.md` +file and it will load the content into the textarea. PDF upload is not yet +supported — the UI now shows a friendly inline message instead of throwing +an alert. + +## How to run the CLI evaluation + +The CLI is a thin wrapper around the same evaluator. Useful for batch testing +or for piping output into other tools. + +```bash +# Build the CLI once +pnpm --filter @cv-builder/cli build + +# Score a CV +node packages/cli/dist/cli.js evaluate /path/to/your-cv.md + +# Score against a JD +node packages/cli/dist/cli.js evaluate /path/to/your-cv.md --jd /path/to/jd.md + +# Machine-readable JSON output +node packages/cli/dist/cli.js evaluate /path/to/your-cv.md --format json + +# List the archetypes the evaluator can detect +node packages/cli/dist/cli.js archetypes + +# Help +node packages/cli/dist/cli.js help +``` + +The CLI uses the same color-coded scoring the web UI uses. Use `--format json` +to pipe into `jq` or other tools. + +## Sample CV to test with + +The repo ships five golden fixtures under `packages/eval/fixtures/`. To demo +with a known-good CV: + +```bash +cat packages/eval/fixtures/swe-strong/resume.md +``` + +To demo with a weak CV (tables, no metrics): + +```bash +cat packages/eval/fixtures/swe-weak-table/resume.md +``` + +Or copy one into the web UI's CV textarea and click Evaluate. + +## Expected result shape + +The evaluator returns this shape: + +```ts +type EvaluationResult = { + score: number; // 0–5, weighted average across dimensions + dimensions: Array<{ // 6 dimensions, score/maxScore/weight/feedback + name: string; + score: number; // 0–5 + maxScore: number; // always 5 today + weight: number; // archetype-specific, sums to ~1.0 + feedback: string; // optional human-readable note + }>; + strengths: string[]; // bullet points to lean into in the interview + issues: Array<{ // things to fix, severity-ordered + element: string; // the rule name (e.g. "Excessive CV length") + why: string; // 1-sentence reasoning + fix: string; // concrete suggested fix + severity: "critical" | "major" | "minor"; + }>; + archetype: { // detected role, used to weight dimensions + id: string; + name: string; + }; + atsCompatible: boolean; // false if tables or smart quotes detected + rewrites: Rewrite[]; // current evaluator output +}; +``` + +A typical score breakdown looks like: + +```text +CV Score: 2.3/5 +Archetype: Backend Engineer + +Dimensions: + Shipped Evidence █░░░░ 1/5 + Quantified Impact ██░░░ 2/5 + Tooling Visibility ██░░░ 2/5 + ATS Compatibility █████ 5/5 + Keyword Match ███░░ 3/5 + Public Proof ██░░░ 2/5 + +Strengths: + ✓ Uses quantified metrics + ✓ Links to public code + +ATS Compatible: ✓ Yes +``` + +A weak CV scores lower on the same dimensions, and typically shows ATS +incompatibility plus 1–3 issues (e.g. "Excessive CV length", "Inconsistent +date formats", "Outdated tool without modern stack"). + +## Running the test suite + +```bash +pnpm test # all packages +pnpm --filter @cv-builder/core test # 21 evaluator + rules tests +pnpm --filter @cv-builder/eval test # 21 fixture-driven tests +pnpm lint # biome check, expect 0 errors +pnpm build # all 6 packages build +``` + +If all five commands pass, the MVP is healthy. + +## Troubleshooting + +### `pnpm install` complains about lockfile + +The lockfile is `pnpm-lock.yaml`. If you've switched pnpm versions you may +need: + +```bash +pnpm install --no-frozen-lockfile +``` + +Don't commit the regenerated lockfile unless the change is intentional. + +### `pnpm dev` fails with "Cannot find module" + +Run `pnpm install` again. If that doesn't help, `rm -rf node_modules && pnpm install`. + +### Web UI loads but Evaluate returns 0 dimensions or NaN + +Check the browser console. Common causes: + +- The CV is empty (the form rejects empty CVs with an alert) +- The CV has unsupported characters that crash the parser (very rare; + `TextStats` shows char/word counts so you can confirm the textarea is + populated) + +### CLI says "Cannot find module @cv-builder/core" + +The CLI uses workspace dependencies. Make sure you ran `pnpm install` from +the repo root, not from inside `packages/cli/`. + +### Lint reports errors + +Run `pnpm format` to auto-fix formatting. If real lint +errors remain (not formatting), read the message — they're usually about +unused imports or non-null assertions. + +### Build fails on the web UI + +Check that `apps/web-ui/out/` is writable. If you have an old `out/` from a +previous build, delete it. + +## Privacy reminders + +- **The web UI does not upload anything.** Everything runs in your browser. +- **The CLI does not upload anything.** It reads files locally and prints to + stdout. +- **Do not paste your real CV into GitHub issues.** GitHub issues are public. + Anonymize first — see [FEEDBACK_GUIDE.md](FEEDBACK_GUIDE.md). +- **Results in the web UI live in `localStorage`.** Clearing browser data + wipes them. There is no cloud sync. + +## What to test + +If you want to help, here are a few high-value things to try: + +1. **Run the same CV twice with different JDs.** Does the Keyword Match + score change? Does the archetype stay the same? +2. **Try a CV in your native language.** The keyword detector is + English-first; non-English CVs may give odd scores. +3. **Drag a `.txt` of your own CV.** Does the file upload work? Does the + score feel right? +4. **Drag a PDF.** You should see a friendly inline message instead of an + alert. +5. **Refresh the page after evaluating.** Does the result survive a reload? + (It should — it's in `localStorage`.) +6. **Open `/results` directly in the URL bar.** Do you see the empty state + with a back link? + +Report what you find at +https://github.com/TechImmigrants/cv-builder/issues/new \ No newline at end of file