What I Applied
A personal applicant-tracking and AI-assisted career prep web app: one profile, one record per application, and AI where it speeds up grounded prep—whether that is JD-specific materials or speculative outreach when no posting exists—without replacing your judgment.
Pipeline chaos for one job seeker
Job seekers juggle many employers, different job descriptions, and interview stages across spreadsheets, notes apps, and email. That leads to:
- Lost context — "What did I say I applied for?" and "Where is that posting's JD?" are hard to answer weeks later.
- Weak reuse — each new application restarts cover-letter and prep work from scratch instead of reusing a structured profile.
- Forgotten follow-ups — opportunities go cold because there is no simple signal when to nudge a recruiter.
Corporate ATS tools are built for hiring teams, not for one candidate managing their own pipeline. I wanted a small, honest workspace: one profile, one place per application, and AI where it speeds up grounded prep—whether that is JD-specific materials or speculative outreach when no posting exists—without replacing judgment.
System of record + selective AI
Signed-in users can:
- Maintain a master profile — structured experience, education, skills, and an "About me" narrative; optional PDF-assisted extraction (text only — the file is not stored).
- Log each application — company (deduplicated by name), role, posting URL, optional full job description, or "No JD available" for speculative outreach (for example email without a posting). Status includes Exploring as the default for new roles, plus pipeline states such as Applied, Screening, Being ghosted, Offer, Rejected, Withdrawn.
- Track a per-job pipeline — stages (type, format, schedule, notes, links, status) as a lightweight timeline. Schedule overlap hints (same user, about one-hour blocks on
SCHEDULEDstages) show as informational warnings on list and detail views — they never block saves. - Generate tailored assets per job — one Gemini call returns a cover letter, elevator pitch, anticipated interview questions (with reasoning), strategic focus points, and a role match score (0–10) with honest justification, validated with Zod. With a saved JD, copy aligns to the posting; without a JD, the same JSON shape supports email-style inquiry and conservative fit versus title, company context, and resume only — no invented requirements. Assets live in
AiAsset; match score and rationale are copied toJobfor fast list and detail display. The coach prompt stresses humble, evidenced output — no fabricated credentials. - Job search direction (dashboard) — a gated questionnaire (profile or long About me required) captures industries, target roles, location and work preferences, priorities, optional avoid-list and context, and yes or no signals (remote, company size, geography, mission, relocation, visa, comp discussion). One Gemini call returns a narrative summary and at least ten company suggestions, stored in
CareerDirectionInsight. Rate limits (cooldown plus rolling 24-hour cap via request logs) protect the API; users can regenerate within those limits. - Get gentle operational nudges — jobs with no activity for seven days surface a non-AI follow-up email template (copy to clipboard), except while status is Exploring (no follow-up draft). Terminal outcomes (offer, rejected, withdrawn) turn the stale reminder off. Rejected applications get an optional thank-you or feedback-request email template.
Authentication is email and password (bcrypt, NextAuth JWT). Data is scoped per user in PostgreSQL.
Impact (qualitative)
This is a personal portfolio build rather than a shipped product with analytics. The value is in day-to-day clarity, velocity, and disciplined communication — with explicit limits on spend.
Clarity
One system of record for what you applied for — including cases without a saved posting — and what each role asked when a JD exists.
Velocity
Parsing plus structured save reduces retyping; one-shot AI cuts time to a first draft of role-specific or speculative outreach (plus an explicit fit score when enabled). The dashboard job-search-direction flow offers a structured starting point for where to look next.
Discipline
Stale-job reminders and static email templates (follow-up plus post-rejection thank-you) encourage consistent communication without building a mailer.
Cost awareness
Per-job coach: one successful full generation after match metadata exists (API returns 409 if repeated); one extra run is allowed when legacy rows have assets but no match score or justification yet. Retries stay available when generation fails. Job search direction: rate limits (spacing plus a daily-style cap) bound repeat Gemini calls while still allowing intentional regeneration.
Features
Product surface
- Landing page for anonymous visitors; signed-in users go to the dashboard.
- Register and login with protected routes (Next.js
proxy); login includes a password visibility toggle. - Dashboard: snapshot counts, shortcuts, and Job search direction (questionnaire plus stored Gemini report when the profile is ready; rate-limited regeneration).
- Applications CRUD: list (whole row opens detail, match score in the meta line, pipeline schedule warnings), create, detail; company match-or-create by name; default status Exploring; optional JD via No JD available.
- Job detail: inline edit of title, URL, description (or none), No JD toggle, status; pipeline stage CRUD; stage updates bump
updatedAtfor reminder logic; match rationale when present; AI section respects one-generation plus legacy backfill rules; coach adapts when there is no posting text.
Profile, AI, and ops
- Resume editor: load and save profile; PDF upload to parse API, human-in-the-loop edit, transactional save (replaces resume rows, updates
aboutMe). - Personal information: read-only review of stored profile.
- AI career coach: Gemini JSON validated with Zod; persists
AiAssetplusJob.matchScore/Job.matchJustification; static cover-letter fallback when AI fails; clearer API errors for badGEMINI_MODELversus DB drift in development. - Follow-up and rejection helpers: follow-up template and clipboard when eligible; Exploring skips follow-up; Rejected shows a post-rejection thank-you template; terminal statuses suppress stale reminders.
- Responsive UI: mobile-friendly navigation and layouts.
Engineering spotlight
01. Grounded AI with guardrails
Google Gemini is called server-side with a JSON MIME type and single-attempt calls mapped to structured errors (versus open-ended retries). Zod validates payloads before persistence; the prompt favors humble, evidenced copy so the model does not invent credentials. Per-job assets live in AiAsset, with match score and rationale denormalized to Job for list performance. The API enforces one successful full generation once match fields exist (409), with a narrow backfill path for older rows missing match metadata.
02. Privacy-minded resume intake
pdf-parse extracts text only for optional profile bootstrapping; the binary is not stored. Profile updates use a transactional replace of resume-related rows plus aboutMe so partial writes do not leave the profile half-migrated.
03. Scheduling hints and bounded “direction” AI
Overlap detection compares scheduled stage blocks for the same user and surfaces ~one-hour conflicts as informational UI warnings — never blocking saves. The career-direction feature gates on profile richness, then uses request logging for cooldown and rolling 24-hour caps so intentional regeneration stays possible without unbounded Gemini spend across the user base.
Tech stack
Full-stack TypeScript on Next.js App Router, with PostgreSQL as the source of truth and validation at API and AI boundaries.
Framework: Next.js (App Router), React · Language: TypeScript
Database: PostgreSQL (e.g. Neon) · ORM: Prisma 7 with Neon serverless adapter
Auth: NextAuth.js (credentials provider, JWT sessions, bcryptjs)
Validation: Zod (API bodies, AI JSON, resume shapes)
AI: Google Gemini (@google/genai), JSON MIME type, single-attempt calls with structured error mapping.
PDF: pdf-parse (text extraction only) · Styling: Tailwind CSS 4, responsive shell
Future roadmap
Paid tier
Relaxed per-job regenerate rules, higher job-search-direction quotas, optional email send (today: coach 409 when assets and match fields already exist, with one legacy backfill; career direction uses shared rate limits for all users).
Calendar integration
Push JobStage times to Google or Outlook instead of overlap warnings only.
Richer pipeline
Attachments, interviewer names, reminders (email or push) integrated with calendar.
OAuth and export
Google or LinkedIn sign-in alongside credentials; PDF or Markdown export of applications and AI assets for offline backup.
Analytics, accessibility, i18n
Funnel stats (applied to interview to offer) for personal retrospectives; deeper accessibility audit and localized templates.