AI-Assisted Job Search — In Progress
A Next.js application that integrates Claude AI for resume tailoring and job fit evaluation. An exploration of what happens when you treat AI as a tool inside a real product instead of a standalone chat interface.
Platform focus
Problem
What Needed To Change
- Job applications are repetitive: copy job description, manually tailor resume, write cover letter, repeat.
- Fit evaluation is subjective and time-consuming when done manually for every posting.
- Generic LLM responses hallucinate skills and exaggerate experience unless explicitly constrained.
- AI-as-a-chat-interface does not integrate cleanly into a product workflow with state, persistence, and authentication.
Engineering Goal
What The System Needed To Prove
Build a working job search product where Claude handles tailoring and evaluation while the user stays in control of the final output and application decisions.
Audience
Who The Work Serves
Job seekers
Need faster, more consistent resume tailoring without sacrificing accuracy.
Engineers exploring AI integration
Need evidence that LLM APIs can be wrapped into product workflows with structured outputs and accuracy constraints.
System
System Shape
Claude Integration Layer
API routes wrapping the Anthropic SDK with system prompts that enforce accuracy constraints, writing style rules, and structured output formats.
Resume Tailoring
Given a master CV and job description, Claude rewrites the resume with bullet reordering, keyword alignment, and explicit anti-hallucination rules.
Job Fit Evaluation
Claude scores jobs as high, medium, low, or skip against the candidate profile and preferences, returning structured JSON.
Authentication
NextAuth.js with Google OAuth, Prisma adapter, protected routes via middleware, and returnTo URL preservation.
State Management
Zustand with persistence middleware for client-side job and profile data. Prisma and SQLite for authenticated user data and search run history.
Architecture
Monorepo Shape
jobflow/
app/
page.tsx (landing)
login/ (OAuth flow)
(dashboard)/ (protected routes)
api/
auth/ (NextAuth handlers)
tailor/route.ts (Claude → tailored resume)
cover-letter/ (Claude → cover letter)
evaluate/ (Claude → fit scoring)
lib/
claude.ts (Anthropic SDK + prompts)
auth.ts (NextAuth + Prisma adapter)
store.ts (Zustand + persistence)
domain/
job-search/
orchestrator.ts (multi-source coordination)
prisma/
schema.prisma (User, Session, JobSearchRun)- AI endpoints are standard Next.js API routes — no special runtime, just HTTP and the Anthropic SDK.
- System prompts include explicit accuracy rules to prevent fabrication and scope inflation.
- Two-layer state: Zustand for client persistence, Prisma for authenticated server data.
- The orchestrator skeleton exists for future multi-source job discovery but sources are not yet connected.
Decisions
Architecture Choices
Decision 1
Wrap Claude in API routes, not client-side calls
- Reason
- API keys stay server-side. The client never sees the Anthropic SDK or raw prompts.
- Tradeoff
- Adds a round-trip compared to edge functions.
- Outcome
- Simpler security model. The frontend treats AI as a service endpoint like any other API.
Decision 2
System prompt includes explicit anti-hallucination rules
- Reason
- Resume tailoring fails if Claude invents skills or inflates scope. The prompt enforces only use information explicitly provided.
- Tradeoff
- The prompt is longer and more prescriptive.
- Outcome
- Tailored resumes stay accurate to the source material. The user can trust the output.
Decision 3
Return structured JSON for fit scoring
- Reason
- The UI needs a machine-readable fit score (high, medium, low, skip) and a human-readable explanation.
- Tradeoff
- Requires parsing and validation on the server.
- Outcome
- Clean separation between AI response and UI display. Fit badges render directly from JSON.
Decision 4
Zustand for client state, Prisma for server state
- Reason
- Job data and profile content should survive page refresh (client). Authenticated user records and search history belong in a database (server).
- Tradeoff
- Two persistence layers to maintain.
- Outcome
- Each layer handles what it is good at. No awkward workarounds for authentication or offline-first client state.
Workflows
Key Flows
Resume Tailoring
- 1User adds a job (URL or pasted description)
- 2System auto-evaluates fit via Claude
- 3User requests tailored resume
- 4Claude rewrites resume with job-specific keywords and reordering
- 5User reviews, copies, or downloads the result
Job Fit Evaluation
- 1User pastes job description
- 2Claude scores against profile and preferences
- 3System returns fit (high/medium/low/skip) + notes
- 4User decides whether to pursue the job
Cover Letter Generation
- 1User selects a job with a saved description
- 2Claude generates a cover letter connecting experience to the role
- 3User reviews and edits as needed
Implementation
System Notes
- Built with shadcn/ui components for consistent form controls, cards, and badges.
- Tailwind CSS for layout and spacing, following the Labs design token scale where applicable.
- Fit scores display as colored badges: green (high), yellow (medium), gray (low), red (skip).
- Markdown output from Claude is rendered with react-markdown for clean formatting.
Scope
V1 Scope Control
Included in V1
- Resume tailoring via Claude API
- Cover letter generation
- Job fit evaluation with structured scoring
- Google OAuth authentication
- Protected routes with middleware
- Client-side state persistence (Zustand)
- Database schema for users, sessions, search runs
- Orchestrator skeleton for future job discovery
Intentionally deferred
These were kept out of V1 to protect learning speed and reduce integration risk.
- Automated job board scraping (planned, not built)
- PDF export
- Email integration
- Interview scheduling
- Company research automation
- Real-time job alerts
Roadmap
From Support To Automation
V1 Shipped
- Claude API integration for tailoring, cover letters, fit scoring
- Google OAuth and protected routes
- Manual job adding with auto-evaluation
- Zustand persistence for profile and job data
- Database schema for authenticated data
V2 Discovery
- Connect job source adapters (LinkedIn, Greenhouse, Lever)
- Orchestrator coordination across sources
- Deduplication and incremental search runs
- SSE progress updates for long searches
V3 Polish
- PDF export for tailored resumes
- Token usage tracking and caching
- Semantic job matching with embeddings
- Interview prep module
Impact
What Became Clearer
- Demonstrates that LLM APIs can be integrated into product workflows, not just chat interfaces.
- Shows prompt engineering with accuracy constraints — the opposite of letting Claude freestyle.
- Creates a usable tool while exploring the engineering patterns underneath.
- Documents the gap between AI can do this and this is a shipped product.
Reflection
What I Learned
AI integration is mostly plumbing: API routes, error handling, structured outputs, and prompt iteration.
The hard part is not calling Claude — it is defining what Claude should and should not do, then enforcing it in the prompt.
Human-in-the-loop is not a limitation; it is the product design. The user reviews everything before it leaves the app.
Next, I would add caching to reduce API costs, connect real job sources, and build better feedback loops when Claude output misses the mark.
Explore JobFlow
