Design for review · 02 / 11

Proposed architecture. Pilot products, privacy policy and cost-risk acceptance remain open.

Architecture and ownership

Deploy a modular system

The browser uses one same-origin application Worker for rendering, sign-in and Connect requests. A separate Email Worker has only intake permissions. A queue consumer parses alerts and computes results. They share versioned domain packages, not HTTP calls between small internal services.

Phone browser
React · TanStack

HTTPS + session cookie ↓

Application Worker
OIDC · Connect · authorization

owned repositories ↓

D1
Facts · corrections · calculation revisions

↑ idempotent writes

Queue consumer
Parse · classify evidence · calculate

↑ message ID only

Email Worker → R2 + outbox
Tag gate · size gate · durable intake

R2 holds raw MIME without a public URL. Queue bodies contain opaque intake IDs and versions, never email text or account details. A D1 outbox repairs the non-atomic boundary between R2, D1 and Queues.

Package boundaries

Module Owns Must not do
web Routes, forms, sheets, accessibility, Query keys Calculate reward rules in components
contract Protobuf descriptors and generated clients Import database tables
api Session, tenant authorization, request validation Trust a supplied account ID
intake Size limits, tag validation, receipts, MIME retention Guess card ownership from sender
parsers Versioned bank-template adapters and evidence extraction Fetch remote email content or execute HTML
ledger Facts, credits, revisions and deduplication Infer that a category proves MCC
rewards Pure deterministic evaluation of verified rule data Call AI or read the clock implicitly
projection Build complete result revisions and publish pointers Mix results from different revisions
jobs Outbox, retry, cleanup, deletion and reconciliation Run unbounded account-wide scans

Runtime contracts

Conceptual interfaces below describe responsibilities, not implementation code.

parseAlert(raw, parserVersion) -> ParsedEvidence | NeedsReview(reason)
resolveCapture(evidence, accountContext) -> PurchaseFact | CreditFact | HeldCapture
calculate(facts, ruleVersions, settingsVersions, asOf) -> CalculationRevision
publish(revision, expectedLedgerVersion) -> Published | Superseded
readSnapshot(account, selection) -> Snapshot(revision, completeness, provenance)

Use integer minor units for money and integer or rational reward units. Parse external strings at boundaries. Unknown amounts, dates, MCCs and payment methods are explicit variants. They never default to zero or an eligible state.

Why D1 for the pilot

D1 fits the existing Workers plan and supports transactional batches. Each database processes queries on one thread, so expensive calculations stay outside SQL write transactions. The pilot starts with one database per environment and indexed tenant queries. A measured contention or storage limit triggers a new ADR before expansion. D1 limits.

Postgres with Hyperdrive remains the alternative for heavier write concurrency, richer transactional workflows or a residency requirement D1 cannot meet. Hyperdrive is a connection layer, not a supplied Postgres server. No external database subscription is assumed.

Use Workers for the application runtime; the documentation pages are a separate static Pages artifact. TanStack Start has an official Workers deployment path. The Connect adapter, MIME parser and auth library still need a real Workers compatibility spike. Start on Workers.