Building GetReadyForWork: A Job Search Tracker That Actually Helps
The Job Search Problem
Job hunting is chaos. You apply to dozens of companies, lose track of where you are in each process, send the wrong CV version, forget to follow up. Spreadsheets work until they don't.
I wanted a tool that would:
- Track applications through every stage
- Manage multiple CV versions tailored to different roles
- Show me what's actually working (response rates, interview conversion)
- Not feel like another chore
So I built GetReadyForWork.
Starting Fresh with Next.js 16
This project was my excuse to try the bleeding edge: Next.js 16, React 19, Prisma 7, Tailwind CSS 4. Everything latest.
The first commit was simple: "feat: initial commit - job search tracker app".
From there, the architecture emerged:
src/
├── app/
│ ├── (auth)/ # Login, signup, password reset
│ ├── (main)/ # Dashboard, applications, CV editor
│ └── api/ # API routes with auth guards
├── components/
│ ├── ui/ # Design system components
│ └── kanban/ # Drag-and-drop board
└── lib/
├── prisma.ts # Database client
└── supabase/ # Auth utilities
Route groups ((auth), (main)) kept the code organized. Protected routes redirect unauthenticated users automatically via middleware.
Authentication: Supabase + Prisma
I chose Supabase for auth because I didn't want to build password reset flows, email verification, and OAuth from scratch again. But I needed my own database schema for application data.
The solution: Supabase handles auth, Prisma handles everything else. A sync function bridges them:
export async function getAuthenticatedUser() {
const supabase = await createClient();
const { data: { user: authUser } } = await supabase.auth.getUser();
if (!authUser) {
return { error: NextResponse.json({ error: "Unauthorized" }, { status: 401 }) };
}
// Sync to Prisma on each request
const user = await prisma.user.upsert({
where: { id: authUser.id },
update: { email: authUser.email },
create: { id: authUser.id, email: authUser.email! }
});
return { user };
}
OAuth came next: GitHub and Google. The tricky part was account merging—what happens when someone signs up with email, then later tries to log in with Google using the same email? Supabase handles this gracefully, and my sync function ensures the Prisma user stays consistent.
The Kanban Board
A job tracker needs a visual pipeline. I built a Kanban board using dnd-kit:
const columns = [
{ id: 'APPLIED', label: 'Applied' },
{ id: 'SCREENING', label: 'Screening' },
{ id: 'TECHNICAL', label: 'Technical' },
{ id: 'FINAL', label: 'Final Round' },
{ id: 'OFFER', label: 'Offer' },
{ id: 'REJECTED', label: 'Rejected' }
];
Dragging a card between columns triggers an optimistic update—the UI moves immediately, then syncs with the server. If the API call fails, the card snaps back.
The status colors are defined centrally so they're consistent everywhere:
export const STATUS_CONFIG = {
APPLIED: { color: 'indigo', label: 'Applied' },
SCREENING: { color: 'sky', label: 'Screening' },
TECHNICAL: { color: 'amber', label: 'Technical' },
OFFER: { color: 'emerald', label: 'Offer' },
REJECTED: { color: 'slate', label: 'Rejected' }
};
CV Management: The Core Feature
Here's where GetReadyForWork differs from basic trackers. Most tools let you upload one CV. But job hunting requires tailored CVs—one for frontend roles, another for full-stack, maybe a third emphasizing leadership experience.
I built a full CV editor:
- Profile - Your master data (experience, education, skills)
- CV Versions - Role-specific selections from your profile
- PDF Export - ATS-compatible templates via Puppeteer
// CV Version schema
model CVVersion {
id String @id @default(uuid())
name String // "Frontend Developer CV"
targetRole String?
summary String?
skills Json // Selected from profile
experience Json // Selected/reordered from profile
education Json
applications Application[] // Track which applications used this CV
}
The killer feature: CV performance tracking. I can see which CV version gets the most responses and interviews. Data-driven job hunting.
PDF Import: Parsing Existing CVs
Users already have CVs. Making them re-enter everything would be friction. So I added PDF import.
This was harder than expected. PDFs aren't structured data—they're visual documents. I used unpdf to extract text, then compromise (an NLP library) to identify sections:
async function parseCV(pdfBuffer: Buffer) {
const text = await extractTextFromPDF(pdfBuffer);
// Use NLP to identify sections
const doc = nlp(text);
return {
experience: extractWorkExperience(doc),
education: extractEducation(doc),
skills: extractSkills(doc)
};
}
It's not perfect—PDFs vary wildly in structure—but it gets 80% of the data right, which is enough to save users significant time.
The Dashboard: Making Data Useful
Raw data isn't helpful. The dashboard synthesizes everything into actionable insights:
- Pipeline funnel - How many applications at each stage
- Conversion rates - Applied → Response → Interview → Offer
- Activity trends - Weekly application volume
- Follow-up reminders - Applications that need attention
- Stale alerts - Applications stuck in limbo
// Dashboard metrics calculation
const metrics = {
totalApplications: applications.length,
responseRate: (responded / total) * 100,
interviewRate: (interviewed / responded) * 100,
offerRate: (offers / interviewed) * 100
};
The CV performance widget shows which versions are working. If my "Frontend Focus" CV has a 40% response rate but "Full-Stack Generalist" is at 15%, that's a clear signal.
Design System: Dark Mode First
I built the design system dark-mode-first. Most developers work in dark mode, and job hunting often happens late at night. Light mode exists, but dark is the default.
The color palette:
- Primary: Indigo (professional, calm)
- Success: Emerald (offers, positive)
- Warning: Amber (follow-ups needed)
- Danger: Rose (rejected, be careful)
Every component respects the theme:
<Card className="bg-white dark:bg-slate-800 border-slate-200 dark:border-slate-700">
<StatusBadge status={application.status} />
</Card>
50 Commits Later
In 50 commits, GetReadyForWork went from empty repo to:
- Full auth with OAuth
- Kanban board with drag-and-drop
- Complete CV editor and PDF export
- PDF import with NLP parsing
- Analytics dashboard
- Dark mode throughout
- PostHog analytics integration
What's Next
The roadmap includes:
- Email reminders for follow-ups
- Interview prep notes with AI suggestions
- Salary negotiation tracker
- Chrome extension to auto-capture job postings
Lessons Learned
- Next.js 16 is stable - Even bleeding-edge versions work fine for new projects
- Supabase + Prisma is a great combo - Auth handled, data yours
- PDF parsing is imperfect - But 80% accuracy beats manual entry
- Dark mode first - Easier than retrofitting
- Track everything - Can't improve what you don't measure
Currently job hunting? I'd love feedback on GetReadyForWork. Reach out on GitHub or LinkedIn.