- Server: auth routes, owner profile on requests/jobs/pipeline, migrations - Client: BasicAuthAppGate, SSE/API session handling, profile quick switch - Tests: tracer-links, ghostwriter request-context mock, pipeline coverage - Env examples for cron and optional basic auth credentials Made-with: Cursor
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