Add blockedCountries in Settings so pipeline discovery drops jobs whose location mentions listed countries (existing discovered rows are kept). Document the feature, fix smoke tsconfig inheritance for nested extractors, and run smoke via an absolute-tsconfig wrapper. Co-authored-by: Cursor <cursoragent@cursor.com>
Job Ops Orchestrator
A unified orchestrator for the job application pipeline. Discovers jobs, scores them for suitability, generates tailored resumes, and provides a UI to manage applications.
Architecture
orchestrator/
├── src/
│ ├── server/ # Express backend
│ │ ├── api/ # REST API routes
│ │ ├── db/ # SQLite + Drizzle ORM
│ │ ├── pipeline/ # Orchestration logic
│ │ ├── repositories/ # Data access layer
│ │ └── services/ # Integrations (crawler, AI, PDF)
│ ├── client/ # React frontend
│ │ ├── api/ # API client
│ │ ├── components/ # UI components
│ │ └── styles/ # CSS design system
│ └── shared/ # Shared types
├── data/ # SQLite DB + generated PDFs (gitignored)
└── public/ # Static assets
Setup
-
Install dependencies:
cd orchestrator npm install -
Set up environment:
cp .env.example .env # The app is self-configuring. You can add keys via the UI Onboarding.After the server starts, use the onboarding modal to connect your LLM provider, configure Reactive Resume (
v5orv4), and select a template resume.v5(API key) is recommended for self-hosted/latest Reactive Resume. Usev4when connecting to the legacy email/password flow.OpenRouter is the default LLM provider, but OpenAI, LM Studio, Ollama,
openai-compatibleendpoints, and Gemini are also supported.Use
LLM_API_KEY/llmApiKeyto configure providers that require an API key. To use the native OpenAI integration, setLLM_PROVIDER=openai. For third-party services that expose an OpenAI-style API but are not OpenAI itself, useLLM_PROVIDER=openai-compatible. -
Initialize database:
npm run db:migrate -
Start development server:
npm run devThis starts:
- Backend API at
http://localhost:3001 - Frontend at
http://localhost:5173
- Backend API at
API Endpoints
Jobs
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/jobs |
List all jobs (filter with ?status=ready,discovered) |
| GET | /api/jobs/:id |
Get single job |
| PATCH | /api/jobs/:id |
Update job |
| POST | /api/jobs/actions |
Run job actions (move_to_ready, rescore, skip) for one or many jobs |
| POST | /api/jobs/actions/stream |
Stream job action progress/events for one or many jobs |
| POST | /api/jobs/:id/apply |
Mark as applied |
Pipeline
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/pipeline/status |
Get pipeline status |
| GET | /api/pipeline/runs |
Get recent pipeline runs |
| POST | /api/pipeline/run |
Trigger pipeline manually |
| POST | /api/webhook/trigger |
Webhook for n8n (use WEBHOOK_SECRET) |
Post-Application Tracking
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/post-application/inbox |
List pending messages for review |
| POST | /api/post-application/inbox/:id/approve |
Approve and link to job |
| POST | /api/post-application/inbox/:id/deny |
Ignore message |
| GET | /api/post-application/runs |
List sync run history |
| GET | /api/post-application/providers/gmail/oauth/start |
Initiate Gmail OAuth flow |
| POST | /api/post-application/providers/gmail/oauth/exchange |
Exchange OAuth code |
Daily Flow
-
17:00 - n8n triggers pipeline:
- Calls
POST /api/webhook/trigger - Pipeline crawls Gradcracker
- Scores jobs with AI
- Generates tailored resumes for top 10
- Calls
-
You review in the UI:
- See jobs at
http://localhost:5173 - "Ready" tab shows jobs with generated PDFs
- Use command bar search (
Cmd/Ctrl+K) to quickly find and open jobs - Click "View Job" to open application
- Download PDF and apply manually
- Click "Mark Applied" to mark application status
- See jobs at
-
Track responses (optional):
- Connect Gmail in Tracking Inbox settings
- Automatic email monitoring for interview invites, offers, rejections
- Review and approve/ignore matched emails in the Inbox
n8n Setup
Create a workflow with:
- Schedule Trigger - Every day at 17:00
- HTTP Request:
- Method: POST
- URL:
http://localhost:3001/api/webhook/trigger - Headers:
Authorization: Bearer YOUR_WEBHOOK_SECRET
Development
# Run just the server
npm run dev:server
# Run just the client
npm run dev:client
# Run the pipeline manually
npm run pipeline:run
# Build for production
npm run build
npm start
Tech Stack
- Backend: Express, TypeScript, Drizzle ORM, SQLite
- Frontend: React, Vite, CSS (custom design system)
- AI: Configurable LLM provider (OpenRouter default; also supports OpenAI via the dedicated
openaiprovider,openai-compatibleendpoints, Gemini, LM Studio, and Ollama) - PDF Generation: Reactive Resume v4/v5 API export (configured via Settings)
- Job Crawling: Wraps existing TypeScript Crawlee crawler