Work / Case study · Published · 2026-10-15

RecruitRadar

Hiring-market intelligence from public job postings, with an explainable score.

RecruitRadar radar of companies with priority scores
RecruitRadar radar of companies with priority scores. Screenshot of the implemented application with its synthetic sample data.

The problem

Public job postings are noisy: the same company appears under several names, roles are reposted, and a single number hides why a company looks active. A recruiter needs normalized postings, careful de-duplication and a score whose every part can be checked.

What it does

  • Radar of companies with role counts, role mix, locations, sources and signal age, plus a priority score with per-component breakdown and coverage.
  • Missing information is listed and left out of the score, never counted as zero.
  • CSV import with line-by-line errors, merge review for look-alike company names (never merged automatically), CSV exports with evidence.
  • Connected mode (local FastAPI backend) refreshes public Greenhouse, Lever and Ashby boards with a recorded refresh history; failed refreshes never delete data.
  • Local-data mode runs fully in the browser; this is what the published demo uses.

Engineering choices

  • The scoring and identity logic is one pure function, implemented twice and independently: Python for the backend and TypeScript for the browser, from one written spec.
  • A third, standard-library-only oracle generates golden vectors; a seeded differential fuzzer compares all three implementations.
  • FastAPI with SQLAlchemy 2 and Alembic on SQLite; Host guard, total provider deadline and busy-database handling added after review.

Significant challenge: Two implementations that must agree

The first differential fuzz run found 212 mismatches in 940 generated cases that the existing golden vectors had missed. Each was resolved from the spec text and recorded as a decision. The independent review later found that the Python and TypeScript CSV importers disagreed on eight input classes; they are now held to shared vectors and a second differential fuzz.

Tested results

  • 706 Vitest and 1,578 pytest tests; ruff and mypy --strict clean.
  • Golden vectors (47 analysis, 173 normalization) and differential fuzz: 948 analysis cases and 610 CSV cases, 0 mismatches.
  • 20 Playwright tests under /recruit-radar/.
  • Independent acceptance review: 12 findings fixed with regression tests.
  • Published 2026-10-15; the first CI run failed on a Linux file-permission lint, was fixed, then went green.

Last recorded verification 2026-10-15; latest recorded commit f9d6103. The full commands and outcomes are in the repository's docs/test-report.md.

Stack

  • TypeScript
  • React
  • Vite
  • Python
  • FastAPI
  • SQLAlchemy
  • Alembic
  • SQLite
  • pytest
  • Vitest
  • Playwright

Candid limitations

  • The static demo cannot refresh from job boards; that needs the local backend.
  • Scores are fixed-weight heuristics with no semantic title matching.
  • Provider payload shapes come from documentation and a one-off live check; automated tests use synthetic payloads.

How it was made

Directed and reviewed by the owner; specification, code, tests and documentation written with Claude Code (AI). A separate Claude Code session that did not write the code then re-ran every check and fixed what it found; that is an AI review, not a human code audit. See the repository's AI_ASSISTANCE.md.