From 390d03625efeabdd1fd56cfd5936221bbf42e630 Mon Sep 17 00:00:00 2001 From: Shaheer Sarfaraz <53654735+DaKheera47@users.noreply.github.com> Date: Mon, 16 Feb 2026 00:33:35 +0000 Subject: [PATCH] Add documentation for undocumented features (#172) * documentation writing skill * visa sponsors page * overview * in progress board * settings * reactive resume section * database backups * workflows * post application tracking flow * manual tracking caveats * pricing section * pipeline run detalis * job search bar * keyboard shortcuts * bulk actions * no informal phrasing * formatting * build fix? * Update docs-site/docs/features/overview.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update docs-site/versioned_docs/version-0.1.20/features/orchestrator.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update docs-site/docs/features/visa-sponsors.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update docs-site/docs/features/in-progress-board.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * remove link to page that don't exist --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- AGENTS.md | 17 ++ docs-site/docs/extractors/manual.md | 14 +- docs-site/docs/extractors/overview.md | 30 ++- docs-site/docs/features/ghostwriter.md | 62 +++-- docs-site/docs/features/in-progress-board.md | 90 +++++++ docs-site/docs/features/job-search-bar.md | 73 ++++++ docs-site/docs/features/keyboard-shortcuts.md | 79 +++++++ .../features/multi-select-and-bulk-actions.md | 63 +++++ docs-site/docs/features/orchestrator.md | 132 ++++++----- docs-site/docs/features/overview.md | 65 ++++++ docs-site/docs/features/pipeline-run.md | 112 +++++++++ docs-site/docs/features/reactive-resume.md | 220 ++++++++++++++++++ docs-site/docs/features/settings.md | 154 ++++++++++++ docs-site/docs/features/visa-sponsors.md | 74 ++++++ .../docs/getting-started/database-backups.md | 127 ++++++++++ docs-site/docs/intro.md | 80 ++++++- .../reference/documentation-style-guide.md | 4 +- docs-site/docs/reference/faq.md | 16 +- .../workflows/find-jobs-and-apply-workflow.md | 96 ++++++++ .../workflows/post-application-workflow.md | 141 +++++++++++ docs-site/sidebars.ts | 18 ++ .../version-0.1.20/extractors/overview.md | 22 +- .../version-0.1.20/features/ghostwriter.md | 62 +++-- .../version-0.1.20/features/orchestrator.md | 128 ++++++---- .../reference/documentation-style-guide.md | 34 --- 25 files changed, 1720 insertions(+), 193 deletions(-) create mode 100644 docs-site/docs/features/in-progress-board.md create mode 100644 docs-site/docs/features/job-search-bar.md create mode 100644 docs-site/docs/features/keyboard-shortcuts.md create mode 100644 docs-site/docs/features/multi-select-and-bulk-actions.md create mode 100644 docs-site/docs/features/overview.md create mode 100644 docs-site/docs/features/pipeline-run.md create mode 100644 docs-site/docs/features/reactive-resume.md create mode 100644 docs-site/docs/features/settings.md create mode 100644 docs-site/docs/features/visa-sponsors.md create mode 100644 docs-site/docs/getting-started/database-backups.md create mode 100644 docs-site/docs/workflows/find-jobs-and-apply-workflow.md create mode 100644 docs-site/docs/workflows/post-application-workflow.md diff --git a/AGENTS.md b/AGENTS.md index b1b18c1..b15b646 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -57,6 +57,23 @@ Use consistent status/code mapping: - No raw sensitive payload logging or raw upstream body throws. - New/changed webhook or LLM payloads are sanitized and documented. +## Documentation Standards (Condensed) + +When adding or updating user-facing docs: + +- Use this feature-page structure: + 1. **What it is** + 2. **Why it exists** + 3. **How to use it** + 4. **Common problems** + 5. **Related pages** +- Include frontmatter keys: `id`, `title`, `description`, `sidebar_position`. +- Prefer concrete, step-by-step instructions over abstract explanation. +- Include copy-pasteable examples where relevant. +- State defaults and constraints explicitly. +- Link related docs with `/docs/...` URLs. +- Any user-visible behavior change should include corresponding docs updates. + ## Validation / Verification Before marking work complete, verify changes with the same checks used by CI. diff --git a/docs-site/docs/extractors/manual.md b/docs-site/docs/extractors/manual.md index d8bb0cf..927fd6f 100644 --- a/docs-site/docs/extractors/manual.md +++ b/docs-site/docs/extractors/manual.md @@ -13,7 +13,13 @@ User pastes raw description, AI infers structure, user reviews edits, then impor ## 1) Input -User pastes a job description in the **Manual Import** UI. +Manual import accepts: + +- plain text job descriptions +- raw HTML job descriptions +- job links/URLs + +When a URL is provided, backend fetch attempts depend on whether the page can be resolved with `curl`. Some job sites block or heavily script content, so certain links will not resolve cleanly. ## 2) AI inference @@ -27,10 +33,14 @@ Service: Behavior: -- Sends raw text to configured LLM +- Converts the provided input into text context and sends it to the configured LLM - Extracts structured fields (title, employer, location, salary, etc.) - Returns inferred JSON for user review +Practical limit: + +- The inference quality ceiling is mostly the configured model capability and context behavior. Better model quality generally yields better field extraction. + If no LLM key is configured, inference is skipped and user can fill fields manually. ## 3) Review and edit diff --git a/docs-site/docs/extractors/overview.md b/docs-site/docs/extractors/overview.md index aea8aa2..f6a2670 100644 --- a/docs-site/docs/extractors/overview.md +++ b/docs-site/docs/extractors/overview.md @@ -5,9 +5,29 @@ description: Technical index of supported extractors and how they work. sidebar_position: 1 --- -Technical breakdowns of each extractor: +This page helps you choose the right extractor for your run, understand key constraints, and navigate to detailed technical guides. -- [Gradcracker](/docs/extractors/gradcracker) -- [JobSpy](/docs/extractors/jobspy) -- [UKVisaJobs](/docs/extractors/ukvisajobs) -- [Manual Import](/docs/extractors/manual) +## Extractor chooser + +| Extractor | Best use case | Core constraints/dependencies | Notable controls | Output/behavior notes | +| --- | --- | --- | --- | --- | +| [Gradcracker](/docs/next/extractors/gradcracker) | UK graduate roles from Gradcracker | Crawling stability depends on page structure and anti-bot behavior; tuned for low concurrency | `GRADCRACKER_SEARCH_TERMS`, `GRADCRACKER_MAX_JOBS_PER_TERM`, `JOBOPS_SKIP_APPLY_FOR_EXISTING` | Scrapes listing metadata, then detail pages and apply URL resolution | +| [JobSpy](/docs/next/extractors/jobspy) | Multi-source discovery (Indeed, LinkedIn, Glassdoor) | Requires Python wrapper execution per term; source availability and quality vary by site/location | `JOBSPY_SITES`, `JOBSPY_SEARCH_TERMS`, `JOBSPY_RESULTS_WANTED`, `JOBSPY_HOURS_OLD`, `JOBSPY_LINKEDIN_FETCH_DESCRIPTION` | Produces JSON per term, then orchestrator normalizes and de-duplicates by `jobUrl` | +| [UKVisaJobs](/docs/next/extractors/ukvisajobs) | UK visa sponsorship-focused roles | Requires authenticated session and periodic token/cookie refresh | `UKVISAJOBS_EMAIL`, `UKVISAJOBS_PASSWORD`, `UKVISAJOBS_MAX_JOBS`, `UKVISAJOBS_SEARCH_KEYWORD` | API pagination + dataset output; orchestrator de-dupes and may fetch missing descriptions | +| [Manual Import](/docs/next/extractors/manual) | One-off jobs not covered by scrapers | Inference quality depends on model/provider and input quality; some URLs cannot be fetched reliably | App/API endpoints (`/api/manual-jobs/infer`, `/api/manual-jobs/import`) | Accepts text/HTML/URL, runs inference, then saves and scores job after review | + +## Which extractor should I use? + +- Use **JobSpy** for broad first-pass sourcing across common boards. +- Use **Gradcracker** when targeting graduate pipelines in the UK. +- Use **UKVisaJobs** for sponsorship-specific UK searches. +- Use **Manual Import** when you already have a specific posting and need direct import. + +Many runs combine sources: broad discovery first, then manual import for high-priority jobs that scraping misses. + +## Related extractor docs + +- [Gradcracker](/docs/next/extractors/gradcracker) +- [JobSpy](/docs/next/extractors/jobspy) +- [UKVisaJobs](/docs/next/extractors/ukvisajobs) +- [Manual Import](/docs/next/extractors/manual) diff --git a/docs-site/docs/features/ghostwriter.md b/docs-site/docs/features/ghostwriter.md index 2c03ac6..48e53b2 100644 --- a/docs-site/docs/features/ghostwriter.md +++ b/docs-site/docs/features/ghostwriter.md @@ -5,30 +5,37 @@ description: Context-aware per-job AI chat assistant behavior and API surface. sidebar_position: 2 --- -Ghostwriter is the per-job AI chat assistant in JobOps. +## What it is -## What it is for +Ghostwriter is the per-job AI chat assistant in JobOps. Ghostwriter uses: -- Current job description and metadata -- Reduced profile snapshot -- Global writing style settings +- current job description and metadata +- reduced profile snapshot +- global writing style settings + +The UI behavior is one persistent conversation per job, shown in the right-side drawer from job details. + +## Why it exists + +Ghostwriter helps you produce job-specific writing quickly while preserving consistency with your profile and style settings. Typical use cases: -- Role-specific answer drafting -- Cover letter and outreach drafts -- Interview prep tied to the JD -- Rephrasing with tone constraints +- role-specific answer drafting +- cover letter and outreach drafts +- interview prep tied to the job description +- rephrasing with tone constraints -## Where it appears +## How to use it -- Available from job details in `discovered` and `ready` -- Right-side drawer UX -- One persistent conversation per job +1. Open a job in `discovered` or `ready`. +2. Open the Ghostwriter drawer. +3. Enter your prompt and stream a response. +4. Stop or regenerate responses when needed. -## Writing style settings impact +### Writing style settings impact Global settings affecting generations: @@ -44,14 +51,14 @@ Defaults: - Constraints: empty - Do-not-use terms: empty -## Context and safety model +### Context and safety model - Job snapshot is truncated to fit prompt budget. - Profile snapshot includes relevant slices only. - System prompt enforces read-only assistant behavior. - Logging stores metadata, not full prompt/response dumps. -## API surface +### API surface - `GET /api/jobs/:id/chat/messages` - `POST /api/jobs/:id/chat/messages` (streaming) @@ -59,3 +66,26 @@ Defaults: - `POST /api/jobs/:id/chat/messages/:assistantMessageId/regenerate` (streaming) Compatibility thread endpoints remain, but UI behavior is one thread per job. + +## Common problems + +### Responses feel too generic + +- Verify the job description is complete and current. +- Confirm style constraints in Settings are specific enough. + +### Generation quality is lower than expected + +- Check model/provider configuration in Settings. +- Tighten prompts with explicit output intent (for example, "3 bullet points for recruiter outreach"). + +### Missing context in answers + +- Update profile data and relevant project details used by Ghostwriter context. +- Regenerate after updating job notes/description. + +## Related pages + +- [Settings](/docs/next/features/settings) +- [Reactive Resume](/docs/next/features/reactive-resume) +- [Orchestrator](/docs/next/features/orchestrator) diff --git a/docs-site/docs/features/in-progress-board.md b/docs-site/docs/features/in-progress-board.md new file mode 100644 index 0000000..29ceafe --- /dev/null +++ b/docs-site/docs/features/in-progress-board.md @@ -0,0 +1,90 @@ +--- +id: in-progress-board +title: In Progress Board +description: Post-application kanban board for tracking fewer, higher-attention jobs through interview and offer stages. +sidebar_position: 3 +--- + +## What it is + +The In Progress Board is a kanban view for jobs that have moved beyond initial application. + +It groups jobs into post-application lanes: + +- Recruiter Screen +- Assessment +- Team Match +- Technical Interview +- Final Round +- Offer +- Closed + +## Why it exists + +JobOps uses two operational modes: + +- **Pre-application tracking** (`Jobs` page): large volume, pipeline and readiness focused. +- **Post-application tracking** (`In Progress Board`): smaller volume, higher attention per job. + +Once a job enters the post-application phase, each opportunity usually needs tighter follow-up, interview prep, and deliberate stage management. A kanban board is better for that than a large list. + +## How to use it + +1. Open **In Progress Board**. +2. Review jobs by lane to see current stage distribution. +3. Drag a card to a new lane to log a stage transition. +4. Open a card to view full job details and timeline. +5. Use sorting (Recent / Title / Company) to prioritize review. + +### Moving jobs into post-application + +Jobs typically move into post-application tracking when they receive a response after applying. + +This can happen via: + +- Tracking Inbox review/automation (recommended) +- Manual stage transitions in job detail/timeline tools + +### API examples + +```bash +# List in-progress jobs +curl "http://localhost:3001/api/jobs?status=in_progress&view=list" +``` + +```bash +# Move a job to technical interview +curl -X POST "http://localhost:3001/api/jobs//stage-events" \ + -H "content-type: application/json" \ + -d '{ + "toStage": "technical_interview", + "metadata": { + "actor": "user", + "eventType": "status_update", + "eventLabel": "Moved to Technical Interview" + } + }' +``` + +## Common problems + +### Board is empty + +- Confirm jobs have status `in_progress`. +- Confirm stage events exist for applied jobs expected on the board. + +### A card appears in an unexpected lane + +- The board uses the latest stage event as source of truth. +- Check timeline events for out-of-order or mistaken transitions. + +### Drag-and-drop move failed + +- Network/API error can roll back optimistic UI movement. +- Retry move and check server logs for validation errors. + +## Related pages + +- [Overview](/docs/next/features/overview) +- [Orchestrator](/docs/next/features/orchestrator) +- [Post-Application Tracking](/docs/next/features/post-application-tracking) diff --git a/docs-site/docs/features/job-search-bar.md b/docs-site/docs/features/job-search-bar.md new file mode 100644 index 0000000..0261f95 --- /dev/null +++ b/docs-site/docs/features/job-search-bar.md @@ -0,0 +1,73 @@ +--- +id: job-search-bar +title: Job Search Bar +description: Use the global job search/command bar to find and open jobs fast, with optional status locking. +sidebar_position: 3 +--- + +The Job Search Bar is the quickest way to jump to any job from the Jobs page. + +## Open it + +Use either: + +- keyboard shortcut: `Cmd+K` (macOS) or `Ctrl+K` (Windows/Linux) +- the **Search** button in the Jobs page filter row + +## What it searches + +Search matches job fields with fuzzy ranking: + +- title +- company/employer +- location + +Results are grouped by status sections: + +- Ready +- Discovered +- Applied +- Other + +Selecting a result opens that job in its correct tab automatically. + +## Status lock (`@`) + +You can lock the search scope to one status: + +1. Type `@` plus a status prefix (example: `@rea`, `@app`). +2. Press `Tab` or `Enter` to apply the lock. +3. Continue typing your normal query. + +Supported lock targets: + +- `ready` +- `discovered` +- `applied` +- `skipped` +- `expired` + +Common aliases: + +- `ready`: `ready`, `rdy` +- `discovered`: `discovered`, `discover`, `disc` +- `applied`: `applied`, `apply`, `app` +- `skipped`: `skipped`, `skip`, `skp` +- `expired`: `expired`, `expire`, `exp` + +## Lock controls + +- `Backspace` on an empty query clears the active lock. +- `Esc` clears the active lock while the search dialog stays open. +- Closing the dialog resets lock state. + +## When to use this vs filters + +- Use **Search Bar** when you already know what role/company you want to jump to quickly. +- Use **Filters** when you want broad narrowing (source, salary, sponsor, sort) for browsing. + +## Related pages + +- [Orchestrator](./orchestrator) +- [Pipeline Run](./pipeline-run) +- [Find Jobs and Apply Workflow](../workflows/find-jobs-and-apply-workflow) diff --git a/docs-site/docs/features/keyboard-shortcuts.md b/docs-site/docs/features/keyboard-shortcuts.md new file mode 100644 index 0000000..783b9c8 --- /dev/null +++ b/docs-site/docs/features/keyboard-shortcuts.md @@ -0,0 +1,79 @@ +--- +id: keyboard-shortcuts +title: Keyboard Shortcuts +description: Complete keyboard shortcut reference for the Jobs page, including tab-scoped actions and help/search toggles. +sidebar_position: 4 +--- + +This page documents keyboard shortcuts available on the Jobs page. + +## Open shortcut help + +Use `?` to toggle the keyboard shortcut dialog. + +The dialog: + +- shows shortcuts for your current tab context +- groups shortcuts by Navigation, Actions, Tabs, and General +- is shown automatically once for first-time users + +## Bottom shortcut hint bar + +On desktop (`lg+`), hold `Control` to reveal the bottom shortcut hint bar. + +It shows the same tab-scoped shortcuts in a compact layout. + +## Global navigation shortcuts + +- `j` or `ArrowDown`: next job +- `k` or `ArrowUp`: previous job +- `1`: Ready tab +- `2`: Discovered tab +- `3`: Applied tab +- `4`: All Jobs tab +- `ArrowLeft`: previous tab +- `ArrowRight`: next tab + +## Search and help shortcuts + +- `Cmd+K` / `Ctrl+K`: open job search bar +- `/`: open job search bar +- `?`: toggle keyboard shortcut help dialog + +For search lock behavior (`@ready`, `@app`, etc.), see [Job Search Bar](./job-search-bar). + +## Context action shortcuts + +### Available in `discovered` and `ready` + +- `s`: skip job + +### Available in `discovered` + +- `r`: move to Ready + +Note: if you have multi-select active, `r` runs bulk move-to-ready. + +### Available in `ready` + +- `a`: mark applied +- `p`: view PDF +- `d`: download PDF + +### Available in all tabs (when applicable) + +- `o`: open job listing +- `x`: toggle select current job +- `Esc`: clear selection + +## Shortcut availability rules + +Shortcuts are disabled while blocking modals are open (for example Run modal, Filters, drawer states). + +Search (`/`) and Help (`?`) can still open their own dialogs when other blocking dialogs are not active. + +## Related pages + +- [Job Search Bar](./job-search-bar) +- [Orchestrator](./orchestrator) +- [Pipeline Run](./pipeline-run) diff --git a/docs-site/docs/features/multi-select-and-bulk-actions.md b/docs-site/docs/features/multi-select-and-bulk-actions.md new file mode 100644 index 0000000..7f0f0ea --- /dev/null +++ b/docs-site/docs/features/multi-select-and-bulk-actions.md @@ -0,0 +1,63 @@ +--- +id: multi-select-and-bulk-actions +title: Multi-Select and Bulk Actions +description: Select multiple jobs with mouse or keyboard and run bulk actions like Move to Ready, Skip, or Recalculate match. +sidebar_position: 5 +--- + +Multi-select lets you process many jobs at once instead of repeating the same action one-by-one. + +## Why this exists + +When you run discovery at scale, you often need to: + +- skip batches of low-priority jobs +- move a shortlist to Ready quickly +- recalculate fit scores after settings/profile changes + +Bulk actions reduce repetitive clicks, keep momentum high, and make triage runs faster. + +## Mouse workflow + +### Select jobs + +1. Use the checkbox on each row to include/exclude a job. +2. Use **Select all filtered** to select jobs currently visible in the active filtered list. +3. Check the selected count in the list header. + +### Run bulk actions + +When one or more jobs are selected, a floating action bar appears at the bottom. + +Available actions depend on selected job statuses: + +- **Move to Ready** +- **Skip selected** +- **Recalculate match** +- **Clear** (clears selection) + +## Keyboard workflow + +Use shortcuts from the Jobs page: + +- `x`: toggle select on the currently focused job +- `Esc`: clear current selection +- `r`: in `discovered`, move to Ready + +`r` behavior with selection: + +- if you have a multi-selection active, `r` runs the bulk **Move to Ready** action +- if nothing is selected, `r` runs move-to-ready for the single current job + +## Important limits and behavior + +- Bulk actions are capped at **100 jobs per run**. +- `Select all filtered` also respects the same 100-job cap. +- Selection resets when you switch tabs. +- If jobs disappear from the active filtered list, they are removed from selection automatically. + +## Related pages + +- [Keyboard Shortcuts](./keyboard-shortcuts) +- [Orchestrator](./orchestrator) +- [Find Jobs and Apply Workflow](../workflows/find-jobs-and-apply-workflow) diff --git a/docs-site/docs/features/orchestrator.md b/docs-site/docs/features/orchestrator.md index 9138f20..571e28f 100644 --- a/docs-site/docs/features/orchestrator.md +++ b/docs-site/docs/features/orchestrator.md @@ -5,88 +5,116 @@ description: Job states, ready flow, and PDF generation/regeneration behavior. sidebar_position: 1 --- -This guide explains job states, how jobs become ready, and how PDF generation works. +## What it is -## Job states +The Orchestrator is the primary jobs workspace in JobOps. -- `discovered`: Found by crawler/import, not tailored yet. -- `processing`: Tailoring and/or PDF generation in progress. -- `ready`: Tailored PDF generated and ready to apply. -- `applied`: Marked as applied. -- `skipped`: Explicitly excluded from active queue. -- `expired`: Deadline passed. +It controls: -## Intended ready flow +- job lifecycle states +- manual and automatic ready flow +- PDF generation and regeneration +- handoff to post-application tracking -### 1) Manual flow +Job states: -1. Job starts in `discovered`. -2. Open in Discovered panel and choose Tailor. -3. Edit JD/tailored fields/project picks. -4. Click **Finalize & Move to Ready**. +- `discovered`: found by crawler/import, not tailored yet +- `processing`: tailoring and/or PDF generation in progress +- `ready`: tailored PDF generated and ready to apply +- `applied`: marked as applied +- `skipped`: explicitly excluded from active queue +- `expired`: deadline passed -### 2) Auto flow +## Why it exists -1. Pipeline scores discovered jobs. -2. Top jobs above threshold are auto-processed. -3. Jobs move directly to `ready` with generated PDFs. +Orchestrator centralizes the transition from discovered opportunities to application-ready artifacts. -## Ghostwriter +It exists to ensure: + +- a consistent path from discovery to tailored output +- clear status transitions across manual and automated workflows +- predictable regeneration behavior when job data changes + +## How to use it + +### Intended ready flow + +1. Manual flow: + 1. Job starts in `discovered`. + 2. Open the job and choose Tailor. + 3. Edit JD/tailored fields/project picks. + 4. Click **Finalize & Move to Ready**. +2. Auto flow: + 1. Pipeline scores discovered jobs. + 2. Top jobs above threshold are auto-processed. + 3. Jobs move directly to `ready` with generated PDFs. + +### Ghostwriter availability Ghostwriter is available in `discovered` and `ready` job views. -For details, see [Ghostwriter](/docs/features/ghostwriter). +For details, see [Ghostwriter](/docs/next/features/ghostwriter). -## Generating PDFs (first time) +### Generating PDFs PDF generation uses: -- Base resume selected from RxResume -- Job description -- Tailored summary/headline/skills/projects +- base resume selected from RxResume +- job description +- tailored summary/headline/skills/projects Common paths: -- **Discovered → Tailor → Finalize** - - `POST /api/jobs/:id/process` -- **Ready → Regenerate PDF** - - `POST /api/jobs/:id/generate-pdf` +- Discovered to finalization: `POST /api/jobs/:id/process` +- Ready regeneration: `POST /api/jobs/:id/generate-pdf` -## Regenerating PDFs after edits +### Regenerating PDFs after edits (copy-pasteable examples) If JD or tailoring changes, regenerate PDF to keep output in sync. -### API flow - ```bash -PATCH /api/jobs/:id -{ - "jobDescription": "", - "tailoredSummary": "", - "tailoredHeadline": "", - "tailoredSkills": "[{\"name\":\"Backend\",\"keywords\":[\"TypeScript\",\"Node.js\"]}]", - "selectedProjectIds": "p1,p2" -} +curl -X PATCH "http://localhost:3001/api/jobs/" \ + -H "content-type: application/json" \ + -d '{ + "jobDescription": "", + "tailoredSummary": "", + "tailoredHeadline": "", + "tailoredSkills": [{"name":"Backend","keywords":["TypeScript","Node.js"]}], + "selectedProjectIds": "p1,p2" + }' ``` ```bash -POST /api/jobs/:id/summarize?force=true -POST /api/jobs/:id/generate-pdf +curl -X POST "http://localhost:3001/api/jobs//summarize?force=true" +curl -X POST "http://localhost:3001/api/jobs//generate-pdf" ``` -## Post-application tracking - -For inbox routing flow and setup, see [Post-Application Tracking](/docs/features/post-application-tracking). - -## Notes and gotchas - -- `processing` is transient. On PDF failure, job reverts to `discovered`. -- PDFs are served at `/pdfs/resume_.pdf` with cache-bust on `updatedAt`. -- `skipped`/`applied` jobs can be reopened by patching `status` to `discovered`. - -## External payload and sanitization defaults +### External payload and sanitization defaults - LLM prompts send minimized profile/job fields. - Webhooks are sanitized and whitelisted by default. - Logs and error details are redacted/truncated by default. - Correlation fields include `requestId`, and when available `pipelineRunId` and `jobId`. + +## Common problems + +### Job is stuck in `processing` + +- `processing` is transient; failures generally revert the job to `discovered`. +- Check run logs and retry generation. + +### PDF does not reflect recent edits + +- Run summarize with `force=true` after changing the JD/tailoring. +- Regenerate PDF after summarize completes. + +### Reopen skipped/applied jobs + +- Patch `status` back to `discovered` to return the job to the active queue. + +## Related pages + +- [Pipeline Run](/docs/next/features/pipeline-run) +- [Ghostwriter](/docs/next/features/ghostwriter) +- [Reactive Resume](/docs/next/features/reactive-resume) +- [Post-Application Tracking](/docs/next/features/post-application-tracking) diff --git a/docs-site/docs/features/overview.md b/docs-site/docs/features/overview.md new file mode 100644 index 0000000..262d6a7 --- /dev/null +++ b/docs-site/docs/features/overview.md @@ -0,0 +1,65 @@ +--- +id: overview +title: Overview +description: Dashboard analytics for application volume and conversion over selectable time windows. +sidebar_position: 1 +--- + +## What it is + +The Overview page is the analytics dashboard for your pipeline outcomes. + +It visualizes: + +- Applications per day +- Application-to-response conversion +- Funnel progression (Applied, Screening, Interview, Offer, Rejected) + +## Why it exists + +The page helps you measure whether your current sourcing and tailoring approach is producing responses, not just applications. + +Use it to quickly answer: + +- Are application volumes increasing or dropping? +- Is response conversion improving? +- Where are applications stalling in the funnel? + +## How to use it + +1. Open **Overview**. +2. Select a time window (`7d`, `14d`, `30d`, `90d`) in the top-right selector. +3. Review: + - **Applications per day** for volume trend + - **Application → Response Conversion** for quality/outcome trend +4. Compare periods and adjust your sourcing terms, filters, or tailoring strategy. + +### Data and calculation defaults + +- Default window is `30d`. +- Only jobs in statuses `applied` and `in_progress` are used as input. +- Conversion counts any positive response-stage event (for example recruiter screen, assessment, interview stages, or offer). +- Conversion trend chart uses a rolling window up to 7 days. + +## Common problems + +### Empty charts + +- Verify you have jobs with `appliedAt` timestamps. +- The selected duration may exclude your recent activity. + +### Conversion appears low + +- Conversion only counts jobs that reached response stages. +- If stage events are missing or delayed, conversion will under-report. + +### Trend icons look counterintuitive + +- Volume trend compares first-half vs second-half averages in the selected window. +- Changing the time window can materially change trend direction. + +## Related pages + +- [Orchestrator](/docs/next/features/orchestrator) +- [Post-Application Tracking](/docs/next/features/post-application-tracking) +- [Troubleshooting](/docs/next/troubleshooting/common-problems) diff --git a/docs-site/docs/features/pipeline-run.md b/docs-site/docs/features/pipeline-run.md new file mode 100644 index 0000000..8be3860 --- /dev/null +++ b/docs-site/docs/features/pipeline-run.md @@ -0,0 +1,112 @@ +--- +id: pipeline-run +title: Pipeline Run +description: How to use Run Mode (Automatic vs Manual), presets, source controls, and advanced run settings. +sidebar_position: 2 +--- + +## What it is + +Pipeline Run is the Jobs-page run modal for starting either: + +- an **Automatic** pipeline run +- a **Manual** one-job import + +For end-to-end sequence, read [Find Jobs and Apply Workflow](/docs/next/workflows/find-jobs-and-apply-workflow). +For manual import internals, read [Manual Import Extractor](/docs/next/extractors/manual). + +## Why it exists + +The modal provides one place to control run volume, source compatibility, and processing aggressiveness before consuming compute/time. + +It helps you: + +- choose speed vs depth with presets +- avoid invalid source/country combinations +- understand estimated run cost before starting + +## How to use it + +1. Open the Jobs page and use the top-right run control. +2. Choose either **Automatic** or **Manual** tab. +3. Configure required inputs and start run. + +### Automatic tab + +#### Presets + +Three presets set defaults for run aggressiveness: + +- **Fast**: lower processing volume, higher score threshold +- **Balanced**: middle-ground defaults +- **Detailed**: higher processing volume, lower score threshold + +If values are edited manually, the UI shows **Custom**. + +#### Country and source compatibility + +- Country selection affects which sources are available. +- UK-only sources are disabled for non-UK countries. +- Glassdoor can be enabled only when: + - selected country supports Glassdoor + - a **Glassdoor city** is set in Advanced settings + +Incompatible sources are disabled with explanatory tooltips. + +#### Advanced settings + +- **Resumes tailored** (`topN`) +- **Min suitability score** +- **Max jobs discovered** (run budget cap) +- **Glassdoor city** (required only for Glassdoor) + +#### Search terms + +- Add terms with Enter or commas. +- Multiple terms increase discovery breadth and runtime. +- At least one search term is required. + +#### Estimate and run gating + +The footer estimate shows expected discovered jobs and resume-processing range. + +`Start run now` is disabled when: + +- a run is already in progress +- required save/run work is still in progress +- no compatible sources are selected +- no search terms are present + +### Manual tab + +Manual mode opens direct import flow in the same modal. + +Use it when you already have a specific job description or link and do not want full discovery. + +For accepted input formats, inference behavior, and limits, see [Manual Import Extractor](/docs/next/extractors/manual). + +## Common problems + +### Start button stays disabled + +- Ensure at least one search term is present. +- Ensure at least one compatible source is selected. +- Wait for active save/run operations to finish. + +### Glassdoor cannot be enabled + +- Verify selected country supports Glassdoor. +- Set a Glassdoor city in Advanced settings. + +### Run takes longer than expected + +- Reduce term count. +- Use `Fast` preset or lower `Max jobs discovered`. +- Disable high-cost source combinations where acceptable. + +## Related pages + +- [Find Jobs and Apply Workflow](/docs/next/workflows/find-jobs-and-apply-workflow) +- [Manual Import Extractor](/docs/next/extractors/manual) +- [Orchestrator](/docs/next/features/orchestrator) +- [Overview](/docs/next/features/overview) diff --git a/docs-site/docs/features/reactive-resume.md b/docs-site/docs/features/reactive-resume.md new file mode 100644 index 0000000..dfe8e41 --- /dev/null +++ b/docs-site/docs/features/reactive-resume.md @@ -0,0 +1,220 @@ +--- +id: reactive-resume +title: Reactive Resume +description: Configure RxResume integration, base resume selection, and project inclusion behavior for PDF generation. +sidebar_position: 4 +--- + +## What it is + +Reactive Resume integration powers JobOps PDF generation. + +JobOps uses a selected RxResume base resume as the source of truth, then applies job-specific tailoring (summary, headline, skills, project visibility) before exporting a PDF. + +## Why it exists + +Most users need a repeatable resume pipeline: + +- one canonical resume source +- controlled project inclusion rules +- per-job tailored output without manual copy/paste + +Reactive Resume integration provides that workflow end-to-end. + +### Why JobOps uses RxResume (instead of building a new editor) + +RxResume is a mature, established resume product with strong PDF output quality. + +Key reasons: + +- ATS-friendly PDF generation is already excellent and battle-tested. +- The editor UX is strong and supports extensive user customization. +- It supports many themes out of the box. +- It has a JSON-native model (import/export), which is critical for JobOps automation. + +Because RxResume uses structured JSON, JobOps can safely apply LLM-driven updates to specific sections before generating PDFs. + +## Core concepts + +### Base resume + +Your **base resume** is selected in Settings and used for: + +- profile extraction +- project catalog extraction +- PDF generation + +If no base resume is selected, profile-dependent features and PDF generation cannot run. + +### Project catalog + +JobOps reads projects from `sections.projects.items` in the selected RxResume resume. + +Each project is identified by: + +- `id` +- `name` +- `description` +- `date` +- `visible` (visible in base resume) + +### Project selection controls + +The Settings UI supports 3 controls: + +- **Must Include**: always include these projects. +- **AI Selectable**: pool of projects AI can pick from. +- **Max Projects**: final cap for included projects. + +At generation time: + +1. Must-include projects are added first. +2. AI picks up to remaining slots from AI-selectable projects. +3. Final visible projects are applied to the generated resume. + +## Setup and configuration + +### 1) Configure RxResume credentials + +Configure in Settings: + +- `rxresumeEmail` +- `rxresumePassword` + +Or via environment variables: + +- `RXRESUME_EMAIL` +- `RXRESUME_PASSWORD` +- optional `RXRESUME_URL` (defaults to `https://v4.rxresu.me`) + +### 2) Select base resume + +In **Settings → Reactive Resume**: + +1. Click refresh to fetch resumes. +2. Select the template/base resume. +3. Save settings. + +### 3) Configure project behavior + +In the same section: + +1. Set `Max projects`. +2. Mark projects as **Must Include** where needed. +3. Mark remaining projects as **AI selectable**. +4. Save settings. + +## Runtime behavior + +### During PDF generation + +High-level flow: + +1. Load selected base resume from RxResume. +2. Apply tailored summary/headline/skills. +3. Compute final visible projects from your selection rules. +4. Create temporary resume in RxResume. +5. Export PDF. +6. Delete temporary resume. + +### What JobOps changes with AI + +Current AI-driven edits are intentionally scoped: + +- `summary` +- `headline/title` +- `skills` and keywords +- project **visibility** (enable/disable per project) + +## API reference + +```bash +# Get effective settings (includes resolved resumeProjects and base resume id) +curl "http://localhost:3001/api/settings" +``` + +```bash +# Save base resume and project controls +curl -X PATCH "http://localhost:3001/api/settings" \ + -H "content-type: application/json" \ + -d '{ + "rxresumeBaseResumeId": "resume_id_here", + "resumeProjects": { + "maxProjects": 4, + "lockedProjectIds": ["proj_a"], + "aiSelectableProjectIds": ["proj_b","proj_c","proj_d"] + } + }' +``` + +```bash +# List available RxResume resumes +curl "http://localhost:3001/api/settings/rx-resumes" +``` + +```bash +# Fetch projects from one RxResume resume +curl "http://localhost:3001/api/settings/rx-resumes//projects" +``` + +```bash +# Regenerate PDF for a job after changing settings or resume data +curl -X POST "http://localhost:3001/api/jobs//generate-pdf" +``` + +## Troubleshooting and FAQ + +### RxResume controls are disabled + +- Ensure RxResume credentials are configured. +- Save settings, then refresh resumes in the Reactive Resume section. + +### No resumes appear in dropdown + +- Confirm credentials are valid for `rxresu.me`/your configured RxResume URL. +- Confirm the selected RxResume account actually has resumes. + +### Project list is empty in settings + +- Root cause is usually the source resume on [rxresu.me](https://rxresu.me) having an empty **Projects** section. +- Add projects directly in RxResume first. +- Re-select/refresh the base resume in JobOps and regenerate the PDF. + +### Project checkboxes look wrong after changing base resume + +- Save after selecting the new base resume. +- Re-open Reactive Resume section and verify project IDs from that resume. +- Re-run PDF generation to apply the new project map. + +### Changes did not affect an already generated PDF + +- Settings changes apply to new generation runs. +- Regenerate PDFs for already-ready jobs. + +## Best practices + +- Keep base resume projects complete and up to date in RxResume. +- Use **Must Include** sparingly for cornerstone projects. +- Keep AI-selectable pool broad enough for job-specific relevance. +- After major resume edits, regenerate PDFs for active high-priority jobs. + +### Add “context projects” even if they are usually hidden + +The LLM only knows what exists in your resume data. + +That means there is real value in adding additional projects in RxResume, even if you keep them hidden by default: + +- They increase the AI’s context about your skills and range. +- They can be toggled on only when relevant to a role. + +Example: + +- If your main background is not Android, but you have one credible Android side project, include it in RxResume, but keep it hidden by default. +- For a mobile role, the AI can enable that project automatically based on the job description. + +## Related pages + +- [Settings](./settings) +- [Orchestrator](./orchestrator) +- [Ghostwriter](./ghostwriter) +- [Self-Hosting](../getting-started/self-hosting) diff --git a/docs-site/docs/features/settings.md b/docs-site/docs/features/settings.md new file mode 100644 index 0000000..3f36b44 --- /dev/null +++ b/docs-site/docs/features/settings.md @@ -0,0 +1,154 @@ +--- +id: settings +title: Settings +description: Configure models, webhooks, accounts, backup behavior, scoring, and safety controls. +sidebar_position: 2 +--- + +## What it is + +The Settings page is the control center for app-wide behavior. + +It lets you configure: + +- LLM provider and models +- Webhook destinations and secret +- Display and Ghostwriter defaults +- Service credentials and basic auth +- Reactive Resume project selection +- Backup and scoring rules +- Data-clearing actions in the Danger Zone + +## Why it exists + +Most teams want stable defaults for repeated workflows, without editing environment variables every time. + +Settings gives you runtime overrides for the key parts of discovery, scoring, tailoring, and post-application automation. + +## How to use it + +1. Open **Settings**. +2. Expand each section you want to change. +3. Update values and click **Save Changes**. +4. Re-run the workflow that uses those settings (for example pipeline runs, Ghostwriter, or resume tailoring) to verify behavior. + +## Section-by-section guide + +### Model + +- Choose provider (`openrouter`, `lmstudio`, `ollama`, `openai`, `gemini`) +- Set provider-specific base URL/API key when required +- Configure default model plus task-specific overrides: + - Scoring model + - Tailoring model + - Project-selection model + +### Webhooks + +- Pipeline status webhook: called on run completion/failure +- Job completion webhook: called when a job is marked applied +- Optional webhook secret (sent as bearer token) + +### Display Settings + +- Toggle visa sponsor badge visibility in job lists/details + +### Ghostwriter + +- Set global writing defaults: + - Tone + - Formality + - Constraints + - Do-not-use terms + +### Reactive Resume + +- Select a template/base resume +- Configure project selection behavior: + - Max projects + - Must-include projects + - AI-selectable projects + +### Environment & Accounts + +- Configure service accounts: + - RxResume email/password + - UKVisaJobs email/password +- Optional basic authentication for write operations + +### Backup + +- Enable/disable automatic daily backups +- Configure backup hour (UTC) and max retained backups +- Create or delete backups manually +- See [Database Backups](../getting-started/database-backups) for full backup/restore guidance. + +### Scoring Settings + +- Penalize missing salary data +- Set penalty amount +- Optional auto-skip threshold for low-score jobs + +### Danger Zone + +- Clear jobs by selected statuses +- Clear jobs below a score threshold +- Clear the full database + +## API examples + +```bash +# Get effective settings (defaults + overrides) +curl "http://localhost:3001/api/settings" +``` + +```bash +# Update settings overrides +curl -X PATCH "http://localhost:3001/api/settings" \ + -H "content-type: application/json" \ + -d '{ + "llmProvider": "openrouter", + "model": "openai/gpt-4.1-mini", + "chatStyleTone": "concise", + "showSponsorInfo": true + }' +``` + +```bash +# List and create backups (used by the Backup section) +curl "http://localhost:3001/api/backups" +curl -X POST "http://localhost:3001/api/backups" +``` + +## Common problems + +### Saved value does not seem to apply + +- Some settings apply only to new runs/actions after save. +- Re-run scoring/tailoring/pipeline to validate effect. + +### RxResume controls are disabled + +- Configure RxResume credentials in Environment & Accounts first. +- Then refresh available resumes from the Reactive Resume section. + +### RxResume projects look empty in the RxResume UI + +- Root cause: your resume on [rxresu.me](https://rxresu.me) has an empty **Projects** section. +- Fix in RxResume first: add project entries to the base resume you selected in Settings. +- Then return to JobOps, refresh/select the same base resume in **Reactive Resume**, and regenerate the PDF. +- JobOps preserves current visibility state, but it cannot create missing project content if the source resume has no projects. + +### Webhook calls fail + +- Verify URL reachability from the server host. +- Confirm auth expectations on the receiver side (including secret/bearer token). + +## Related pages + +- [Reactive Resume](./reactive-resume) +- [Database Backups](../getting-started/database-backups) +- [Overview](./overview) +- [Orchestrator](./orchestrator) +- [Ghostwriter](./ghostwriter) +- [Self-Hosting](../getting-started/self-hosting) diff --git a/docs-site/docs/features/visa-sponsors.md b/docs-site/docs/features/visa-sponsors.md new file mode 100644 index 0000000..e97d749 --- /dev/null +++ b/docs-site/docs/features/visa-sponsors.md @@ -0,0 +1,74 @@ +--- +id: visa-sponsors +title: Visa Sponsors +description: Search the UK licensed sponsor register and use sponsor matches in your job workflow. +sidebar_position: 4 +--- + +## What it is + +The Visa Sponsors page lets you search the UK Home Office licensed sponsor register from inside JobOps. + +For each company, it shows: + +- Match score against your query +- Company location (when available) +- Licensed routes and type/rating details +- Last data refresh time and sponsor count + +## Why it exists + +Many roles require sponsorship-ready employers. This page helps you quickly validate whether a target company appears on the official sponsor list, so you can prioritize applications and sourcing terms. + +## How to use it + +1. Open **Visa Sponsors** in the app. +2. Enter a company name in the search box. +3. Select a result to view sponsor details. +4. Use the score and route details to decide whether to prioritize that employer. + +### Refresh schedule + +- Automatic update runs daily at about **02:00** (server local time). +- Use the download/update button in the page header to fetch the latest register immediately. + +### API examples + +```bash +# Search sponsors +curl -X POST http://localhost:3001/api/visa-sponsors/search \ + -H "content-type: application/json" \ + -d '{"query":"Monzo","limit":100,"minScore":20}' +``` + +```bash +# Get one organization's entries (all licensed routes) +curl "http://localhost:3001/api/visa-sponsors/organization/Monzo%20Bank%20Ltd" +``` + +```bash +# Trigger manual refresh +curl -X POST http://localhost:3001/api/visa-sponsors/update +``` + +## Common problems + +### No results found + +- Try alternate legal names (`Ltd`, `Limited`, abbreviations). +- Reduce spelling strictness by searching a shorter core name. + +### Sponsor data is empty + +- Run a manual refresh with the header update button (or `POST /api/visa-sponsors/update`). +- Check that the server can reach `gov.uk` and `assets.publishing.service.gov.uk`. + +### Company appears once but has multiple routes + +- Open the detail panel for that company; route/type entries are shown there. + +## Related pages + +- [Orchestrator](/docs/next/features/orchestrator) +- [Post-Application Tracking](/docs/next/features/post-application-tracking) +- [Self-Hosting](/docs/next/getting-started/self-hosting) diff --git a/docs-site/docs/getting-started/database-backups.md b/docs-site/docs/getting-started/database-backups.md new file mode 100644 index 0000000..c49991c --- /dev/null +++ b/docs-site/docs/getting-started/database-backups.md @@ -0,0 +1,127 @@ +--- +id: database-backups +title: Database Backups +description: Configure, run, and restore JobOps database backups. +sidebar_position: 2 +--- + +## What this covers + +This page is about database backups: + +- automatic backup schedule +- manual backup creation/deletion +- retention behavior +- restore workflow +- backup troubleshooting + +## Backup behavior + +JobOps stores backups in the same data directory as `jobs.db`. + +Two backup types exist: + +- **Automatic** backups +- **Manual** backups + +### Automatic backups + +- Scheduled daily. +- Filename format: `jobs_YYYY_MM_DD.db` +- Schedule hour is configured in Settings (**UTC hour**). +- Automatic retention is capped by `backupMaxCount`. +- If today’s automatic backup already exists, JobOps skips creating a duplicate. + +### Manual backups + +- Triggered from Settings or `POST /api/backups`. +- Filename format: `jobs_manual_YYYY_MM_DD_HH_MM_SS.db` +- If a filename collision occurs, JobOps appends `_1`, `_2`, etc. +- Manual backups are **not** auto-deleted by automatic retention cleanup. + +## Configure backups + +In **Settings → Backup**: + +1. Enable automatic backups. +2. Set backup hour (`0-23`, UTC). +3. Set max automatic backups to keep (`1-5`). +4. Save settings. + +## API reference + +```bash +# List backups + next scheduled run time +curl "http://localhost:3001/api/backups" +``` + +```bash +# Create a manual backup +curl -X POST "http://localhost:3001/api/backups" +``` + +```bash +# Delete a specific backup +curl -X DELETE "http://localhost:3001/api/backups/jobs_manual_2026_02_15_10_20_30.db" +``` + +```bash +# Update backup settings via Settings API +curl -X PATCH "http://localhost:3001/api/settings" \ + -H "content-type: application/json" \ + -d '{ + "backupEnabled": true, + "backupHour": 2, + "backupMaxCount": 5 + }' +``` + +## Restore workflow + +To restore from a backup: + +1. Stop JobOps. +2. Locate backup files in your data directory. +3. Copy the chosen backup over the main DB file (`jobs.db`). +4. Start JobOps. +5. Verify jobs/runs in the UI. + +Example shell flow: + +```bash +# Example only: adjust paths for your setup +cp /path/to/data/jobs_manual_2026_02_15_10_20_30.db /path/to/data/jobs.db +``` + +## Troubleshooting + +### Backups are not running automatically + +- Confirm `backupEnabled` is true. +- Confirm backup hour is set as intended (UTC, not local time). +- Verify the app process is running at scheduled time. + +### `POST /api/backups` fails + +- Confirm the data directory and `jobs.db` are writable/readable. +- Confirm `jobs.db` exists. +- In demo mode, manual backup creation is blocked. + +### Cannot delete a backup + +- Filename must match valid backup patterns. +- Invalid names and missing files return errors. + +### Next scheduled time is null + +- Automatic backups are currently disabled. + +## Notes + +- Backup cleanup applies only to automatic backups. +- Manual backups stay until you delete them. + +## Related pages + +- [Settings](../features/settings) +- [Self-Hosting](./self-hosting) diff --git a/docs-site/docs/intro.md b/docs-site/docs/intro.md index 0d32bf0..09b178c 100644 --- a/docs-site/docs/intro.md +++ b/docs-site/docs/intro.md @@ -10,40 +10,102 @@ Welcome to the JobOps documentation. This site contains guides for setup, config ## Getting Started -- **[Self-Hosting Guide](/docs/getting-started/self-hosting)** +- **[Self-Hosting Guide](/docs/next/getting-started/self-hosting)** - Docker setup instructions - Gmail OAuth configuration for email tracking - Environment variables reference - Demo mode deployment +- **[Database Backups](/docs/next/getting-started/database-backups)** + - Automatic backup scheduling and retention + - Manual backup creation/deletion + - Restore workflow and troubleshooting + +## Workflows + +- **[Find Jobs and Apply Workflow](/docs/next/workflows/find-jobs-and-apply-workflow)** + - Run pipeline first, then review discovered and ready jobs + - Use fit assessment and score to prioritize applications + - Mark jobs as applied to trigger webhooks and analytics + +- **[Post-Application Workflow](/docs/next/workflows/post-application-workflow)** + - Track events manually for direct control + - Or configure automatic Gmail sync and inbox review + - Move confirmed updates into in-progress tracking + ## Feature Documentation -- **[Orchestrator](/docs/features/orchestrator)** +- **[Orchestrator](/docs/next/features/orchestrator)** - Job states explained (`discovered`, `ready`, `applied`, etc.) - The ready flow (manual vs auto) - PDF generation and regeneration - Post-application tracking overview -- **[Ghostwriter](/docs/features/ghostwriter)** +- **[Pipeline Run](/docs/next/features/pipeline-run)** + - Run modal controls (`Automatic` vs `Manual`) + - Presets, source/country compatibility, and advanced settings + - Run estimate and start conditions + +- **[Job Search Bar](/docs/next/features/job-search-bar)** + - Open with `Cmd+K` / `Ctrl+K` or the Search button + - Fuzzy search across title, company, and location + - Use `@status` lock syntax to scope results quickly + +- **[Keyboard Shortcuts](/docs/next/features/keyboard-shortcuts)** + - Full Jobs-page shortcut reference by context + - `?` shortcut help dialog and `Control` hint bar behavior + - Tab-specific actions like skip, move to ready, and mark applied + +- **[Multi-Select and Bulk Actions](/docs/next/features/multi-select-and-bulk-actions)** + - Select many jobs using row checkboxes or select-all + - Run bulk move, skip, and rescore actions from the floating action bar + - Keyboard support for select, clear, and fast bulk move-to-ready + +- **[Settings](/docs/next/features/settings)** + - LLM provider/model and task-specific overrides + - Webhooks, service accounts, and basic auth controls + - Backup scheduling, scoring thresholds, and danger-zone cleanup tools + +- **[Reactive Resume](/docs/next/features/reactive-resume)** + - Base resume selection and RxResume integration + - Project inclusion controls (must-include, AI-selectable, max) + - PDF generation behavior and troubleshooting + +- **[Applications Overview](/docs/next/features/overview)** + - Applications-per-day trend + - Conversion analytics and funnel + - Duration window controls (`7d`, `14d`, `30d`, `90d`) + +- **[In Progress Board](/docs/next/features/in-progress-board)** + - Pre-application vs post-application workflow split + - Kanban tracking for higher-attention opportunities + - Drag-and-drop stage management + +- **[Ghostwriter](/docs/next/features/ghostwriter)** - One persistent conversation per job - Streaming responses, stop, and regenerate - Markdown rendering and drawer behavior - Writing style settings impact -- **[Post-Application Tracking](/docs/features/post-application-tracking)** +- **[Post-Application Tracking](/docs/next/features/post-application-tracking)** - How the Smart Router AI works - Gmail integration setup - Using the Tracking Inbox - Privacy and security details - API reference +- **[Visa Sponsors](/docs/next/features/visa-sponsors)** + - Search licensed UK sponsor organizations + - Review company routes and sponsor ratings + - Trigger manual data refresh + ## Extractors -- **[Extractors Overview](/docs/extractors/overview)** -- **[Gradcracker](/docs/extractors/gradcracker)** -- **[UKVisaJobs](/docs/extractors/ukvisajobs)** -- **[JobSpy](/docs/extractors/jobspy)** -- **[Manual Import](/docs/extractors/manual)** +- **[Extractors Overview](/docs/next/extractors/overview)** +- **[Gradcracker](/docs/next/extractors/gradcracker)** +- **[UKVisaJobs](/docs/next/extractors/ukvisajobs)** +- **[JobSpy](/docs/next/extractors/jobspy)** +- **[Manual Import](/docs/next/extractors/manual)** ## Quick Reference diff --git a/docs-site/docs/reference/documentation-style-guide.md b/docs-site/docs/reference/documentation-style-guide.md index 63ded16..0ddc409 100644 --- a/docs-site/docs/reference/documentation-style-guide.md +++ b/docs-site/docs/reference/documentation-style-guide.md @@ -27,7 +27,9 @@ Every doc should include: - Prefer concrete steps over abstract prose. - Provide copy-pasteable examples. - State defaults and constraints explicitly. -- Link related docs using `/docs/...` URLs. +- Use absolute `/docs/...` URLs and include the version segment when needed. +- For current docs, use `/docs/next/...` links. +- For versioned docs, link within that version (for example `/docs/...` in `version-0.1.20`). ## PR expectations diff --git a/docs-site/docs/reference/faq.md b/docs-site/docs/reference/faq.md index 3d9658d..db31800 100644 --- a/docs-site/docs/reference/faq.md +++ b/docs-site/docs/reference/faq.md @@ -9,10 +9,6 @@ sidebar_position: 1 Yes. The docs static build is bundled and served locally at `/docs`. -## Do I need internet access to read docs after deployment? - -No, for bundled docs pages. - ## How are docs versions managed? Docs are versioned using Docusaurus versions, intended to map to release tags. @@ -21,6 +17,14 @@ Docs are versioned using Docusaurus versions, intended to map to release tags. Edit files under `docs-site/docs` for latest docs. -## Are old markdown files in `documentation/` still canonical? +## What does this cost in practice? -No. `docs-site/docs` is the source of truth after migration. +Real-world reference: from early December 2025 to mid-February 2026, with heavy usage and testing (about 10 to 15 applications per day), easily more than 3000 jobs scored, total LLM spend was about **$12 USD** using Gemini 3 Flash through OpenRouter. + +Cost varies by: + +- selected model/provider +- prompt volume and size +- number of jobs scored/tailored per run + +For this workload, Gemini 3 Flash has been low-cost while still producing high-quality outputs. diff --git a/docs-site/docs/workflows/find-jobs-and-apply-workflow.md b/docs-site/docs/workflows/find-jobs-and-apply-workflow.md new file mode 100644 index 0000000..779324a --- /dev/null +++ b/docs-site/docs/workflows/find-jobs-and-apply-workflow.md @@ -0,0 +1,96 @@ +--- +id: find-jobs-and-apply-workflow +title: Find Jobs and Apply Workflow +description: Recommended end-to-end pre-application workflow from pipeline run to marking jobs as applied. +sidebar_position: 1 +--- + +## Goal + +This guide documents the main intended pre-application workflow in JobOps. + +If you follow this order, you get the strongest results from discovery, scoring, tailoring, and tracking. + +## Recommended flow (in order) + +### 1) Run a pipeline first + +From the **Jobs** page, use the top-right pipeline/run control. + +What this does: + +- fetches jobs from enabled extractors +- scores relevance against your resume/profile +- optionally tailors top jobs and prepares PDFs + +Important: + +- Some scrapers are slower and can take significant time. +- Larger scrape ranges and more sources increase run duration. + +### 2) Configure pipeline advanced settings + +In pipeline advanced settings, configure: + +- how many jobs to discover (approximate target) +- minimum score threshold for tailoring +- how many jobs should be tailored/generated + +This directly controls how many jobs appear downstream in `discovered` and `ready`. + +### 3) Review the `Discovered` column + +After the run, `discovered` is populated with jobs found by extractors. + +For each discovered job: + +- review the suitability score +- read the AI fit justification in **Fit Assessment** +- decide whether the opportunity is worth advancing + +### 4) Work from `Ready` for applications + +`ready` jobs are the primary application queue. + +These jobs already have tailored PDFs generated for the specific job description, using the workflow described in [Reactive Resume](../features/reactive-resume). + +At this stage: + +1. Open job details. +2. Download the tailored PDF. +3. Submit your application externally. + +### 5) Mark jobs as applied in JobOps + +After submitting, return to JobOps and mark the job as `applied`. + +Effects: + +- job moves to the `applied` state +- configured completion webhook(s) are triggered +- job is included in overview analytics + +This completes the detailed pre-application loop. + +## What happens next + +Once a job is marked `applied`, it becomes part of: + +- pipeline outcome analytics on [Overview](../features/overview) +- optional post-application workflows (inbox/review routing) + +## Practical tips + +- Start with conservative run sizes while tuning sources. +- Increase tailored-job count only after score thresholds feel calibrated. +- Expect scraper runtime variance by source. +- Keep resume/project context up to date so scoring/tailoring quality stays high. + +## Related pages + +- [Orchestrator](../features/orchestrator) +- [Reactive Resume](../features/reactive-resume) +- [Settings](../features/settings) +- [Overview](../features/overview) +- [Post-Application Workflow](./post-application-workflow) +- [Post-Application Tracking](../features/post-application-tracking) diff --git a/docs-site/docs/workflows/post-application-workflow.md b/docs-site/docs/workflows/post-application-workflow.md new file mode 100644 index 0000000..c4d8e8f --- /dev/null +++ b/docs-site/docs/workflows/post-application-workflow.md @@ -0,0 +1,141 @@ +--- +id: post-application-workflow +title: Post-Application Workflow +description: Track post-application progress manually, or configure automatic Gmail syncing and inbox review. +sidebar_position: 2 +--- + +## Goal + +After a job is marked `applied`, use this workflow to track what happens next. + +You have two valid paths: + +- **Manual tracking**: update stages/events yourself. +- **Automatic Gmail sync**: let email ingestion route events into inbox/review flow. + +## Option A: Manual event tracking + +Use this when you want explicit, hands-on control for each job. + +### Manual flow + +1. Open an `applied` or `in_progress` job. +2. Record stage progress as events (screening, interview, offer, closed, etc.). +3. Keep notes/outcomes current as conversations progress. +4. Use In Progress Board for high-attention jobs in later stages. + +### API example (manual stage transition) + +```bash +curl -X POST "http://localhost:3001/api/jobs//stages" \ + -H "content-type: application/json" \ + -d '{ + "toStage": "technical_interview", + "metadata": { + "actor": "user", + "eventType": "status_update", + "eventLabel": "Moved to Technical Interview" + } + }' +``` + +## Option B: Automatic Gmail syncing + +Use this when you want JobOps to ingest recruitment emails and suggest/apply updates. + +### High-level flow + +1. Connect Gmail provider. +2. Run sync (or scheduled sync, depending on setup). +3. Smart router scores message-to-job match. +4. High confidence updates are auto-linked. +5. Mid/low confidence items go to inbox for review. + +### Configure Gmail sync + +Set OAuth variables: + +```bash +GMAIL_OAUTH_CLIENT_ID=... +GMAIL_OAUTH_CLIENT_SECRET=... +GMAIL_OAUTH_REDIRECT_URI=https://your-domain.com/oauth/gmail/callback +``` + +Then in app: + +1. Open Tracking Inbox / provider controls. +2. Start Gmail OAuth. +3. Complete consent. +4. Trigger sync and review inbox items. + +### API examples (Gmail path) + +```bash +# Start OAuth +curl "http://localhost:3001/api/post-application/providers/gmail/oauth/start?accountKey=default" +``` + +```bash +# Exchange authorization code +curl -X POST "http://localhost:3001/api/post-application/providers/gmail/oauth/exchange" \ + -H "content-type: application/json" \ + -d '{"accountKey":"default","state":"","code":""}' +``` + +```bash +# Trigger provider sync action +curl -X POST "http://localhost:3001/api/post-application/providers/gmail/actions/sync" \ + -H "content-type: application/json" \ + -d '{"accountKey":"default","maxMessages":100,"searchDays":30}' +``` + +```bash +# Review inbox +curl "http://localhost:3001/api/post-application/inbox?provider=gmail&accountKey=default" +``` + +```bash +# Approve inbox item +curl -X POST "http://localhost:3001/api/post-application/inbox//approve" \ + -H "content-type: application/json" \ + -d '{"provider":"gmail","accountKey":"default"}' +``` + +```bash +# Deny inbox item +curl -X POST "http://localhost:3001/api/post-application/inbox//deny" \ + -H "content-type: application/json" \ + -d '{"provider":"gmail","accountKey":"default"}' +``` + +## Which option should you use? + +- Choose **manual** if your volume is low and you want direct control. +- Choose **automatic Gmail sync** if your volume is higher and you want less repetitive triage. +- Many users combine both: auto-sync first, manual adjustments for edge cases. + +## Common problems + +### Gmail connected but no messages appear + +- Verify OAuth credentials and redirect URI. +- Confirm you are syncing the intended account key. +- Check search window (`searchDays`) and message cap (`maxMessages`). + +### Wrong job matched + +- Expected in lower-confidence buckets. +- Deny incorrect inbox items and apply manual stage updates where needed. + +### I prefer not to grant Gmail access + +- Use the manual tracking path only. +- The post-application workflow still works without Gmail integration. + +## Related pages + +- [Find Jobs and Apply Workflow](./find-jobs-and-apply-workflow) +- [Post-Application Tracking](../features/post-application-tracking) +- [In Progress Board](../features/in-progress-board) +- [Overview](../features/overview) diff --git a/docs-site/sidebars.ts b/docs-site/sidebars.ts index dcaab0f..e8ed354 100644 --- a/docs-site/sidebars.ts +++ b/docs-site/sidebars.ts @@ -8,13 +8,30 @@ const sidebars: SidebarsConfig = { label: "Getting Started", items: ["getting-started/self-hosting"], }, + { + type: "category", + label: "Workflows", + items: [ + "workflows/find-jobs-and-apply-workflow", + "workflows/post-application-workflow", + ], + }, { type: "category", label: "Core Features", items: [ + "features/overview", + "features/pipeline-run", + "features/job-search-bar", + "features/keyboard-shortcuts", + "features/multi-select-and-bulk-actions", "features/orchestrator", + "features/settings", + "features/reactive-resume", + "features/in-progress-board", "features/ghostwriter", "features/post-application-tracking", + "features/visa-sponsors", ], }, { @@ -33,6 +50,7 @@ const sidebars: SidebarsConfig = { label: "Self-Hosting & Ops", items: [ "getting-started/self-hosting", + "getting-started/database-backups", "troubleshooting/common-problems", ], }, diff --git a/docs-site/versioned_docs/version-0.1.20/extractors/overview.md b/docs-site/versioned_docs/version-0.1.20/extractors/overview.md index aea8aa2..2655b34 100644 --- a/docs-site/versioned_docs/version-0.1.20/extractors/overview.md +++ b/docs-site/versioned_docs/version-0.1.20/extractors/overview.md @@ -5,7 +5,27 @@ description: Technical index of supported extractors and how they work. sidebar_position: 1 --- -Technical breakdowns of each extractor: +This page helps you choose the right extractor for your run, understand key constraints, and navigate to detailed technical guides. + +## Extractor chooser + +| Extractor | Best use case | Core constraints/dependencies | Notable controls | Output/behavior notes | +| --- | --- | --- | --- | --- | +| [Gradcracker](/docs/extractors/gradcracker) | UK graduate roles from Gradcracker | Crawling stability depends on page structure and anti-bot behavior; tuned for low concurrency | `GRADCRACKER_SEARCH_TERMS`, `GRADCRACKER_MAX_JOBS_PER_TERM`, `JOBOPS_SKIP_APPLY_FOR_EXISTING` | Scrapes listing metadata, then detail pages and apply URL resolution | +| [JobSpy](/docs/extractors/jobspy) | Multi-source discovery (Indeed, LinkedIn, Glassdoor) | Requires Python wrapper execution per term; source availability and quality vary by site/location | `JOBSPY_SITES`, `JOBSPY_SEARCH_TERMS`, `JOBSPY_RESULTS_WANTED`, `JOBSPY_HOURS_OLD`, `JOBSPY_LINKEDIN_FETCH_DESCRIPTION` | Produces JSON per term, then orchestrator normalizes and de-duplicates by `jobUrl` | +| [UKVisaJobs](/docs/extractors/ukvisajobs) | UK visa sponsorship-focused roles | Requires authenticated session and periodic token/cookie refresh | `UKVISAJOBS_EMAIL`, `UKVISAJOBS_PASSWORD`, `UKVISAJOBS_MAX_JOBS`, `UKVISAJOBS_SEARCH_KEYWORD` | API pagination + dataset output; orchestrator de-dupes and may fetch missing descriptions | +| [Manual Import](/docs/extractors/manual) | One-off jobs not covered by scrapers | Inference quality depends on model/provider and input quality; some URLs cannot be fetched reliably | App/API endpoints (`/api/manual-jobs/infer`, `/api/manual-jobs/import`) | Accepts text/HTML/URL, runs inference, then saves and scores job after review | + +## Which extractor should I use? + +- Use **JobSpy** for broad first-pass sourcing across common boards. +- Use **Gradcracker** when targeting graduate pipelines in the UK. +- Use **UKVisaJobs** for sponsorship-specific UK searches. +- Use **Manual Import** when you already have a specific posting and need direct import. + +Many runs combine sources: broad discovery first, then manual import for high-priority jobs that scraping misses. + +## Related extractor docs - [Gradcracker](/docs/extractors/gradcracker) - [JobSpy](/docs/extractors/jobspy) diff --git a/docs-site/versioned_docs/version-0.1.20/features/ghostwriter.md b/docs-site/versioned_docs/version-0.1.20/features/ghostwriter.md index 2c03ac6..fb4a457 100644 --- a/docs-site/versioned_docs/version-0.1.20/features/ghostwriter.md +++ b/docs-site/versioned_docs/version-0.1.20/features/ghostwriter.md @@ -5,30 +5,37 @@ description: Context-aware per-job AI chat assistant behavior and API surface. sidebar_position: 2 --- -Ghostwriter is the per-job AI chat assistant in JobOps. +## What it is -## What it is for +Ghostwriter is the per-job AI chat assistant in JobOps. Ghostwriter uses: -- Current job description and metadata -- Reduced profile snapshot -- Global writing style settings +- current job description and metadata +- reduced profile snapshot +- global writing style settings + +The UI behavior is one persistent conversation per job, shown in the right-side drawer from job details. + +## Why it exists + +Ghostwriter helps you produce job-specific writing quickly while preserving consistency with your profile and style settings. Typical use cases: -- Role-specific answer drafting -- Cover letter and outreach drafts -- Interview prep tied to the JD -- Rephrasing with tone constraints +- role-specific answer drafting +- cover letter and outreach drafts +- interview prep tied to the job description +- rephrasing with tone constraints -## Where it appears +## How to use it -- Available from job details in `discovered` and `ready` -- Right-side drawer UX -- One persistent conversation per job +1. Open a job in `discovered` or `ready`. +2. Open the Ghostwriter drawer. +3. Enter your prompt and stream a response. +4. Stop or regenerate responses when needed. -## Writing style settings impact +### Writing style settings impact Global settings affecting generations: @@ -44,14 +51,14 @@ Defaults: - Constraints: empty - Do-not-use terms: empty -## Context and safety model +### Context and safety model - Job snapshot is truncated to fit prompt budget. - Profile snapshot includes relevant slices only. - System prompt enforces read-only assistant behavior. - Logging stores metadata, not full prompt/response dumps. -## API surface +### API surface - `GET /api/jobs/:id/chat/messages` - `POST /api/jobs/:id/chat/messages` (streaming) @@ -59,3 +66,26 @@ Defaults: - `POST /api/jobs/:id/chat/messages/:assistantMessageId/regenerate` (streaming) Compatibility thread endpoints remain, but UI behavior is one thread per job. + +## Common problems + +### Responses feel too generic + +- Verify the job description is complete and current. +- Confirm style constraints in Settings are specific enough. + +### Generation quality is lower than expected + +- Check model/provider configuration in Settings. +- Tighten prompts with explicit output intent (for example, "3 bullet points for recruiter outreach"). + +### Missing context in answers + +- Update profile data and relevant project details used by Ghostwriter context. +- Regenerate after updating job notes/description. + +## Related pages + +- [Orchestrator](/docs/features/orchestrator) +- [Post-Application Tracking](/docs/features/post-application-tracking) +- [Troubleshooting](/docs/troubleshooting/common-problems) diff --git a/docs-site/versioned_docs/version-0.1.20/features/orchestrator.md b/docs-site/versioned_docs/version-0.1.20/features/orchestrator.md index 9138f20..d9fd609 100644 --- a/docs-site/versioned_docs/version-0.1.20/features/orchestrator.md +++ b/docs-site/versioned_docs/version-0.1.20/features/orchestrator.md @@ -5,88 +5,114 @@ description: Job states, ready flow, and PDF generation/regeneration behavior. sidebar_position: 1 --- -This guide explains job states, how jobs become ready, and how PDF generation works. +## What it is -## Job states +The Orchestrator is the primary jobs workspace in JobOps. -- `discovered`: Found by crawler/import, not tailored yet. -- `processing`: Tailoring and/or PDF generation in progress. -- `ready`: Tailored PDF generated and ready to apply. -- `applied`: Marked as applied. -- `skipped`: Explicitly excluded from active queue. -- `expired`: Deadline passed. +It controls: -## Intended ready flow +- job lifecycle states +- manual and automatic ready flow +- PDF generation and regeneration +- handoff to post-application tracking -### 1) Manual flow +Job states: -1. Job starts in `discovered`. -2. Open in Discovered panel and choose Tailor. -3. Edit JD/tailored fields/project picks. -4. Click **Finalize & Move to Ready**. +- `discovered`: found by crawler/import, not tailored yet +- `processing`: tailoring and/or PDF generation in progress +- `ready`: tailored PDF generated and ready to apply +- `applied`: marked as applied +- `skipped`: explicitly excluded from active queue +- `expired`: deadline passed -### 2) Auto flow +## Why it exists -1. Pipeline scores discovered jobs. -2. Top jobs above threshold are auto-processed. -3. Jobs move directly to `ready` with generated PDFs. +Orchestrator centralizes the transition from discovered opportunities to application-ready artifacts. -## Ghostwriter +It exists to ensure: + +- a consistent path from discovery to tailored output +- clear status transitions across manual and automated workflows +- predictable regeneration behavior when job data changes + +## How to use it + +### Intended ready flow + +1. Manual flow: + 1. Job starts in `discovered`. + 2. Open the job and choose Tailor. + 3. Edit JD/tailored fields/project picks. + 4. Click **Finalize & Move to Ready**. +2. Auto flow: + 1. Pipeline scores discovered jobs. + 2. Top jobs above threshold are auto-processed. + 3. Jobs move directly to `ready` with generated PDFs. + +### Ghostwriter availability Ghostwriter is available in `discovered` and `ready` job views. For details, see [Ghostwriter](/docs/features/ghostwriter). -## Generating PDFs (first time) +### Generating PDFs PDF generation uses: -- Base resume selected from RxResume -- Job description -- Tailored summary/headline/skills/projects +- base resume selected from RxResume +- job description +- tailored summary/headline/skills/projects Common paths: -- **Discovered → Tailor → Finalize** - - `POST /api/jobs/:id/process` -- **Ready → Regenerate PDF** - - `POST /api/jobs/:id/generate-pdf` +- Discovered to finalization: `POST /api/jobs/:id/process` +- Ready regeneration: `POST /api/jobs/:id/generate-pdf` -## Regenerating PDFs after edits +### Regenerating PDFs after edits (copy-pasteable examples) If JD or tailoring changes, regenerate PDF to keep output in sync. -### API flow - ```bash -PATCH /api/jobs/:id -{ - "jobDescription": "", - "tailoredSummary": "", - "tailoredHeadline": "", - "tailoredSkills": "[{\"name\":\"Backend\",\"keywords\":[\"TypeScript\",\"Node.js\"]}]", - "selectedProjectIds": "p1,p2" -} +curl -X PATCH "http://localhost:3001/api/jobs/" \ + -H "content-type: application/json" \ + -d '{ + "jobDescription": "", + "tailoredSummary": "", + "tailoredHeadline": "", + "tailoredSkills": [{"name":"Backend","keywords":["TypeScript","Node.js"]}], + "selectedProjectIds": "p1,p2" + }' ``` ```bash -POST /api/jobs/:id/summarize?force=true -POST /api/jobs/:id/generate-pdf +curl -X POST "http://localhost:3001/api/jobs//summarize?force=true" +curl -X POST "http://localhost:3001/api/jobs//generate-pdf" ``` -## Post-application tracking - -For inbox routing flow and setup, see [Post-Application Tracking](/docs/features/post-application-tracking). - -## Notes and gotchas - -- `processing` is transient. On PDF failure, job reverts to `discovered`. -- PDFs are served at `/pdfs/resume_.pdf` with cache-bust on `updatedAt`. -- `skipped`/`applied` jobs can be reopened by patching `status` to `discovered`. - -## External payload and sanitization defaults +### External payload and sanitization defaults - LLM prompts send minimized profile/job fields. - Webhooks are sanitized and whitelisted by default. - Logs and error details are redacted/truncated by default. - Correlation fields include `requestId`, and when available `pipelineRunId` and `jobId`. + +## Common problems + +### Job is stuck in `processing` + +- `processing` is transient; failures generally revert the job to `discovered`. +- Check run logs and retry generation. + +### PDF does not reflect recent edits + +- Run summarize with `force=true` after changing the JD/tailoring. +- Regenerate PDF after summarize completes. + +### Reopen skipped/applied jobs + +- Patch `status` back to `discovered` to return the job to the active queue. + +## Related pages + +- [Ghostwriter](/docs/features/ghostwriter) +- [Post-Application Tracking](/docs/features/post-application-tracking) diff --git a/docs-site/versioned_docs/version-0.1.20/reference/documentation-style-guide.md b/docs-site/versioned_docs/version-0.1.20/reference/documentation-style-guide.md index 63ded16..e69de29 100644 --- a/docs-site/versioned_docs/version-0.1.20/reference/documentation-style-guide.md +++ b/docs-site/versioned_docs/version-0.1.20/reference/documentation-style-guide.md @@ -1,34 +0,0 @@ ---- -id: documentation-style-guide -title: Documentation Style Guide -description: Standards for writing user-facing docs in this repository. -sidebar_position: 2 ---- - -Use this structure for feature pages: - -1. **What it is** -2. **Why it exists** -3. **How to use it** -4. **Common problems** -5. **Related pages** - -## Frontmatter requirements - -Every doc should include: - -- `id` -- `title` -- `description` -- `sidebar_position` - -## Writing rules - -- Prefer concrete steps over abstract prose. -- Provide copy-pasteable examples. -- State defaults and constraints explicitly. -- Link related docs using `/docs/...` URLs. - -## PR expectations - -Any user-visible behavior change should include matching docs updates.