• v1.0.0 71eca2f194

    bwilliams released this 2026-10-21 15:59:23 +01:00 | 4 commits to main since this release

    The first release of Job Search: it gathers UK public procurement
    opportunities from Find a Tender and EU Supply into one SQLite database,
    and serves them in a web app for working through them.

    Sources

    • Find a Tender, through its OCDS API. Each source carries on from the
      newest release it has stored, or from --since. A start more than 7 days
      ago is backfilled in 7-day windows, each saved before the next, and a
      failed fetch keeps what it got. Rate limits are waited out, up to
      rate_limit_retries times (default 5).
    • EU Supply's UK portal, scraped from its public pages, with its own
      rate limit (a random 2–10s between requests). A tender that repeats an
      opportunity from another source (title 90% alike, buyer or description
      80% alike, within 30 days) is stored hidden and skipped.
    • Skip rules: a JSON file of filters by buyer, title words or CPV
      codes that mark new opportunities Skipped as they arrive. It is reloaded
      when it changes, and job-search skip-rules apply applies it to those
      already stored.

    Web app

    • A sortable table of opportunities: published, contract start and end,
      closing date, value, buyer and more.
    • Filters by status, classification (a CPV tree), marks, SME suitability,
      title and "published in the last X days", remembered between visits.
    • Marks for each opportunity (hidden, skipped, interested, bid submitted,
      won, lost), and a "Hide all visible" button.
    • A details dialog with every release, and links to the notice on Find a
      Tender or the tender on EU Supply.
    • Live updates over a WebSocket: new and changed opportunities arrive
      without reloading, and a reconnect catches up on what changed.
    • Light and dark themes.

    Server

    • job-search serve runs the web app, the REST API (described in OpenAPI
      3.1 at /api/openapi.json, browsable at /api/docs) and every enabled
      source.
    • CSRF protection (job-search config generate-csrf-key keeps the key
      across restarts), rate limits, security headers, optional TLS and proxy
      protocol, and an access log.

    Installing

    The release tarball holds job-search, a systemd unit
    (job-search.service) and a logrotate configuration
    (job-search.logrotate). The unit's comments give the install steps: a
    job-search system user, /etc/job-search/config.yaml, data in
    /var/lib/job-search, and logs in the journal or, with logging.file, in
    /var/log/job-search.

    Create and migrate the database before the first start, and migrate after
    each upgrade:

    sudo -u job-search job-search --config /etc/job-search/config.yaml migrate up --create
    

    job-search config init writes a config file to start from; see
    internal/config/README.md for every setting.

    Known limitations

    • Find a Tender pages its results newest first. If a backfill is stopped
      partway through a window, a restart without --since skips the rest of
      that window: restart with --since set to the window's start (logged as
      backfilling).
    • EU Supply's pages give no contract period, so its opportunities have a
      closing date but no start or end.
    • An EU Supply tender bought by an agent, with no description, isn't
      recognised as a repeat, and one buyer's name inside another's counts as
      the same buyer.
    Downloads