Skip to content

Latest commit

 

History

155 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JobTools — AI resume, cover letter, resignation & interview tools

JobTools — the open-source AI job-search suite

A free, self-hostable alternative to AI resume SaaS like Rezi, Jobscan, Teal, Kickresume, Zety and friends — an AI resume builder + ATS checker, tailored cover letters, resignation letters, interview prep, a live remote-job board, an application tracker, and an always-on AI career copilot. One codebase, your infrastructure, your AI key.

License: MIT PRs welcome React 18 Vite 5 TypeScript Firebase

Features · How it works · Self-hosting · Environment variables · Data model · Contributing

History: JobTools ran in production as the SaaS at jobtools.co from 2024 to 2026. In July 2026 the hosted service was retired and the entire codebase was open-sourced under the MIT license. There is no hosted version anymore — this repo is now a self-host-first project.


Why JobTools instead of a resume SaaS?

Commercial AI resume tools (Rezi, Jobscan, Teal, Kickresume, Zety, Enhancv, resume.io, …) are subscription products: your documents live in their cloud, AI usage is metered by their plans, and the "ATS report" logic is a black box. JobTools is the same product category with the opposite posture:

JobTools (this repo) Typical AI resume SaaS
Price Free, MIT-licensed Subscription / credit packs
Your data Your own Firebase project (+ localStorage) Vendor's cloud
AI Bring your own OpenRouter key, server-side proxy Bundled, metered
AI cost control Built-in per-user rate limits you can tune Plan limits
Scoring & prompts All prompts and heuristics readable in src/services/ Black box
Extensible Fork it, PR it Feature requests

The repo even ships the comparison research: 11 data-driven competitor pages (/compare/jobtools-vs-rezi, -vs-jobscan, …) live in src/data/comparisons.ts.

Features

📄 Documents

  • AI resume builder (/resume-builder) — build from scratch or upload a PDF; AI extracts and structures your experience.
  • ATS checker & deep analysis (/resume-analysis) — section/skill extraction, resume↔job-description match scoring, per-ATS-system compatibility checks, and concrete fixes (src/services/{advancedResumeService,atsOptimizationService,jobDescriptionService}.ts).
  • Resume tailor (/resume-tailor) — rewrites your resume against a pasted job description, with one-click handoff from the job board.
  • Side-by-side resume editor (/resume-editor) and 4 resume templates (/resume-templates).
  • AI cover letter generator (/cover-letter) and resignation letter builder (/resignation-letter).

🔎 Job search suite

  • Live job board (/job-search) — aggregates four keyless public APIs in parallel (Remotive, Arbeitnow, Jobicy, The Muse), dedupes, and scores every job against your profile. No API keys needed.
  • Discover (/discover) — swipe-style yes/no triage of scored roles.
  • Application tracker (/applications) — kanban across saved → applied → interviewing → offer → rejected.
  • Insider connections (/connections) — AI suggests who to reach at a target company (recruiter / hiring manager / future teammate) and drafts the outreach.
  • Insights (/insights) — response rate, match quality, and profile-strength funnel.

🎤 Interview prep

  • AI interview coach (/interview-coach) — mock interviews with written feedback.
  • Role-specific question banks (/interview-questions/:role).

🤖 Career copilot

  • Full-page chat (/copilot) plus a floating widget on every page; shares state across tabs (src/services/jobtools/copilotChat.ts).

📈 Built-in programmatic SEO engine — everything is statically authored and data-driven, useful as a reference even outside job tools:

  • 44 cover-letter role pages (src/data/coverLetterRoles.ts)
  • 27 interview-question role pages (src/data/interviewRoles.ts)
  • 12 resignation-situation pages (src/data/resignationSituations.ts)
  • 11 competitor comparison pages + hub (src/data/comparisons.ts)
  • 21 blog posts with AI-generated editorial illustrations (src/blog/posts.ts)
  • JSON-LD builders (FAQ / SoftwareApplication / Breadcrumb / Organization) in src/lib/seoSchema.ts, per-page meta via src/components/SEO.tsx, sitemap.xml + robots.txt in public/.

Signed-out users can use every tool with deterministic non-AI fallbacks; signing in (Google) unlocks the AI features and cloud sync.

Modern Professional template Creative Designer template Minimal Clean template Tech Innovator template

How it works

flowchart LR
  SPA["React 18 SPA<br/>(Vite, Tailwind)"] -- "Firebase ID token" --> FN["POST /api/ai<br/>Vercel serverless function"]
  FN -- "verify token" --> AUTH[("Firebase Auth<br/>Google sign-in")]
  FN -- "rate limit<br/>20/min · 300/day" --> RL[("Firestore<br/>rateLimits/{uid}")]
  FN -- "chat completion" --> OR["OpenRouter<br/>openrouter/auto"]
  SPA -- "owner-scoped CRUD" --> FS[("Firestore<br/>users/{uid}/…")]
  SPA -- "file uploads" --> ST[("Firebase Storage")]
Loading
  • The browser never holds an AI key. All AI calls go through a single auth-gated serverless function, api/ai.ts: it verifies the caller's Firebase ID token with the Admin SDK, enforces per-user rate limits in a Firestore transaction, then proxies to OpenRouter's openrouter/auto model (override with OPENROUTER_MODEL). Guards: max 40 messages, 24,000 prompt chars, 2,000 output tokens per request.
  • localStorage-first storage. Your work is saved locally first and mirrored best-effort to Firestore under users/{uid}/…; guest work is merged into your account on first sign-in (src/services/jobtools/storage.ts, src/context/AuthContext.tsx).
  • Owner-only security rules. firestore.rules and storage.rules lock every document and file to its owner; the rateLimits collection is server-only.

Tech stack

React 18 + TypeScript 5.5 · Vite 5 · Tailwind CSS 3.4 (+ shadcn-style primitives with Radix, CVA, tailwind-merge) · react-router 6 · framer-motion · lucide-react · pdfjs-dist / react-pdf for PDF parsing & preview · Firebase (Auth, Firestore, Storage) · one Vercel serverless function (@vercel/node) · OpenRouter for AI · Vercel Analytics. No Redux/state library — React context plus useSyncExternalStore over localStorage.

Self-hosting

Prerequisites

  • Node.js 20+
  • A Firebase project (free Spark tier is enough for auth + Firestore)
  • An OpenRouter API key (the only thing that costs money — pay-per-token)
  • Optional: Vercel CLI (npm i -g vercel) to run the AI function locally and to deploy

1. Clone & install

git clone https://github.com/dineshxr/jobtools.git
cd jobtools
npm install

2. Set up Firebase

In the Firebase console:

  1. Create a project and add a Web app (Project settings → Your apps) — this gives you the VITE_FIREBASE_* config values.
  2. Authentication → Sign-in method → Google → Enable (set a support email). Under Settings → Authorized domains add localhost and your production domain.
  3. Firestore Database → Create database (production mode).
  4. Optional — Storage → Get started (needs the Blaze pay-as-you-go plan; only used for document uploads).
  5. Project settings → Service accounts → Generate new private key. From the JSON you need project_id, client_email, and private_key (server-side vars below).

Then deploy the security rules from the repo root:

npx firebase-tools deploy --only firestore:rules,storage --project <your-project-id>

3. Configure environment

cp .env.example .env        # client config (VITE_FIREBASE_*) — safe-to-expose identifiers
cp .env.example .env.local  # server config (OPENROUTER_API_KEY, FIREBASE_* admin vars)

Fill .env with your Firebase web config and .env.local with the server-side values (used by vercel dev). No env file is committed; src/lib/firebase.ts refuses to start without your own config, so a fork can never silently point at someone else's backend.

4. Run

npm run dev      # frontend only — AI calls are disabled (tools fall back to non-AI mode)
vercel dev       # frontend + /api/ai — full AI features locally

npm run build + npm run preview builds and serves the production bundle; npm run lint runs ESLint.

5. Deploy

Deploy with Vercel

Any static host + serverless runtime works, but the repo is Vercel-shaped out of the box (vercel.json provides the SPA fallback rewrite; api/ai.ts is a Vercel function). Set all environment variables from the table below in your Vercel project — including the VITE_* ones, since env files aren't committed and Vite needs them at build time. Remember to add your production domain to Firebase's authorized domains.

Environment variables

Variable Side Required Purpose
VITE_FIREBASE_API_KEY client ✅ Firebase web config (public identifier, not a secret)
VITE_FIREBASE_AUTH_DOMAIN client ✅ Firebase web config
VITE_FIREBASE_PROJECT_ID client ✅ Firebase web config
VITE_FIREBASE_STORAGE_BUCKET client ✅ Firebase web config
VITE_FIREBASE_MESSAGING_SENDER_ID client ✅ Firebase web config
VITE_FIREBASE_APP_ID client ✅ Firebase web config
OPENROUTER_API_KEY server ✅ for AI OpenRouter key used by /api/ai — the only billed secret
FIREBASE_PROJECT_ID server ✅ for AI Admin SDK service account (token verification + rate limits)
FIREBASE_CLIENT_EMAIL server ✅ for AI Admin SDK service account
FIREBASE_PRIVATE_KEY server ✅ for AI Admin SDK private key — keep the quotes and \n escapes
OPENROUTER_MODEL server optional Model override; defaults to openrouter/auto
SITE_URL server optional Sent to OpenRouter as HTTP-Referer attribution

Server variables must never be prefixed with VITE_ — that would bake them into the public bundle.

Data model & security

All user data is namespaced under the signed-in user:

Firestore path Used by
users/{uid}/resumes/{id} resume builder / editor
users/{uid}/coverLetters/{id} cover letter generator
users/{uid}/resignationLetters/{id} resignation builder
users/{uid}/documents/{id} document uploads (files in Storage at users/{uid}/documents/…)
users/{uid}/applications/{id} application tracker
users/{uid}/profile/main, users/{uid}/settings/main job-seeker profile & preferences
rateLimits/{uid} AI rate limiting — server-only (clients denied by rules)

Cost controls for self-hosters: /api/ai enforces 20 requests/min and 300/day per user (constants at the top of api/ai.ts), caps prompt size and output tokens, and requires sign-in — so anonymous traffic can never spend your OpenRouter credits. Note that the rate limiter fails open if Firestore is unreachable (a deliberate availability trade-off — tighten it if you need a hard guarantee).

Project structure

api/ai.ts               # the single serverless function: auth-gated AI proxy
src/
  App.tsx               # all routes
  pages/                # 30+ route components (tools, SEO families, marketing)
  components/           # shared UI (landing/, jobtools/ shell & copilot, ui/ primitives)
  services/             # domain logic: resume/ATS/cover-letter/JD analysis + AI calls
    jobtools/           # job board, tracker, profile, match scoring, copilot state
  data/                 # programmatic SEO content (roles, situations, comparisons)
  blog/posts.ts         # 21 posts, inline HTML
  lib/                  # firebase.ts, aiClient.ts, seoSchema.ts, utils.ts
  context/AuthContext.tsx
public/                 # static assets, sitemap.xml, robots.txt, templates, blog art
firestore.rules · storage.rules · firebase.json · vercel.json
GOAL.md                 # product philosophy: every page must produce a usable artifact

Forking notes

A few things are branded for the original deployment and worth changing in a fork:

  • src/lib/seoSchema.ts (SITE_URL), public/sitemap.xml, public/robots.txt, and the IndexNow key file in public/ — regenerate for your domain.
  • support@jobtools.co appears on the contact/privacy/terms pages.
  • src/data/comparisons.ts and several blog posts make comparative claims about commercial products as of 2026 — review before republishing them on your own domain.

Known gaps

Honest list of what's missing: no test suite or CI yet; the resume editor's undo/redo/save toolbar has stub TODOs (src/components/ResumeEditor.tsx); src/services/openaiService.ts is legacy-named (it talks to OpenRouter); a couple of unrouted legacy pages linger in src/pages/. PRs for any of these are very welcome.

Contributing

Issues and PRs are welcome. Before opening a PR:

  1. Read GOAL.md — the product bar: every page must be reachable, produce a real artifact, persist work, and hand off to a next step.
  2. npm run lint must pass.
  3. Keep the security posture: AI keys stay server-side, user data stays owner-scoped.

Credits & license

Built by Dinesh Puppala as jobtools.co; open-sourced in July 2026. Blog and site illustrations were AI-generated via OpenRouter (prompts and generation records preserved in public/images/*/manifest.jsonl).

Rezi, Jobscan, Teal, Kickresume, Zety, Enhancv, resume.io and other product names are trademarks of their respective owners; JobTools is not affiliated with or endorsed by any of them.

MIT — do whatever helps someone land a job.

About

Free, open-source AI job-search suite — AI resume builder, ATS checker, cover letters, resignation letters, interview prep, job board & application tracker. Self-hosted alternative to Rezi, Jobscan & co.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages