Shaheer Sarfaraz 05f1c62de2
Auto save project selection bug (#134)
* fix(tailoring): remove auto-sync effect causing race conditions

Remove the problematic useEffect that was syncing incoming job data
automatically. The effect caused race conditions where user edits were
overwritten after auto-save completed. Now, state only resets when the
job ID changes (user switches to a different job). User edits persist
until explicitly saved.

Fixes #133

* fix(tailoring): remove auto-save from tailor mode

Remove the 1500ms auto-save timeout that was causing race conditions
with the state sync. Users must now explicitly save changes via the
Save Selection button or finalize to persist changes.

* refactor(tailoring): remove draft status state and UI

Remove the draftStatus state and related UI elements that showed
saving/saved/unsaved status. With auto-save removed, this status
indicator is no longer needed. Users now explicitly save via buttons.

* test(tailoring): remove auto-save test

Remove the test that verified auto-save behavior since auto-save
has been removed from the tailor mode. Users now explicitly save
via the Finalize button.

* refactor(tailoring): remove dead focus tracking code

Remove the activeField state and all related focus/blur tracking that
was orphaned after removing auto-sync. The focus tracking was only
used to prevent the auto-sync effect from running while editing.

Changes:
- Remove TailoringActiveField type export
- Remove activeField state and setActiveField from useTailoringDraft
- Remove handleFieldBlur callback from TailoringWorkspace
- Remove onFieldFocus/onFieldBlur props and handlers from TailoringSections

39 lines of dead code removed.

* docs(tailoring): clarify save behavior comment

Update comment to distinguish between editor mode (Save Selection
button) and tailor mode (only persists on finalize). Addresses
review feedback.

* docs(tailoring): clarify useEffect dependencies

Add note explaining why 'job' is included in dependencies despite
the effect being guarded by job.id check. Addresses review feedback
about dependency array clarity.

* fix(tailoring): sync server-normalized values after save

Update persistCurrent and saveChanges to use the returned job from
api.updateJob and call applyIncomingDraft. This ensures local state
stays in sync with server-normalized values (e.g., trimmed fields).

Also removes unused markCurrentAsSaved dependency.

* refactor(tailoring): simplify draft sync effect

Remove unused save snapshot helpers and stop exposing them from the
hook. Track the latest job in a ref and only sync drafts when the job
id changes to avoid unnecessary effect runs while keeping data
correctness.

Addresses review feedback on dependency churn and dead API surface.
2026-02-11 16:18:17 +00:00
2026-02-02 21:30:14 +00:00
2026-02-08 00:19:26 +00:00
2026-02-02 21:30:14 +00:00
2026-01-25 13:34:16 +00:00
2026-02-02 21:30:14 +00:00
2026-01-17 02:53:31 +00:00
2026-02-10 22:13:05 +00:00

JobOps

AI-powered job discovery and application pipeline. Automatically finds jobs, scores them against your profile, and generates tailored resumes.

Workflow

  1. Search: Scrapes Gradcracker, Indeed, LinkedIn, Glassdoor, and UK Visa Sponsorship jobs.
  2. Score: AI ranks jobs by suitability using the configured LLM provider (OpenRouter by default).
  3. Tailor: Generates a custom resume summary for top-tier matches.
  4. Export: Uses RxResume v4 to create tailored PDFs.
  5. Manage: Review and mark jobs as "Applied" via the dashboard (calls webhooks for lifecycle events).

Example of generating a tailored resume for a job

https://github.com/user-attachments/assets/5b9157a9-13b0-4ec6-9bd2-a39dbc2b11c5

Example of applying to a Ready job

https://github.com/user-attachments/assets/06e5e782-47f5-42d0-8b28-b89102d7ea1b

How to Start

Prerequisites

  • Docker Desktop (or Docker Engine + Docker Compose)

Overview

  • Run the app with Docker (this pulls the pre-built image).

  • Create accounts:

    • OpenRouter (LLM scoring/tailoring)
    • RxResume v4 (PDF export + editable resume data)
  • Open the dashboard and complete the onboarding wizard:

    • Add API keys/credentials
    • Choose a resume template from RxResume
    • Run the pipeline to fetch jobs → score → tailor → export PDFs
  • Review jobs in the dashboard and mark stages

Quick Start (commands)

# 1. Clone and move to directory
git clone https://github.com/DaKheera47/job-ops.git
cd job-ops

# 2. Start with Docker (pulls pre-built image from GHCR)
docker compose up -d

# 3. Open the dashboard in your browser, the app will onboard your credentials
# http://localhost:3005

Required accounts

  • OpenRouter (LLM provider)

    • Create an account and generate an API key.
  • RxResume v4

    • Create an account on v4.rxresu.me
    • The summary, title, chosen projects, and keywords in the Resume will be tailored for the job description
    • Recreate/import your resume there so JobOps can:
      • pick a template
      • generate tailored PDFs from your stored resume data

App Onboarding

The app will guide you through setup on first launch. The onboarding wizard helps you:

  • Configure the LLM provider (OpenRouter by default) and add an API key if required (for AI scoring/tailoring)
  • Add your RxResume credentials (for PDF export via v4.rxresu.me)
  • Select a template resume from your v4.rxresu.me account

Technical Details

  • Technical breakdowns here: documentation/extractors/README.md
  • Orchestrator docs here: documentation/orchestrator.md
  • Persistent data lives in ./data (bind-mounted into the container).

Notes / sharp edges

  • Crawl targets: edit extractors/gradcracker/src/main.ts to change the Gradcracker location/role matrix.
  • Pipeline config knobs: POST /api/pipeline/run accepts { topN, minSuitabilityScore }; PIPELINE_TOP_N/PIPELINE_MIN_SCORE are used by npm run pipeline:run (CLI runner).
  • Anti-bot reality: crawling is headless + "humanized", but sites can still block; expect occasional flakiness.

Note on Analytics: The current alpha version includes anonymous analytics (Umami) to help me debug performance. This will be made opt-in only in the upcoming updates. If you want to disable it now, block umami.dakheera47.com in your firewall.

Contact

If you need any help with any step of the process, feel free to open an issue. I am actively monitoring this section and I would be extremely happy to help you get up and running!

Star History

Star History Chart

License

AGPLv3

Description
No description provided
Readme AGPL-3.0 6.7 MiB
Languages
TypeScript 98.6%
Python 0.4%
Shell 0.4%
CSS 0.3%
Dockerfile 0.2%