Skip to content
YKYogesh Kadam
← Back to projects

ApplyVibe — Job Application Tracker

Free-first full-stack SaaS for job seekers — Kanban pipeline, analytics dashboard, smart insights, and Auth.js auth. Built with Next.js 16, Prisma, and Neon PostgreSQL.

8 app pages + 6 API routes11 Kanban stages5 DB models0 TypeScript errors
Next.js 16Auth.js v5PrismaNeon PostgreSQLTailwind CSSRechartsdnd-kit

Architecture flow

FrontendNext.js 16 App Router — server components for dashboard, client hooks for Kanban/Analytics
APINext.js API routes — 6 routes (register, applications CRUD, profile) with Zod validation
InfraNeon PostgreSQL (serverless) + Prisma ORM + Vercel deploy + Auth.js JWT sessions
01

Problem

Job seekers applying to hundreds of roles had no clean, free tool to track applications, visualize their pipeline, or understand what was and wasn't working. Existing tools were paid, overly complex, or just spreadsheets.

Students applying to hundreds of internships and full-time roles need to track stage progression, follow-up deadlines, and which sources are actually converting — not just a static list of companies. Notion templates and spreadsheets don't surface patterns or send reminders.

02

Solution

Built a purpose-built Next.js 16 full-stack app with server components, credentials auth, Prisma ORM, Neon PostgreSQL, and a full analytics + Kanban layer — all on the free tier, self-hostable, open-source.

03

Architecture

Frontend: Next.js 16 App Router — server components for dashboard, client hooks for Kanban/Analytics

Backend: Next.js API routes — 6 routes (register, applications CRUD, profile) with Zod validation

Infra: Neon PostgreSQL (serverless) + Prisma ORM + Vercel deploy + Auth.js JWT sessions

Browser │ ├── proxy.ts (Next.js 16 Middleware — JWT check → redirect) │ ├── App Routes │ ├── / Landing page (static) │ ├── /login /signup Auth.js credentials │ ├── /dashboard Server Component → DB fetch → DashboardClient │ ├── /applications Client Component → useApplications hook │ ├── /kanban Client Component → dnd-kit drag/drop │ ├── /analytics Client Component → Recharts │ └── /settings Client Component → profile form │ ├── API Routes │ ├── POST /api/register │ ├── GET /api/applications │ ├── POST /api/applications │ ├── PATCH /api/applications/[id] │ ├── DELETE /api/applications/[id] │ ├── GET /api/profile │ └── PATCH /api/profile │ └── Neon PostgreSQL (via Prisma ORM) ├── User (auth + profile) ├── Application (all job data — fully wired) ├── ApplicationEvent (stage history — schema ready) ├── Reflection (interview notes — schema ready) └── Reminder (follow-up alerts — schema ready)
04

Key Features

  • Auth.js v5 credentials auth with bcrypt + JWT + proxy.ts route protection
  • Full application CRUD: company, role, source, stage, salary, visa, deadlines, recruiter info
  • 11-stage dnd-kit Kanban board with live API sync on drag
  • Analytics: funnel chart, weekly trend, source performance, KPI cards
  • Smart Insights engine — rule-based analysis surfacing actionable patterns
  • Settings: profile form, theme switcher (light/dark/system) via next-themes
05

Authentication System

Auth is fully custom — no third-party identity providers, no vendor lock-in. Users sign up with name, email, and password (bcrypt 12 rounds). Auth.js v5 issues a JWT session on successful login.

Route protection runs in proxy.ts (Next.js 16 Middleware) — every request to /dashboard, /kanban, /analytics, and /settings is checked at the edge — unauthenticated users are redirected to /login before the page renders.

The PrismaAdapter is already wired to the Auth.js config — adding OAuth providers (GitHub, Google) in the future requires only provider configuration, not a schema change.

06

Kanban Board

The Kanban board spans 11 columns: Saved → Applied → OA → Recruiter Screen → Interview 1 → Interview 2 → Final Round → Offer → Rejected → Ghosted → Withdrawn.

Built with dnd-kit using a PointerSensor with an 8px activation threshold. When a card is dropped, a PATCH /api/applications/[id] call fires immediately — UI updates optimistically so there's no visible lag.

07

Analytics Dashboard

The dashboard is a server component — data is fetched at request time from Neon PostgreSQL via Prisma, so the initial render always shows fresh data with no client loading flash.

  • 5 KPI cards — total applications, interviews, offers, rejections, response rate
  • 7-day activity area chart — applications submitted per day
  • Pipeline distribution donut — proportion of applications at each stage
  • Source performance bars — which job board produces the best response rate
  • Smart Insights engine — rule-based analysis: low response rate warnings, overdue follow-ups, OA bottleneck detection
08

Challenges & Decisions

1.Next.js 16 renamed middleware.ts → proxy.ts

Problem

Route protection was silently failing — requests showed 0ms response time and a deprecation warning appeared: "middleware file convention is deprecated."

Fix

Renamed to proxy.ts and changed to export default (named exports also break in this convention).

2.Turbopack crashing in dev

Problem

npm run dev crashed with FATAL: An unexpected Turbopack error every few requests.

Fix

Added --webpack flag to the dev script. Next.js 16 enables Turbopack by default; --webpack forces stable Webpack for local dev only. Production builds unaffected.

3.Prisma generate failing on Vercel during npm install

Problem

Three root causes stacked: no postinstall script, Prisma's env() throwing before env vars were injected, then old commits being deployed.

Fix

Removed postinstall entirely. Changed prisma.config.ts to use process.env.DATABASE_URL ?? "postgresql://localhost/placeholder" — prisma generate doesn't connect to the DB so a fallback URL is safe.

4.Analytics funnel showing wrong counts

Problem

The stageOrder array only had 5 stages — indexOf() returned -1 for interview_2, final_round, rejected, ghosted, withdrawn, making those applications invisible.

Fix

Rewrote funnel logic with 7 pipeline stages and explicit handling of terminal stages — rejected/ghosted/withdrawn count in the 'applied' bucket since stage history isn't stored yet.

5.PATCH API had no validation

Problem

The PATCH route built updateData from raw request body — any string could be set as currentStage (breaking DB enums), and an empty body produced a 500 from Prisma.

Fix

Added applicationSchema.partial() Zod validation at the top of PATCH. Empty updateData returns 400. All fields validated against proper enums before touching the DB.

6.dnd-kit DragOverlay duplicate ID bug

Problem

DragOverlay rendered KanbanCard which called useDraggable({ id: app.id }) — two components shared the same dnd-kit ID, causing flaky drag behavior and console warnings.

Fix

Split into KanbanCardContent (pure JSX, no hooks) and KanbanCardOverlay (wraps content, no useDraggable). The draggable card registers the ID; the overlay is a visual clone only.

09

Design Note

Forest green palette (#245501 → #aad576) to feel calm and growth-oriented — opposite of the anxiety that job hunting usually triggers. snake_case throughout frontend types with explicit dbToApp() mapping from Prisma's camelCase.

Data models use snake_case throughout frontend types (company_name, current_stage) with an explicit dbToApp() mapping from Prisma's camelCase.

10

Impact

  • 0 TypeScript errors across the full codebase — strict mode throughout.
  • Auth secured with bcrypt 12 rounds + JWT sessions + middleware route protection on all app pages.
  • 4 critical + 4 high + 6 medium bugs fixed during development — all documented with root cause and decision.
  • ~12s clean build on Vercel — server components keep dashboard data fresh at request time, no client loading flash.
  • Analytics funnel correctly handles all 11 stages including terminal states (rejected/ghosted/withdrawn).

What I'd improve next

senior signal
  • P0Stage history: Write to ApplicationEvent on every Kanban drag. Schema already exists.
  • P0Rate limiting: Upstash Redis or Vercel Edge Config on /api/register.
  • P1Reflections + Reminders: Schema already exists, just needs UI.
  • P1React Query / SWR: Replace manual useApplications hook with a proper cache layer.
  • P2OAuth: GitHub and Google — PrismaAdapter already wired, just needs provider config.
  • P2CSV export + Prisma enums for currentStage/source.
Open to work · May 2026
Let's Talk →