Building CareerTrack: Crafting an AI-Powered Job Tracker with Next.js 15, React 19 & Prisma Banner Background
Blog

Building CareerTrack: Crafting an AI-Powered Job Tracker with Next.js 15, React 19 & Prisma

A technical deep-dive into architecting CareerTrack: full-stack Kanban state synchronization, multi-provider AI integration (Gemini, Claude, OpenAI), and type-safe database schemas with Prisma.

Ali Hasan Muzahid
Ali Hasan Muzahid
14 min read

The Vision: Beyond Spreadsheets for Job Hunting

Tracking dozens of job applications across static spreadsheets, notes, and emails quickly deteriorates into chaos. When I built CareerTrack, my goal was to engineer a high-performance full-stack workflow system combining interactive Kanban pipelines, resume versioning, interview prep banks, and multi-provider AI assistance (OpenAI, Claude, and Gemini).

"Modern web applications aren't just CRUD interfaces with nice CSS. They demand type-safe full-stack pipelines, deterministic data mutation patterns, and sub-100ms UI responsiveness across complex client interactions."

Full-Stack Type Safety

CareerTrack leverages TypeScript end-to-end: from PostgreSQL tables defined in Prisma schema to React Server Actions and optimistic client state hooks.

CareerTrack Hero Pipeline Interface

CareerTrack platform interface: pipeline tracking, AI JD matching, and full-stack application lifecycle management.

Critical Problems Faced & Bottlenecks

1. Cascading SQL Re-indexing on Drag

Using integer order indexes (1, 2, 3) caused dragging an item to the top of a 200-application column to trigger 200 individual SQL UPDATE queries, spiking database CPU.

2. 6-Second Blocking LLM Latency

Standard REST POST requests for job description gap analysis forced users to stare at a frozen spinner for 5 to 7 seconds while the LLM generated complete JSON schemas.

3. Multi-Tenant API Key Security

Allowing users to connect their own OpenAI/Anthropic/Gemini keys required zero-knowledge cryptographic storage to guarantee no credentials could be leaked or logged.

4. Mobile Drag-and-Drop Glitches

Standard HTML5 drag-and-drop failed completely on mobile touch screens, causing cards to get stuck midway and trigger accidental page reloads.

How I Solved Them: Fractional Indexing & AI Streaming

1. O(1) Fractional Order Indexing

I switched order indexes from integer arrays to floating point values: newOrder = (prev.order + next.order) / 2. Dropping a card between items requires only 1 single atomic SQL query regardless of how many thousands of applications exist in the column.

2. Vercel AI SDK Token Streaming (SSE)

I refactored the JD analysis endpoint into a streaming Route Handler using Server-Sent Events. Initial tokens appear in under 280ms, making the AI analysis feel instant and dynamic.

3. AES-256-GCM Secure Key Isolation

Custom user LLM keys are encrypted using symmetric AES-256-GCM keys tied to user Clerk tokens. Decryption occurs strictly in-memory during request execution and is never written to disk logs.

CareerTrack Kanban Pipeline Board

The Kanban board: optimistic status updates, salary benchmarks, and tag filtering with fractional indexing.

Building the Drag-and-Drop Kanban Pipeline

actions/applicationActions.ts | TypeScript
"use server";

import { z } from "zod";
import { prisma } from "@/lib/prisma";
import { auth } from "@clerk/nextjs/server";
import { revalidatePath } from "next/cache";

const UpdateStageSchema = z.object({
  applicationId: z.string().cuid(),
  newStatus: z.enum(["APPLIED", "SCREENING", "INTERVIEWING", "OFFER", "REJECTED"]),
  prevOrder: z.number().optional(),
  nextOrder: z.number().optional(),
});

export async function updateApplicationStage(data: z.infer) {
  const { userId } = await auth();
  if (!userId) throw new Error("Unauthorized");

  const validated = UpdateStageSchema.parse(data);

  // Compute fractional order index to avoid cascading row updates
  let newOrder: number;
  if (validated.prevOrder !== undefined && validated.nextOrder !== undefined) {
    newOrder = (validated.prevOrder + validated.nextOrder) / 2;
  } else if (validated.prevOrder !== undefined) {
    newOrder = validated.prevOrder + 1000;
  } else if (validated.nextOrder !== undefined) {
    newOrder = validated.nextOrder / 2;
  } else {
    newOrder = 1000;
  }

  const updated = await prisma.jobApplication.update({
    where: { id: validated.applicationId, userId },
    data: { status: validated.newStatus, orderIndex: newOrder },
  });

  revalidatePath("/applications");
  return { success: true, item: updated };
}

Multi-Provider AI Assistant Integration

CareerTrack AI Provider Settings

AI provider settings: model selection, custom temperature parameters, and encrypted API key management.

Data Modeling with Prisma and PostgreSQL

The relational schema connects User, JobApplication, InterviewStage, Note, and ResumeSnapshot with composite indexes on [userId, status] for instant sub-5ms filtering across heavy datasets.

New Skills & Production Insights Gained

1. Optimistic UI Mutations

I mastered optimistic state reconciliation in React 19: updating the visual DOM immediately while server actions reconcile asynchronously in the background.

2. End-to-End Type Contracts

Coupling Prisma database schemas directly with Zod validators eliminated an entire class of runtime regressions before code ever hit production.

Building CareerTrack proved that thoughtful full-stack engineering transforms a tedious process into an empowering, lightning-fast experience.

โ€ข OPEN TO WORK โ€ข OPEN TO WORK
star
OPEN TO WORK ยท OPEN TO WORK ยท
wingsLogo

FROM CONCEPT TO CREATION
LET'S MAKE IT HAPPEN!

I'm available for full-time roles & freelance projects.

I thrive on crafting dynamic web applications, and
delivering seamless user experiences.