Skip to main content
Projects

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

Next.js 14TypeScriptClaude APIPrompt EngineeringNextAuth.jsPrismaProduct Engineering

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

  1. 1User adds a job (URL or pasted description)
  2. 2System auto-evaluates fit via Claude
  3. 3User requests tailored resume
  4. 4Claude rewrites resume with job-specific keywords and reordering
  5. 5User reviews, copies, or downloads the result

Job Fit Evaluation

  1. 1User pastes job description
  2. 2Claude scores against profile and preferences
  3. 3System returns fit (high/medium/low/skip) + notes
  4. 4User decides whether to pursue the job

Cover Letter Generation

  1. 1User selects a job with a saved description
  2. 2Claude generates a cover letter connecting experience to the role
  3. 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

Platform Links