Jobjigsaw is an AI-powered job application and resume customization platform that helps users tailor their resumes for specific job opportunities. The platform analyzes job descriptions, matches them with user skills, and generates optimized resumes using advanced AI models.
Before you begin, ensure you have:
- Node.js (v18+) and npm
- Docker (for local development)
- Cloudflare CLI (
wrangler) for deployment - API Keys (see Environment Setup section)
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Next.js │ │ Cloudflare │ │ AI Services │
│ Frontend │────│ Workers │────│ OpenAI/Gemini │
│ │ │ Backend │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
┌─────────────────┐
│ Cloudflare D1 │
│ Database │
└─────────────────┘
Backend (/backend/)
- Runtime: Cloudflare Workers
- Framework: Hono.js for HTTP routing
- Database: Cloudflare D1 (SQLite)
- Storage: Cloudflare R2 for file uploads
- AI: OpenAI GPT-4, Google Gemini via Cloudflare AI Gateway
- Web Scraping: Puppeteer, Jina AI
Frontend (/jobjigsaw-frontend/)
- Framework: Next.js 15 with App Router
- Language: TypeScript
- Styling: Tailwind CSS v4
- UI Components: Custom components with Heroicons
- Deployment: Cloudflare Pages via OpenNext
Legacy Frontend (/frontend/)
- Framework: React + Vite
- Status: Read-only legacy project, not actively developed. All new work is done in
/jobjigsaw-frontend/
git clone <repository-url>
cd Jobjigsaw
# Install backend dependencies
cd backend
npm install
# Install frontend dependencies
cd ../jobjigsaw-frontend
npm install# Required API Keys
OPENAI_API_KEY=sk-... # OpenAI API key
SERP_API_KEY=... # SERP API for web search
OPENROUTER_API_KEY=... # Alternative AI models
# Cloudflare Configuration
CLOUDFLARE_ACCOUNT_ID=...
CLOUDFLARE_API_TOKEN=...NEXT_PUBLIC_API_BASE_URL=http://localhost:8787 # Backend URLNote: Developers will run npm run dev commands manually. Any AI Agents should not run it themselves unless developer explicitly asks the agent to run them.
# Terminal 1: Start backend
cd backend
npm run dev
# Terminal 2: Start frontend
cd jobjigsaw-frontend
npm run dev# Backend deployment
cd backend
npm run deploy
# Frontend deployment
cd jobjigsaw-frontend
npm run deployindex.ts: Main application entry point with HTTP routesdatabase.ts: D1 database connection and initializationopenai.ts: AI service integrations (OpenAI/Gemini)jina.ts: Web scraping and search services
┌─────────────────┐
│ Controllers │ ← HTTP route handlers (index.ts)
│ (Routes) │
└─────────────────┘
│
┌─────────────────┐
│ Services │ ← Business logic layer
│ (Job, Resume, │
│ MainResume) │
└─────────────────┘
│
┌─────────────────┐
│ Models │ ← Data access layer
│ (Database) │
└─────────────────┘
JobService (/backend/src/job/jobService.ts)
- Manages job postings and analysis
- Key methods:
createJob(),getJobs(),getJobById()
MainResumeService (/backend/src/mainResume/mainResumeService.ts)
- Singleton pattern for user's primary resume
- Key methods:
setMainResume(),getMainResume(),updateMainResume()
ResumeService (/backend/src/resume/resumeService.ts)
- Manages job-specific customized resumes
- Key methods:
createResume(),getResumes(),generateResume()
/app/
├── page.tsx # Home - Job analysis interface
├── main-resume/page.tsx # Resume upload and management
├── create-job/page.tsx # Job creation interface
├── saved-jobs/page.tsx # Job history (placeholder)
├── saved-resumes/page.tsx # Resume library (placeholder)
└── api/ # API routes (proxy to backend)
├── job/
├── main-resume/
└── resume/
JobInferencer(/components/JobInferencer.tsx): Main job analysis interfaceNavLinks(/components/NavLinks.tsx): Application navigation
graph TD
A[Upload Resume] --> B[AI Parsing]
B --> C[Store Main Resume]
C --> D[Enter Job Description]
D --> E[AI Job Analysis]
E --> F[Compatibility Check]
F --> G[Generate Tailored Resume]
G --> H[Save & Export]
User Action: Upload PDF/JSON resume
Frontend: /main-resume/page.tsx
const handleUploadResume = async (file: File) => {
const formData = new FormData();
formData.append("resume", file);
await uploadResume(formData); // API call
};API: POST /api/main-resume/uploadResume Backend: POST /main-resume →
MainResumeService.updateMainResume() AI Processing:
generateJsonFromResume() parses resume using OpenAI
User Action: Enter job description or URL
Frontend: JobInferencer component
const handleInferJob = async () => {
const result = await inferJob(jobDescription);
setInferredJob(result.inferredDescription);
};API: POST /api/job/infer Backend: POST /job/infer →
inferJobDescription() AI Processing: Extracts structured job data (title,
skills, requirements)
API: POST /api/job/infer-match Backend: checkCompatiblity() compares
resume vs job requirements Output: Match percentage, skill gaps,
recommendations
API: POST /api/resume/generate
Backend: generateResume() creates tailored resume AI Processing:
Optimizes content for specific job requirements
generateJsonFromResume(): Parse uploaded resumesinferJobDescription(): Extract job requirementscheckCompatiblity(): Score job-resume compatibilitygenerateResume(): Create customized resumesinferJobDescriptionFromUrl(): Scrape and analyze job URLs
- Resume Parsing: Extracts contact, skills, experience, education
- Job Analysis: Identifies technical/soft skills, requirements, "sugar-coating"
- Compatibility: Provides match scores and improvement suggestions
- Generation: Creates factual, tailored content without fabrication
- Primary: OpenAI GPT-4 via Cloudflare AI Gateway
- Fallback: Google Gemini
- Selection: Environment variable
useOpenAiflag
-- Main user resume (singleton)
CREATE TABLE mainResumes (
id INTEGER PRIMARY KEY DEFAULT 1,
resumeName TEXT,
resumeContent TEXT, -- JSON structure
dateCreated TEXT,
dateUpdated TEXT
);
-- Job postings and analysis
CREATE TABLE jobs (
id INTEGER PRIMARY KEY,
companyName TEXT,
jobTitle TEXT,
jobDescription TEXT,
jobUrl TEXT,
jobStatus TEXT,
inferredData TEXT, -- AI analysis results
jobFitScore INTEGER,
jobFitBreakdown TEXT,
-- ... additional fields
);
-- Generated customized resumes
CREATE TABLE resumes (
id INTEGER PRIMARY KEY,
resumeName TEXT,
resumeContent TEXT, -- Tailored resume JSON
jobId INTEGER, -- Links to jobs table
dateCreated TEXT,
dateUpdated TEXT
);POST /job # Create job
GET /job # List all jobs
GET /job/:id # Get specific job
DELETE /job/:id # Delete job
POST /job/infer # Analyze job description
POST /job/infer-url # Analyze job from URL
POST /job/infer-match # Check compatibility
POST /job/analyze # Full job analysisGET /main-resume # Get main resume
POST /main-resume # Upload/parse resume
PUT /main-resume # Update main resume
POST /resume # Create customized resume
GET /resume # List all resumes
GET /resume/:id # Get specific resume
PUT /resume/:id # Update resume
DELETE /resume/:id # Delete resume
POST /resume/generate # Generate tailored resumecd backend
npm test # Run Vitest testsindex.spec.ts: API endpoint testing- Vitest: Test runner with Cloudflare Workers support
- Environment: Test environment configuration
cd backend
npm run deploy # Deploy to Cloudflare Workerscd jobjigsaw-frontend
npm run deploy # Build and deploy via OpenNext- Backend: Configured in
wrangler.jsonc - Frontend: Configured in Cloudflare Pages dashboard
- Backend First: Implement API endpoints and business logic
- Frontend Integration: Create UI components and API integration
- Testing: Add tests for new functionality
- Documentation: Update relevant documentation
- TypeScript: Strict type checking enabled
- ESLint: Code quality enforcement
- Prettier: Code formatting (backend only)
- Conventional Commits: Use emoji-prefixed commit messages
# Feature development
git checkout -b feature/new-feature
git commit -m "✨ feat: Add new feature"
# Bug fixes
git commit -m "🐛 fix: Resolve issue with X"
# Documentation
git commit -m "📝 docs: Update onboarding guide"/backend/src/index.ts- Main application routes/backend/src/openai.ts- AI service integration/backend/src/database.ts- Database configuration/backend/src/job/jobService.ts- Job business logic/backend/src/mainResume/mainResumeService.ts- Resume management/backend/wrangler.jsonc- Cloudflare Workers config
/jobjigsaw-frontend/src/app/page.tsx- Home page/jobjigsaw-frontend/src/components/JobInferencer.tsx- Main interface/jobjigsaw-frontend/src/app/main-resume/page.tsx- Resume management/jobjigsaw-frontend/next.config.ts- Next.js configuration/jobjigsaw-frontend/package.json- Dependencies and scripts
- Single User System: No authentication or multi-tenancy
- Incomplete UI: Saved Jobs and Saved Resumes pages are placeholders
- No Global State: Limited state management between components
- Error Boundaries: Basic error handling implementation
- Authentication: Implement user accounts and authentication
- State Management: Add Redux or Zustand for global state
- UI Completion: Build out missing list and detail views
- Testing Coverage: Expand test coverage for frontend components
- Performance: Add caching and optimization strategies
- Follow the Getting Started section
- Create feature branches for new work
- Write tests for new functionality
- Update documentation as needed
- Submit pull requests with clear descriptions
- Functionality: Ensure features work as expected
- Performance: Consider impact on load times and AI costs
- Security: Review for potential security vulnerabilities
- Documentation: Verify documentation updates are included
- Cloudflare Workers Documentation
- Hono.js Documentation
- Next.js App Router Guide
- OpenAI API Documentation
- Tailwind CSS Documentation
Welcome to the Jobjigsaw project! This onboarding guide provides everything you need to understand, develop, and contribute to the codebase. For questions or clarifications, refer to the code files linked throughout this document.
- npm Available:
npmis available, if the agent can not run it. Ask the user to run npm commands.