Commit graph

3 commits

Author SHA1 Message Date
hermes
0e13ee5d51 feat(W1): packages/connectors - AF API, generic URL, dedupe, normalizer
- Connector protocol with fetch(query: SearchQuery) -> list[RawPosting]
- ArbetsformedlingenConnector: official Platsbanken API, field mapping
  (headline->title, employer.name->company, webpage_url->url,
  description.text->description, id->external_id), region mapping,
  polite User-Agent
- GenericUrlConnector: readability extraction (prefers main/article,
  strips nav/footer/script/style), title/company guess, Cloudflare
  challenge detection -> UnsupportedSite
- dedupe helper: (source, url) + external_id keying
- normalizer: RawPosting -> JobPosting (job_posting table shape)
- 37 tests, all passing, recorded fixtures (no live network)
- README with usage and mock examples
2026-07-30 18:23:24 +00:00
hermes
8d8a863300 T2: packages/artifacts + packages/llm-gateway + docker-compose.yml + .env.example
packages/artifacts:
- render_cv_pdf(profile, sections) -> bytes: data-driven CV PDF generation
  using fpdf2 with bundled DejaVuSans TTF for unicode (Swedish chars tested).
  Jinja2 template for layout data prep, adapted from build_cv.py approach.
- render_cover_letter(text, profile) -> bytes: simple cover letter PDF.
- hash_bytes(b) -> str: sha256 hex digest.
- next_version(existing) -> int: version numbering helper.
- 16 tests, all passing: PDF validity, Swedish characters, hash stability,
  cover letter rendering, hash correctness, version logic.

packages/llm-gateway:
- Async-first Gateway class with provider config from env.
- Mock mode default when no API key env present (deterministic canned outputs
  per task name, defined in mock.py).
- Telemetry sink injectable (async or sync callable, receives TelemetryRow).
- Budget guard raises BudgetExceeded BEFORE any provider call is made.
- Retry policy: max 2 retries on 429/5xx, then fallback provider for STRONG
  tasks only. CHEAP tasks never use fallback (paid provider protection).
- Schema validation via jsonschema; SchemaValidationError on mismatch.
- Task class routing: CHEAP (score, extract, cv_assist) vs STRONG (critique,
  cl_critique, research). Model routing per task class.
- Paid provider detection heuristic; warns on paid fallback config.
- 31 tests, all passing: mock determinism, schema pass/fail, budget guard
  (mock + real mode), telemetry sink (async/sync/none), config from env,
  provider calls with mocked HTTP (retry, fallback, no-fallback-for-cheap).

docker-compose.yml:
- postgres:16 service, user/pass/db = jobhunt, host port 5433->5432,
  named volume jobhunt_pgdata, healthcheck.

.env.example:
- DATABASE_URL, LLM provider config (primary + fallback), task budgets,
  API and web settings.
2026-07-30 17:59:56 +00:00
hermes
b77c8b0044 Bootstrap: README, ADR-0001 (LLM at decision points), data model, API contract, worker task cards
Design foundation for POC. Monorepo: FastAPI+Postgres backend, Vue 3 frontend,
Python packages (llm-gateway, artifacts, connectors). Approval gate and
token budgets are architectural constraints per measured prototype findings.
2026-07-30 17:56:07 +00:00