Architecture
Patomic is Cloudflare-native end to end. Every request hits a Worker; nothing lives behind a load balancer. This page is the mental model — the moving parts and what each is for.
Request lifecycle (authenticated)
Section titled “Request lifecycle (authenticated)”client │ Authorization: Bearer ptmc_… ▼Cloudflare edge (~250 colos) │ Worker cold-start: 0 ms (kept warm), p95 cold ≈ 5 ms ▼secureHeaders → structuredLogger → onError(global) │ ▼ /v1/* only:authMiddleware │ 1. Bearer extract (in-memory) │ 2. PBKDF2(key, secret) (Web Crypto, ~ms) │ 3. SELECT api_keys (D1, ~5–20 ms) │ 4. attach { user, apiKey } ▼rateLimitMiddleware │ INSERT rate_limits ON CONFLICT DO UPDATE RETURNING count │ Atomic. No race. Per-(key, minute-window). ▼idempotencyMiddleware (non-safe methods only) │ KV.get → if cached, replay verbatim. ▼route handler │ validation (Zod) → repo → response ▼clientEvery middleware emits structured JSON logs correlated by cf-ray, surfaced as x-request-id. Errors flow through Sentry with environment + release tags.
What each component is for
Section titled “What each component is for”D1 (SQLite at the edge)
Section titled “D1 (SQLite at the edge)”The system of record. Holds:
users— accountsapi_keys— authenticationaudit_log— every auth event, rate-limit breach, key mutationrate_limits— minute-window counters- (Phase 2)
patents,assignees,inventors,cpc_codes,citations
Reads scale to ~50k/sec via read replicas. Writes go to the primary region (currently WEUR / London). Roughly 10 ms p50 from a colo near WEUR; ~150 ms from far regions for writes.
KV (eventually-consistent key-value)
Section titled “KV (eventually-consistent key-value)”Hot reads, idempotency cache, future per-API-key caches. Sub-millisecond reads at the colo level. Eventually consistent globally — fine for caches, not used as a system of record.
R2 (object storage)
Section titled “R2 (object storage)”(Phase 2.) Patent full-text, original PDFs from each jurisdiction, archival audit log dumps when retention expires.
Vectorize (vector database)
Section titled “Vectorize (vector database)”(Phase 3.) Embeddings of claim text, abstract, and key element extracts. Semantic search over millions of patents in under 100 ms.
Queues + Durable Objects
Section titled “Queues + Durable Objects”(Phase 2.) Ingestion pipeline. New patent batches from USPTO/EPO/WIPO/JPO/CNIPA are pushed onto a Queue; per-jurisdiction consumers pull, normalise, write to D1+R2+Vectorize. Durable Objects coordinate the canonicalisation across jurisdictions.
Locked stack decisions
Section titled “Locked stack decisions”| Concern | Choice | Why |
|---|---|---|
| Runtime | Cloudflare Workers | Global edge, sub-100 ms p95, free tier scales |
| HTTP framework | Hono | Workers-first, type-safe, OpenAPI integration |
| Validation | Zod (via @hono/zod-openapi) | One schema → runtime validation + OpenAPI doc |
| ORM | Drizzle | Type-safe, no codegen, Workers-friendly |
| Auth hash | PBKDF2-SHA256 with server-side salt | Deterministic for O(1) lookup, brute-force-resistant |
| Rate limit | Atomic D1 upsert | True atomic — no Promise.all([COUNT, INSERT]) race |
| Webhook sig | HMAC-SHA256, Stripe-compatible header | Engineers familiar with Stripe webhooks recognise it instantly |
| Pagination | Signed-cursor keyset | Stable under concurrent inserts, O(1) per page |
| Error contract | Stripe-grade envelope | type, code, message, docs_url, request_id, suggestion |