Journey sequence diagrams
Each diagram has a text transcript for phone and assistive reading. The order is part of the design. The diagrams describe intended behaviour, not delivered functionality.
J1: Sign in and set up
Read the sequence as text
- Browser → App Worker. Open private route; start sign-in.
- App Worker → Google. Authorize with state, nonce and PKCE.
- Google → App Worker. Authorization code callback.
- App Worker → Google. Exchange code; validate token.
- App Worker → D1. Link subject; create session.
- App Worker → Browser. Set session cookie; resume setup.
- Browser → App Worker. Save exact card and statement day.
- App Worker → D1. Persist card and dated settings.
- App Worker → Browser. Show destination and test status.
The server checks OIDC state, nonce, signature, audience, issuer and expiry. It links Google's stable sub to an internal account. No Gmail or Drive scope is requested. Unsupported products can be recorded but have unavailable reward estimates. Setup persists after each successful step. A failed test never claims complete bank coverage. F-01, F-02, F-03.
Forwarding-confirmation messages appear only in the authenticated account's setup panel after exact-provider parsing. Never auto-follow an arbitrary link or forward confirmation messages to another mailbox. Test real Gmail and Outlook formats before accepting them.
Intake: Capture once, even after retries
Read the sequence as text
- Email Worker → R2 / D1. Validate tag; reserve quotas.
- Email Worker → R2 / D1. Store raw object; receipt + outbox.
- R2 / D1 → Queues. Dispatcher sends intake ID.
- Queues → Consumer. Deliver ID; may repeat.
- Consumer → R2 / D1. Check account; parse source; dedupe.
- Consumer → R2 / D1. Commit fact + ledger version.
- Consumer → R2 / D1. Calculate; conditionally publish revision.
- Consumer → Queues. Acknowledge after durable commit.
Reserve quotas before storing MIME. Write an R2 object using an intake ID, then atomically record the intake receipt and outbox row in D1. Dispatch after commit. A bounded orphan sweep deletes objects without receipts. A dispatcher crash may enqueue twice; the consumer deduplicates. A queue failure leaves the outbox pending. Unknown or revoked tags are rejected; persistence failures must be tested for SMTP retry behaviour before launch, not silently treated as accepted.
A second copy with identical raw bytes is deduplicated by a tenant-scoped hash. Forwarded copies with changed MIME use issuer reference and stable semantic evidence. When two real purchases might look identical, hold the possible duplicate for review rather than merge automatically. Ambiguous account, card, currency or amount stays excluded from affected totals. Unknown MCC alone does not exclude a known purchase.
J2: Compare cards before spending
Read the sequence as text
- Browser → App Worker. GetHome(month) via Connect GET.
- App Worker → D1. Validate session and owned selection.
- App Worker → D1. Read published snapshot and pending state.
- D1 → App Worker. Return one calculation revision.
- App Worker → Browser. Return allowances, estimates, evidence.
- Browser → App Worker. GetCard(owned card, period).
- App Worker → Browser. Show full conditions; no invented advice.
Read one account snapshot revision. Cards show separate allowances, conditional minimums and earned estimates in native units. Missing rule or payment evidence suppresses definitive recommendations. User priority breaks ties only among comparable verified choices; cashback is not ranked against miles without an approved valuation. F-05, F-06, F-11.
J3: Correct a purchase in its sheet
Read the sequence as text
- Browser → App Worker. CorrectTransaction(version, command ID).
- App Worker → D1. Authorize; compare record version.
- App Worker → D1. Commit correction + pending + outbox.
- App Worker → Browser. Return corrected fact and pending state.
- D1 → Job worker. Dispatch latest affected calculation.
- Job worker → D1. Publish only if ledger version matches.
- Browser → App Worker. Refetch snapshot while pending.
- App Worker → Browser. Replace totals and review count together.
A command contains an idempotency key and expected record version. A successful correction transaction creates a correction event, increments ledger version, marks affected projections pending and writes the outbox. The UI immediately receives the corrected fact and a pending calculation state. It does not combine a fresh fact with stale numbers presented as final. When recalculation publishes, the client replaces all affected totals and review count together. Cancellation writes nothing; errors preserve form entries. Focus returns to the trigger on close. F-08.
J4: Inspect a month or card cycle
Read the sequence as text
- Browser → App Worker. GetHistory(exact selection).
- App Worker → D1. Read chart and rows at same revision.
- App Worker → Browser. Return period keys and revision.
- Browser → App Worker. GetPeriod(selected key, revision).
- App Worker → D1. Read owned period and paginated facts.
- App Worker → Browser UI. Show totals, credits, uncertainty, reasons.
- Browser → App Worker. ListTransactions(selection, cursor).
- App Worker → Browser UI. Append same-revision page or restart.
Selections are explicit period keys, not a reused October URL. Return chart, list, totals, credits and revision reasons from the same published snapshot. Cursor pagination retains its selection and revision; if that revision expires, ask the client to restart rather than skip rows. No captured purchases yields an em dash, not 100%. F-04, F-09, F-10.
Account deletion: stop access before cleanup
Read the sequence as text
- Browser → App Worker. Recent auth + deletion confirmation.
- App Worker → D1. Revoke access and tags; mark deleting.
- App Worker → Browser. Acknowledge stopped access.
- D1 → Cleanup worker. Dispatch deletion job.
- Cleanup worker → D1. Delete owned records in bounded batches.
- Cleanup worker → D1. Record opaque restore-block marker.
- Cleanup worker → D1. Verify cleanup completion.
- App Worker → Browser. No further private access.
This is a proposed technical deletion mechanism. It is not approval of retention policy. Reauthenticate, revoke sessions and forwarding tokens, and set the account to deleting in one transaction. All later consumers check that state before writes. A bounded job deletes R2 objects, facts, corrections, projections and private overrides. Job retries converge on the same state. A recovery tombstone blocks deleted accounts after a backup restore until cleanup runs again. Proposed deadlines and backup limits are on the security page.