JobCache Architecture
Status (2026-08-18): the API-first architecture is implemented, migrated and
live. JobCache Core's corpus/search facade and participant lifecycle run from
jobcache/interface/ on a protected Alwaysdata origin; the session-private App
API owns the EU jobcache-app D1 at api.jobcache.corbet.ch; and the thin MCP
peer is live at mcp.jobcache.corbet.ch. The old Render service remains
provider-suspended and owns neither public App host.
JobCache is one product with two runtime and privacy zones:
JobCache App
observer-facing perspectives · session-private state
│
privacy seam
│
JobCache Core
shared corpus · extraction · search · recommendations · market intelligence
“Core” is a concern boundary, not another product, brand or repository namespace. Both
zones are named, deployed, logged and operated as JobCache. Core owns neither JobCache
App's session_id nor CareerVector's workspace_id.
JobCache App
The App is the observer-facing edge for employers, analysts, advertisers, operators and their agents.
| Layer | Responsibility |
|---|---|
| perspectives | MCP now; website later; status, ops, QA and wiki remain peers |
| public API | strict role search/evidence plus saved views, snapshots and reductions scoped to one explicit session capability |
| local D1 | session-private views, immutable snapshots, many-to-many view grants, current pointers, opaque live read-only mirrors and deletion outbox |
| reduction | records pseudonymous observer work or a pending anonymous-cohort request; it does not mislabel one session as an aggregate |
| collectors/internal API | strict observer delivery plus a durable participant-erasure drain, each with a distinct bearer |
The App's public API and perspectives are JobCache-specific. Its store, reduction, collectors and seam-facing internal API reuse the same implementation first proven by CareerVector.
JobCache Core
Core is the shared market-intelligence substrate:
| Concern | Owner |
|---|---|
| ads, roles, evidence and public fact projections | CrateDB corpus |
| normalize, disambiguate ad → role, enrich, embed and index | extraction/corpus pipeline |
| live role search and result metadata | search executor |
| person-only preference matching | recommendation engine |
| anonymous cohorts and observer-facing measures | metrics builder |
| claims, leases, delivery receipts, retries and quarantine | operational store beside the internal API |
| authenticated product-to-Core protocol | JobCache internal API |
JobCache Core returns roles as the product unit and ads as supporting evidence. Stable role identity and merge/split aliases are Core responsibilities; product edges must not invent role IDs from URLs.
Operational churn does not belong in CrateDB. The corpus is the durable searchable asset; leases and retry state must not compete with its indexes.
The App/Core privacy seam
Every crossing declares its purpose and privacy class:
| Class | App emits | Core may use it for |
|---|---|---|
| pseudonymous individual | a versioned observer_key and allowlisted facts |
individualized saved state where the feature requires continuity |
| anonymous aggregate | a thresholded cohort with no participant key | market metrics and analytics |
session_id, raw session state and the inverse pseudonym map stay in JobCache App. An
observer_key is pseudonymous personal data, not anonymous. Observer facts never train
the person recommendation engine.
The same rule applies independently at the CareerVector/Core seam with workspace_id and
person_key; see System Architecture.
Perspectives and packages
JobCache perspectives remain peers under jobcache/: api/, mcp/, interface/,
ingest/, ops/, qa/, status/ and wiki/. jobcache/api/ is the App boundary;
jobcache/mcp/ calls only that API; jobcache/interface/ is the current Core facade and
compatibility process. jobcache/shared/ owns JobCache-wide Core helpers. Cross-product
seam contracts live in the repository's shared library family; The Shared Seam
Package is authoritative for their exact paths.
The wikis remain product perspectives: CareerVector documents the applicant product; JobCache documents both its App and Core. Cross-product architectural contracts are linked, not duplicated.
As-built boundary
| Component | Current state |
|---|---|
| CrateDB corpus and JobCache extraction | live |
| JobCache Core role-search API | implemented as a strict, content-identified role contract |
| JobCache Core participant lifecycle | implemented: monotonic tombstones, retryable cleanup, deterministic public-safe receipts and active views that exclude crash residue |
| CareerVector participant erasure transport | live claim/apply/receipt-ack protocol with D1 and Crate lifecycle migrations applied |
| JobCache App public facade | live Cloudflare Worker over EU D1 and protected Core |
| JobCache App D1/session/observer mirror | implemented: opaque sessions, saved views, immutable snapshot grants, live read-only derivatives, reductions and atomic local-delete/Core-erasure outbox |
| shared UI/realtime foundation | implemented: CareerVector and JobCache share shell actions, contribution/scraping state, awareness normalization, relay/WebRTC attachment and status projection; JobCache tab content remains product-owned |
| JobCache MCP | live secretless thin peer over a private App Worker service binding |
| CareerVector seam installation | live search, immutable grants, composite claim/ack, strict delivery and durable participant erasure |
Direct database access and the rolling legacy public-search fallback are compatibility scaffolds. They are not valid final dependencies for CareerVector.
The legacy Crate-backed /api/sessions routes have been removed from
jobcache/interface and return 404. Only jobcache/api/ owns JobCache session
state. Core's runtime principal is schema-scoped; retired direct participant
writers fail closed.