Web · Source available
Job Wire
A job aggregator for the Indonesian market that ranks listings against your CV without sending the CV anywhere.
Why it matters
What makes it stand out.
One search across many job boards
Results from several sources are merged and duplicate listings collapsed, so job seekers do not open board after board.
The CV never leaves your server
CV analysis runs on your own backend. Only search keywords are sent to outside services.
Suggestions you can act on
Users get a concrete list of improvements, including keywords their target listings ask for that the CV does not mention.
No AI cost per request
Matching is rule-based, so results can be explained and there is no model bill for each analysis.
The problem
Job seekers in Indonesia check several boards separately, see the same vacancy repeated, and have no quick way to tell which listings match their CV. Tools that do score a CV usually require uploading it to a third party.
Who it is for
Job seekers in Indonesia who want one search across boards and concrete feedback on their CV, and developers who want a self-hosted starting point.
Key features
One search across sources
Listings come from general web search results through the Serper API and from JobStreet directly, then are merged into a single schema.
De-duplication and expiry filtering
The same vacancy found through two sources is collapsed into one entry, and expired listings are removed before results are returned.
CV parsing from PDF, DOCX or TXT
The backend extracts plain text, then detects skills and the standard CV sections, including Indonesian equivalents of common skill names.
Match score per listing
Each listing is scored by the share of its detected skills that also appear in the CV. Listings with no detectable skills show “score not available” instead of a default number.
Concrete CV suggestions
Missing sections, a lack of measurable achievements, passive phrasing, and keywords that target listings ask for but the CV does not mention.
Pagination without re-uploading
The full ranking is held in a short-lived analysis session, so changing page or filter does not send the file again.
The same approach can be adapted for
- Career portals for a campus or community
- Tools that match documents against requirements
- Aggregators that merge and de-duplicate several data sources
Architecture
Job Wire is two parts: a Vue 3 and Quasar single-page app, and an Express server that does all the work involving external sources and CV text.
The server is organised so that anything testable is a plain module:
index.jshandles routing and orchestrates the source calls.jobPool.jsis pure logic: de-duplication, expiry filtering, coverage notes and pagination.skillMatcher.jsexposes oneextractSkills()function shared by listing normalisation and CV analysis, so both sides are measured with the same dictionary.extractText.jsturns PDF, DOCX and TXT uploads into plain text.cvAnalyzer.jsdetects sections, computes match scores and builds suggestions.
Every source is normalised to the same job schema before it enters the pool. Adding a source means writing one fetch function and registering it. The frontend does not change.
Implementation details
Why rule-based. The matching is a skill dictionary with synonyms, not a language model. It runs locally with no extra API key, its output can be explained line by line, and it costs nothing per request. The suggestion builder is a single function, so swapping in a model call later is a contained change.
Indonesian synonyms. A CV that says “manajemen proyek” should match a listing that asks for “Project Management”. The dictionary maps such pairs so bilingual CVs are scored fairly.
Scores that admit uncertainty. When a listing has too little text to detect any skill, the score is null and the interface says so. A made-up 50% would be worse than no number.
Analysis sessions. POST /api/cv/analyze stores the full ranking under an analysis id with a 15-minute lifetime. Later requests for another page or filter call GET /api/cv/recommendations with that id.
Caching with a fallback. Redis is optional. Without REDIS_URL the server falls back to an in-memory cache, which keeps local setup to two commands.
Relevant results first. Global remote job APIs are used only to enrich a single listing’s detail view. They are kept out of the main search so results stay focused on Indonesia.
Privacy
Only search keywords leave your machine. The contents of an uploaded CV are parsed and matched on the backend you run and are never forwarded to a third party.
What can be verified
- Backend logic for de-duplication, expiry filtering and pagination is isolated in a pure module, and the server ships with a Vitest suite.
- CV text is processed only on the backend you run. Only search keywords are sent to external APIs.
- Works without a Serper key by falling back to JobStreet only, and tells the user that coverage is limited.

