* 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.
* feat(shortcuts): add tinykeys + core infrastructure (useHotkeys, shortcut-map, KbdHint)
Install tinykeys (~400B) for declarative keyboard shortcut handling.
Add useHotkeys React hook with input-guarding logic, centralized
shortcut definitions, and a reusable KbdHint badge component.
Ref #113
* feat(shortcuts): wire j/k navigation and 1-4 tab switching
Add useHotkeys call to OrchestratorPage with:
- j/ArrowDown to navigate to next job in list
- k/ArrowUp to navigate to previous job
- 1/2/3/4 to switch between Ready/Discovered/Applied/All tabs
Auto-scrolls the list to keep the selected job visible.
Ref #113
* feat(shortcuts): add context action shortcuts (s/a/t/p/d/o/x/Esc)
Wire keyboard shortcuts for all primary actions:
- s: skip job (discovered/ready tabs)
- a: mark applied (ready tab)
- t: toggle tailor mode (discovered/ready tabs)
- p: view PDF in new tab (ready tab)
- d: download PDF (ready tab)
- o: open job listing (all tabs)
- x: toggle select current job
- /: open search (command bar)
- Escape: clear selection
Actions are tab-scoped and guard against in-flight state.
Thread tailorTrigger counter prop through JobDetailPanel to
DiscoveredPanel and ReadyPanel for keyboard-driven tailor toggle.
Ref #113
* feat(shortcuts): add bottom hint bar and help dialog (? key)
Add KeyboardShortcutBar -- a Superhuman-style bottom bar showing
available shortcuts for the current tab. Dismissible with X button,
preference stored in localStorage.
Add KeyboardShortcutDialog -- a grouped help overlay triggered by '?'
showing all shortcuts with their key bindings in a two-column layout.
Both components are context-aware, only displaying shortcuts valid
for the active tab.
Ref #113
* feat(shortcuts): add visual KbdHint badges on action buttons
Show keyboard shortcut key caps on primary action buttons:
- DecideMode: 's' on Skip, 't' on Start Tailoring
- ReadyPanel: 'p' on View PDF, 'd' on Download, 'o' on Open Listing,
'a' on Mark Applied
- OrchestratorFilters: '1'-'4' on tab triggers
All hints are desktop-only (hidden below lg breakpoint).
Ref #113
* refactor(shortcuts): migrate Cmd+K to useHotkeys in JobCommandBar
Replace manual window.addEventListener keydown handler with the
shared useHotkeys hook for consistency across all keyboard shortcuts.
Ref #113
* fix(test): mock getProfile in OrchestratorPage tests
* style: move tab shortcut indicator before label
* feat: add ArrowLeft/Right shortcuts for tab navigation
* feat: show keyboard helpers only when Control is held down
* feat: expand shortcut bar with multiline layout
* feat: show keyboard shortcut help on first launch
* 1
* 2
* 3
* better modifier pattern
* 5
* tailoring is a toggle
* tests
* tests is passing
* r to move to ready
* tests
* initial change
* nav highlighting
* icon change
* deeeedoooop
* text
* show version number on all pages
* icon
* remove unused code
* add knip
* formatting
* remove unused code
* types fix
* remove notion completely from the codebase.
* update test for new url structure
* clean up the fucking shop boys
* make a "create job" factory and use that
* moar factories
* formatting
* feat(shared): add glassdoor to job source model
* feat(jobspy): support glassdoor site in scraper and discovery
* feat(pipeline): include glassdoor in source selection and API schema
* feat(ui): add glassdoor toggle to jobspy settings and run estimates
* test/docs: cover glassdoor jobspy integration end-to-end
* fix(jobspy): make glassdoor always-on without settings toggle
* fix(jobspy): fallback glassdoor when location is country-level
* refactor(jobspy): drop direct pandas usage in wrapper
* feat(pipeline): gate glassdoor by supported countries
* fix(jobspy): restore pandas output and keep glassdoor disable copy
* fix(jobspy): map country-level glassdoor searches to city fallbacks
* feat(ui): require glassdoor city for country-level runs
* api(jobs): normalize PATCH /jobs/:id response contract and error mapping
* api(jobs): support core job detail edits in update schema
* feat(client): add JobDetailsEditDrawer with core metadata form
* feat(orchestrator): open edit drawer from JobDetailPanel more actions
* feat(orchestrator): add edit drawer trigger to ready and discovered more actions
* feat(api): add lightweight jobs list view without pagination
* refactor(client): use lightweight jobs list and on-demand job detail
* refactor(ui): separate job list rows from full job detail
* perf(home): reduce jobs payload to applied lightweight rows
* perf(db): add safe composite index for jobs list queries
* feat(api): default jobs endpoint to lightweight list view
* style: apply biome formatting for jobs list-view changes
* feat(api): add jobs revision endpoint for lightweight change detection
* refactor(client): switch jobs auto-refresh to revision checks
* perf(client): drive pipeline freshness via sse with polling fallback
* refactor(orchestrator): remove pipeline status polling loop from page
* chore(client): add periodic safety refresh and refresh lifecycle hardening
* refactor(types): define JobListItem via Pick<Job> to prevent drift
* initial commit
* use colours!
* match by scoring
* scroll job card into view
* introduce @ based 'locks' to restrict search to specific statuses
* clear lock states on close
* split up component
* inline pill
* resuse job row content
* fix intro anim
* larger size, instruction
* refactor existing search feature
* lock colour border
* if active, clear active on escape
* remove query param
* documenration update
* scoring logic
* check exists before scroll
* status dot and checkbox occupy the same space!
* feat(shared): centralize supported country list and source-country rules
* feat(orchestrator): add country selector and UK-only source gating in automatic run modal
* feat(orchestrator): persist country selection and run only compatible extractors
* fix(pipeline): enforce country-source compatibility during discovery
* test(orchestrator): cover country-based source gating and pipeline enforcement
* formatting
* test fix
* lint
* comments
* prevent auto focus grab
* verification
* command and popover
* make sure scroll is working
* initial commit
* accordionising
* merge extra cards
* visual highlight
* everybody becomes an accordion
* bugbashing
* text area
* split up tailoring editor
* feat: enhance `parseTailoredSkills` to support legacy string arrays and add comprehensive tests for parsing logic.
* feat(orchestrator): add unified run modal shell with Automatic/Manual tabs
* feat(orchestrator): implement Automatic tab presets, estimate, and save+run flow
* refactor(manual-import): reuse manual import flow inside unified run modal
* refactor(settings): move pipeline tuning out of settings page into run modal
* stage 5
* jobs per term simplified
* copy improvement
* pill input
* better UI
* style(orchestrator): align run settings inputs on one row
* style(orchestrator): remove hover and pointer affordance from term pills
* style(orchestrator): restore hover and pointer affordance for term pills
* style(orchestrator): make search term pill hover more prominent
* better hover
* refactor(orchestrator): use react-hook-form in automatic run panel
* formatting
* fix(orchestrator): resolve biome issues in automatic run modal
* better copy
* feat(orchestrator): auto-select custom preset on manual config changes
* remove badge
* feat(orchestrator): redesign automatic run panel with collapsible advanced settings
* refactor(orchestrator): move estimate summary to footer and dedupe sources
* style(orchestrator): separate search term input from term pills
* style(orchestrator): remove save preset action from automatic footer
* ux(orchestrator): make entire search term pill tap-to-remove
* remove badge
* remove badge
* fix(orchestrator): return zero estimate when search terms are empty
* initial commit
* test fix
* manual test
* copilot comments
* code quality skill
* comments
* fix types problem
* formatting
* tests now correct for new backup method
* UTC dates
* feat(types): add jobspyIsRemote to TypeScript type definitions
- Add jobspyIsRemote boolean fields to AppSettings interface
- Follow three-field pattern: value, default, override
- Update test fixture with default values (false)
* feat(validation): add jobspyIsRemote validation schema
Add Zod validation schema for jobspyIsRemote boolean setting to ensure type safety in the settings API endpoint.
* feat(db): add jobspyIsRemote to database repository setting keys
* feat(api): add jobspyIsRemote storage to settings API route
* feat(service): add jobspyIsRemote to settings service with environment variable support
* feat(jobspy): add isRemote parameter to JobSpy service interface
* feat(pipeline): pass isRemote setting to JobSpy service
* feat(python): add is_remote parameter to JobSpy scraper script
* feat(ui): add Remote Jobs checkbox to JobSpy settings
* feat(ui): add Remote badge to job display
- Display Remote badge when job.isRemote === true
- Position badge next to Source badge in JobHeader
- Use Badge component with outline variant
- Badge does not display when isRemote is false or null
* docs(env): add JOBSPY_IS_REMOTE environment variable documentation
- Added JobSpy section to .env.example with JOBSPY_IS_REMOTE variable
- Documents remote-only job filtering option with default value of 0 (disabled)
- Follows existing .env.example format with clear section headers and descriptions
* test(remote-jobs): verify end-to-end functionality with comprehensive feedback loops
* initial commit
* fix build issues and configurable time duration
* show in nav
* Positive response rate by posting freshness
* load today's jobs for charts
* fix infinite refetching with onboarding gate
* application to response rate
* refactor charts to their own directory
* bar hover color
* Duration selector embedded in navbar
* always load env
* remove warning about low conversion rate
* trend graph for applications per day
* better copy
* remove freshness response chart
* bottom line chart color and tooltip improved
* introduce check all command
* fix lint
* tests added and CI passing
* backend initial commit
* frontend initial commit
* better copy
* make lmstudio work
* enum of providers
* better error messages
* llm model settings stay in one place
* llm settings should be under the model accordion
* skip llm key step in onboarding if provider is set to local
* onboarding now factors in new llm provider flow
* fix tests
* fix typecheck