Product engine — shared mechanism, separate products
Aligned 2026-08-17. CareerVector and JobCache are two product domains. They reuse code where the mechanism is genuinely the same; they do not collapse their meaning, identity or data ownership into one application.
CareerVector serves one human applying for work. JobCache provides the eagle-eyed market view. JobCache itself contains an observer-facing App zone and a shared Core zone. “Core” is a concern and privacy boundary inside JobCache, not a third product or a required package name.
The reusable archetype
Both product edges use the same small set of mechanisms:
| Mechanism | CareerVector installation | JobCache App installation |
|---|---|---|
| link capability | workspace_id |
session_id |
| local private store | CareerVector D1/Yjs | JobCache App D1 |
| Core pseudonym | versioned person_key |
versioned observer_key |
| public automation | REST plus MCP | REST plus MCP |
| Core result handling | immutable workspace grant/pointer | immutable session grant/pointer |
| deletion | local erase plus durable Core tombstone | local erase plus durable Core tombstone |
This equivalence is an implementation aid, not an identity equivalence. A CareerVector workspace ID is never a JobCache session ID. Neither crosses into JobCache Core. Shared code receives a neutral local-subject port; the product adapter supplies its own noun, store and participant profile.
What is actually shared
| Home | Responsibility |
|---|---|
lib/corpus-shared/ |
strict cross-product privacy, participant, fact, delivery, search, snapshot and lifecycle contracts |
lib/*-platform/ |
vendor-neutral HTTP/MCP/runtime mechanics once their ports are proven |
jobcache/shared/ |
JobCache-owned Core logic: corpus, role/ad projections, extraction, search, recommendation and metrics |
@cv/public-ui and UI kit packages |
one landing, product shell, HeaderBar/SubHeaderBar and link-identity actions consumed by both CareerVector and JobCache |
| Sporewright | generic routing/decision substrate; it does not own product identity or the corpus seam |
The public APIs remain product-specific. Sharing a serializer or store port does not justify a generic endpoint with optional product flags. If a behavior means something different to an applicant and a market observer, each product owns the operation and calls the shared mechanism underneath it.
Session and workspace capabilities
A JobCache session and a CareerVector workspace use the same authorization model: an unguessable URL-safe identifier is the access capability, with no account database. That is the reusable part.
The stored state differs:
- CareerVector owns CV/CL documents, applications, notes, evaluations and applicant interactions.
- JobCache App owns saved market views, dashboard state, observer interactions and locally granted result snapshots.
- JobCache Core owns public ads, roles, evidence, embeddings and accepted purpose-scoped shared facts.
There is deliberately no session enumeration endpoint. API and MCP calls carry the explicit capability; servers do not infer a current session from cookies, environment variables or mutable server-side defaults.
Provider-neutral ports, concrete adapters
The reusable service layer depends on a storage port, not D1 or CrateDB types. Each installation then binds the appropriate adapter:
| Data | Runtime/store |
|---|---|
| CareerVector private workspace state | Cloudflare Worker + D1/Yjs |
| JobCache App private session state | Cloudflare Worker + its own D1 |
| JobCache Core corpus | JobCache service + CrateDB |
| Core operational leases/receipts | an operational store beside the scoped internal API |
The old jobcache_sessions table may remain in historical Crate schemas, but
its runtime adapter has been removed. It mixed App-local identity with the Core
store and is not a basis for new clients.
API first, MCP second, UI on the same boundary
The current build order is intentional:
- Define and test strict pure contracts in shared packages.
- Complete JobCache Core's authenticated search and participant lifecycle operations.
- Build
jobcache/api/as the session-private App boundary over D1. It owns the Core credential and never forwardssession_id. - Build
jobcache/mcp/as a thin peer over that API. It must not query CrateDB or reimplement policy in-process. - Build
jobcache/ui/as another client of the same stable API. It reuses the shared shell/chrome and reaches App through a Cloudflare service binding; it does not get a private state path or a Core credential.
The provider-suspended Render bundle is no longer an application architecture: its UI, embedded MCP and Host router have been removed. The Core process keeps only explicit compatibility reads and protected Core boundaries.
Privacy class is selected by the operation
Every App-to-Core operation declares one of two classes:
- An individualized observer operation carries a versioned
observer_keyin a strict pseudonymous envelope and has retention, erasure and rotation rules. - A market aggregate carries no participant key and crosses only after the App edge has actually formed a permitted cohort and met its configured threshold.
A single session cannot declare itself an anonymous cohort. Storing an aggregation request or threshold policy locally is not the same as emitting an anonymous aggregate. Until a reducer proves membership and threshold, nothing crosses under the aggregate contract.
Reuse rules
- Extract pure algorithms and explicit ports; do not copy route handlers between products.
- Keep D1, CrateDB and provider bindings behind adapters.
- Keep JobCache Core code under JobCache naming;
internalsis diagram prose, not a public namespace. - MCP mirrors API capabilities and policy. It never bypasses the App API to reach Core storage.
- The UI calls the same API as MCP. No UI-only mutations or implicit session state.
- Do not import CareerVector-specific realtime, mutation, LLM or workspace intelligence machinery merely because the link-capability shape is shared.
- Do not expose local identifiers in logs, Core request bodies, result metadata or lifecycle receipts.
Current status
CareerVector is the first deployed proving installation of the seam mechanics.
JobCache Core's corpus, strict role search and participant tombstone lifecycle
exist. jobcache/api/ now implements the App's opaque sessions, D1 adapter,
saved views, immutable snapshot grants, explicit reductions, delivery and
session-erasure outbox. jobcache/mcp/ is a thin API peer with no Core secret.
The App UI, API and MCP Workers are live. jobcache/ui/ implements the
Cloudflare/Svelte shell as a thin App client: CreateLanding, AppShell, both
header rows, responsive tab pills, theme and common link actions are shared
code, while JobCache supplies session wording and product tabs. Remaining UI
work is product content, beginning with Search jobs and its Swiss map; it is not
another backend architecture.