# JobOps Self-hosted job search orchestration: discover roles from multiple sources, score fit with your profile, draft tailored resumes and cover letters, export PDFs, and track application email—**you still submit applications yourself**; JobOps prepares the work and keeps state organized. Licensed under **AGPLv3 + Commons Clause** — see [LICENSE](LICENSE). ![Product screenshot](https://github.com/user-attachments/assets/14fdc392-0e96-43be-bc1f-cf819ab2afc4) ## What’s in this repo | Area | Role | |------|------| | **`orchestrator/`** | Express API, SQLite + Drizzle, pipeline, React (Vite) UI, LLM integrations, Reactive Resume PDF flow | | **`shared/`** | Shared TypeScript types and settings registry | | **`docs-site/`** | Docusaurus user and developer documentation | | **`extractors/`** | Per-source crawlers (Adzuna, Gradcracker, UK Visa Jobs, Hiring Café, Startup Jobs, JobSpy helpers, etc.) | Root `package.json` is an npm **workspace** root; day-to-day app commands usually run under `orchestrator/`. ## Features (high level) - **Sources**: Multiple boards and aggregators (exact list evolves; see docs and extractor packages). - **Scoring & tailoring**: LLM compares jobs to your resume profile; optional drafts for summary, headline, skills, and project selection. The scorer enforces hard caps when deal-breakers fire (e.g. clearance/citizenship conflicts cap score to 0-15) and includes candidate name and location in the profile sent to the model. - **Cover letters**: LLM-generated, profile-aware cover letters. The prompt uses the full job-search profile (experience level, target roles, must-have and nice-to-have skills, work arrangement, location, salary, industries, deal-breakers) and produces 4-5 paragraphs (~550 words) signed with the candidate's name. - **Job notes**: Per-listing personal notes with debounced auto-save, available in Discovered, Ready, and detail panels. - **PDFs**: Tailored exports via **Reactive Resume** (v4 or v5 API). Optional **local JSON resume** (`JOBOPS_LOCAL_RESUME_PATH` or Settings) as the base document for profile/tailoring; PDF export still uses RxResume when configured. - **Pipeline**: Scheduled or manual runs (`POST /api/pipeline/run`, webhook trigger). - **Post-application**: Optional Gmail-based inbox for interview/offer/rejection signals. - **Job list filters** (orchestrator UI): Narrow the pipeline job list by **multiple sources** and **countries** (country is inferred from each listing’s location text). Filters sync to the URL (`source`, `sourceExclude`, `countries`, `countriesExclude`). Each source/country chip cycles **off → include → exclude** (exclude shows in red); listings marked **remote** still pass country include/exclude rules. - **Bulk actions**: Select-all / batch actions support up to **2 500 jobs** per request (raised from 100). - **Data**: SQLite and generated artifacts under `./data` (default in Docker). ## Requirements - **Node.js 22** (see `package.json` / Volta pin) for local development. - **Docker + Compose v2** for the recommended production-style run. ## Quick start (Docker) ```bash git clone cd Jobber cp .env.example .env # Edit .env: MODEL / LLM keys, Reactive Resume or local resume path, optional BASIC_AUTH, etc. docker compose up -d --build ``` - **UI**: `http://localhost:3005` (host port mapped in `docker-compose.yml`; app listens on **3001** inside the container). - **Health**: `GET /health` on the same origin. Persist data by backing up the mounted **`./data`** directory. ## Local development From the repository root: ```bash npm install ``` Then use the orchestrator workspace (see **`orchestrator/README.md`** for API tables and scripts): ```bash cd orchestrator cp .env.example .env npm run db:migrate npm run dev ``` Typical dev URLs: API **http://localhost:3001**, Vite client **http://localhost:5173**. ## Configuration notes - **LLM**: Configurable provider (OpenRouter default; also OpenAI, OpenAI-compatible endpoints, Gemini, Ollama, LM Studio, etc.). Keys can be set in `.env` or onboarding. - **Reactive Resume**: v5 API key or v4 email/password; optional self-hosted `RXRESUME_URL`. Full behavior is documented in the docs site under **Reactive Resume**. - **Local resume JSON**: Set `JOBOPS_LOCAL_RESUME_PATH` (or the Settings field) to a Reactive Resume–shaped export so you do not need a selected cloud “base resume” for profile and tailoring. PDF generation still performs a temporary import/print through RxResume when credentials are present. ## Documentation | Resource | Contents | |----------|----------| | **`docs-site/`** | User-facing guides (build with `npm run docs:dev` from repo root) | | **`orchestrator/README.md`** | Orchestrator layout, endpoints, dev commands | | **`DEPLOY_GITEA_VM_CRON_TELEGRAM.md`** | VM/container deploy, cron, optional Telegram | | **`AGENTS.md`** | API/logging/SSE conventions for contributors and automation | ## Deploy, cron, Telegram See **[DEPLOY_GITEA_VM_CRON_TELEGRAM.md](./DEPLOY_GITEA_VM_CRON_TELEGRAM.md)** for production deploy, scheduling `POST /api/pipeline/run`, and optional notifications. ## Verification (CI parity) From the repo root, before merging substantial changes: ```bash ./orchestrator/node_modules/.bin/biome ci . npm run check:types:shared npm --workspace orchestrator run check:types npm --workspace orchestrator run build:client npm --workspace orchestrator run test:run ``` (Additional workspace typechecks apply in CI; see **`AGENTS.md`**.) ## License **AGPLv3 + Commons Clause** — you may self-host, use, and modify; you may not sell the software or offer paid hosting or support whose value substantially comes from this codebase. See [LICENSE](LICENSE).