
AI-powered job hunt platform with ATS resume scoring, job-fit analysis, tailored resume generation, and automated job application across 12 job platforms — with both web and CLI interfaces.
Domain Knowledge
What problem this project solves
Job hunting is a system design problem: resume parsing, job discovery, fit scoring, resume tailoring, and application submission form a pipeline where each stage must handle failures gracefully. CareerNorth treats this as a multi-stage pipeline with idempotent operations, so a crash at any stage doesn't lose progress. The dual interface (web + CLI) makes the same engine accessible from different workflows — a developer might use the CLI for batch applications while a job seeker prefers the web dashboard.
Architecture
How the system is structured
The system uses a pipeline architecture with clear stage boundaries: Parse Resume → Score ATS → Match Job → Tailor Resume → Apply. Each stage is independently executable and idempotent. The core engine is shared between the Next.js web app and the CLI tool. Resume parsing uses pdfjs-dist for PDF extraction. ATS scoring analyzes keywords, sections, contact info, action verbs, quantification, bullet structure, and formatting. Job discovery uses Playwright to automate browser sessions across 12 platforms (LinkedIn, Naukri, Indeed, Cutshort, Wellfound, etc.). The LLM integration layer supports OpenRouter, OpenAI, and Anthropic for genuine AI resume rewriting — with a deterministic fallback when no LLM key is provided.
Data Model
Schema design and data flow
The data layer uses Prisma with PostgreSQL for persistent storage (Users, Resumes, Jobs, Applications, Activity logs) with localStorage as the default lightweight backend. Each resume stores parsed sections, ATS scores per job match, and tailored versions. Applications track platform, status, tailored resume snapshot, and timestamp. The model supports per-account history and batch operation tracking.
Key Challenges
Hardest problems encountered
The hardest challenge was making browser automation reliable across 12 different job platforms, each with unique DOM structures, CAPTCHA systems, and anti-bot measures. Solved with platform-specific selectors, session persistence, and configurable approval gates. Resume tailoring required balancing ATS optimization with readability — aggressive keyword stuffing improves scores but produces unnatural resumes. The solution uses weighted scoring with configurable thresholds per job fit level.
Scaling Strategy
How the system grows
The pipeline is embarrassingly parallel — each job application is independent and can be batched. The CLI uses PM2 for process management. The web app leverages server-side rendering for the dashboard and API routes for the pipeline. Job discovery results are cached to avoid re-scanning platforms. Application rate limiting per platform prevents account restrictions.
Security
Defense-in-depth approach
Platform credentials are never stored — Playwright uses persistent browser profiles with manual login. LLM API keys are environment-only. Application data is account-scoped with row-level isolation. The system gates applications behind an ATS threshold (default 80) to prevent low-quality submissions that could flag accounts.
Failure Handling
Resilience and recovery
Each pipeline stage has retry logic with exponential backoff. Failed applications are logged with full context (platform, error, input state) for manual review. Browser automation handles CAPTCHAs by pausing for human intervention. Session expiration triggers re-authentication prompts rather than silent failures.
Observability
Monitoring and debugging
Application history provides per-platform success rates, response rates, and timing. ATS score distributions help optimize resume strategies. Pipeline stage timing identifies bottlenecks. Structured logging with correlation IDs connects resume parsing, scoring, and application outcomes.
Trade-offs
Engineering decisions and alternatives
Prisma was chosen over raw SQL for type safety and migration management. Playwright was chosen over Puppeteer for better cross-browser support and built-in waiting mechanisms. Shared engine architecture (web + CLI) was chosen over separate implementations to maintain scoring consistency. PostgreSQL over SQLite for production reliability and concurrent access.
Architecture Decisions
Key choices and what was rejected
Senior-Level Topics
Concepts this project explores