jobhunt-platform/docs/api-contract.md
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

2.1 KiB

API contract (POC)

Base: /api. JSON everywhere. Errors as {error: {code, message}} with proper HTTP status.

Profile & CV

  • GET /profile -> profile object (create default if none)
  • PUT /profile -> update profile fields
  • GET /profile/sections -> list of cv_section ordered by kind, sort_order
  • POST /profile/sections -> create section
  • PUT /profile/sections/{id} -> update
  • DELETE /profile/sections/{id}
  • POST /profile/sections/{id}/ai-assist body {instruction: str} -> {suggestions: [str]} (LLM, cheap->strong routing per config)
  • POST /profile/render-cv -> {artifact_id, url} rendered PDF from current profile + sections (packages/artifacts)

Job postings

  • POST /postings body {url} -> fetch via connectors (manual_url for POC), create job_posting + application(state=discovered)
  • GET /postings -> list
  • POST /postings/{id}/score -> run scoring rubric vs profile -> application.state=scored, returns {score, rationale}

Applications (kanban)

  • GET /applications -> list with posting info joined
  • POST /applications/{id}/transition body {to} -> guarded per data-model.md table; 409 if illegal or guard fails
  • POST /applications/{id}/artifacts multipart upload or {kind, content} -> creates artifact with content_hash
  • POST /applications/{id}/artifacts/cover-letter body {letter_text} -> stores user draft, returns artifact + AI critique {comments: [{quote, suggestion, severity}]} (LLM review, does not rewrite)
  • GET /applications/{id}/artifacts -> list

Approval & outbox (the gate)

  • POST /applications/{id}/approvals body {action, artifact_id} -> creates pending approval (expires_at = now+24h)
  • POST /approvals/{id}/confirm -> user confirms; verified artifact.content_hash == approval.artifact_hash or 409
  • POST /approvals/{id}/reject
  • POST /outbox/send body {approval_id, payload} -> fails 409 unless approval confirmed, unexpired, hash match. On success: outbox.status=sent (POC: log/echo transport pluggable; real SMTP later)

Telemetry

  • GET /telemetry/tasks -> task_run list (tokens, model, cost) — shows users their burn

Health

  • GET /health -> {status: "ok"}