Skip to content

Diagnostic-purchase prompt: tech-triggered, paid on the store's checkout in the customer's browser#32

Open
mrjeeves wants to merge 2 commits into
mainfrom
claude/cec-diagnostic-purchase-integration-hgphzb
Open

Diagnostic-purchase prompt: tech-triggered, paid on the store's checkout in the customer's browser#32
mrjeeves wants to merge 2 commits into
mainfrom
claude/cec-diagnostic-purchase-integration-hgphzb

Conversation

@mrjeeves

@mrjeeves mrjeeves commented Jul 11, 2026

Copy link
Copy Markdown
Owner

The customer side of the $50 CEC Diagnostic Session flow — sibling to the AllMyStuff PR (protocol + node relay + technician controls, mrjeeves/AllMyStuff#167) and the support.cec.direct PR (the checkout hand-off page).

What the customer sees

Only ever when their technician asks — before connecting, mid-session, or after disconnecting; the app never initiates a purchase. A prompt in the house style (same skeleton, tokens, and manners as the approve modal) walks four beats:

  1. The ask — "Alex at CEC is asking you to complete a purchase", the item and $50 price on an order line, plain-language reassurance ("you'll pay on our secure checkout in your own web browser — CEC never sees your card details"), one honest primary button, and a decline that's always available until it's settled.
  2. Finish up in your browser — after Open secure checkout hands off to the default browser (the purchase page → the store's hosted checkout), with I've completed my purchase and Reopen the checkout.
  3. Confirming with your technician — their claim goes to the tech, who verifies the order actually landed in the store before confirming. Includes a "paid but stuck?" phone hint.
  4. You're all set — auto-dismisses after a beat, or Done.

A technician withdrawal takes the prompt down with a note (never a silent vanish). The demo/browser preview plays the whole arc (Preview the purchase prompt next to the existing dial preview), including a pretend technician confirm — screenshots were driven headlessly through all four beats.

Security posture

  • The checkout URL is built in, never taken from the wire. The app constructs support.cec.direct/buy/diagnostic/?sn=…&ref=…&agent=… itself (attribution only), and the new open_url command refuses anything but that page (unit-tested against scheme/host/path escapes). No peer, and no compromised webview, can steer the customer's browser elsewhere through this path.
  • Every browser hand-off now goes through tauri-plugin-opener: the checkout command and the waiting screen's TikTok link (which had landed on the shell plugin's deprecated open). tauri-plugin-shell is dropped entirely, along with the shell:allow-open capability and shell open config — a strictly smaller webview surface than before.
  • The prompt's name prefers the standing approval's agent name (the one the customer actually let in) and otherwise carries the ask's name with exactly the connect prompt's trust: verified against the person on the phone, decline always available.

Compatibility (no release deadlock)

The Rust side compiles without the purchase symbols on purpose — purchase status words are validated locally rather than imported — so this branch builds against whatever AllMyStuff tag main pins and the flow simply lights up at runtime once the bundled/running node carries the relay. Main currently forward-pins v0.2.39 (.allmystuff-rev + the three git-dep tags), so the one remaining step is cutting that AllMyStuff release once #167 lands. The event bridge needed zero changes (it forwards every node event by name).

Verification

  • pnpm check 0 errors / 0 warnings; production build clean (the CI gate).
  • Root workspace fmt/clippy/tests green (the service crate's 5 tests still pass) — the exact battery CI runs.
  • gui/src-tauri: cargo check + 4 unit tests green (URL lock-down, purchase-state validation), compile-checked against the sibling AllMyStuff branch via a temporary path override (not committed; the pinned v0.2.39 tag doesn't exist yet, so nothing resolves it today — same as main, whose CI doesn't build this crate).
  • Full purchase arc driven headlessly in Chromium against the dev build: ask → checkout tab opens → claim → confirm → dismissed. Found-and-fixed along the way: window.open with noopener returns null by spec — the demo no longer misreads that as failure.
  • Rebased onto main's shared-support-area rework (cec: live on the shared support area, lead with Ask for help #35), keeping its raised-hand queue copy and command surface intact alongside the purchase additions.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MzGQaTFkYtzYR7Hq1jBoGR


Generated by Claude Code

claude added 2 commits July 12, 2026 23:31
A technician can now require the $50 diagnostic session at any point in a
help call: before connecting (quoting the work up front), mid-session, or
after disconnecting. Strictly optional and only ever raised by the
technician; the app never initiates a purchase.

The prompt (PurchaseModal) follows the approve-modal's design and walks
four beats driven by the node's cec://purchase events: the ask (item,
price, the asker's name — the standing approval's name when one exists,
else the name the ask carried, verified the same way the connect prompt's
is), "finish up in your browser" once the customer opens the secure
checkout, "confirming with your technician" after they tap
I've-completed-my-purchase, and "You're all set" when the technician
confirms the order actually landed in the store. Declining is always
available until it's settled; a technician withdrawal takes the prompt
down with a note.

No payment data ever touches the app or the mesh:

- "Open secure checkout" opens the customer's own default browser at the
  app's built-in purchase page (support.cec.direct/buy/diagnostic/) with
  attribution only (support number, reference, agent name) — the URL is
  never taken from the wire, and the new open_url Tauri command (via
  tauri-plugin-opener; the shell plugin's open is deprecated) refuses
  anything but that page. The now-unused shell:allow-open capability and
  shell open config are removed.
- The store's hosted checkout handles payment, receipts, and refunds; the
  technician verifies the order (it carries the Support Number as cart
  attributes) and confirms from their side. Human confirmation, no
  webhooks, no server — the same shape as the agent-name check.

Wiring: cec_purchase_status / cec_purchases passthrough commands (status
words validated locally so the crate still compiles against a
pre-purchase node release — the flow lights up at runtime once the
bundled node carries the relay), the Purchase type + bridge listeners,
store state + actions with a demo arc for the browser preview (plus a
"Preview the purchase prompt" affordance), and docs (README contract
table, ARCHITECTURE purchase section + trust model, ROADMAP status).

Also refreshes the stale gui/src-tauri Cargo.lock (v0.2.34 -> v0.2.35 to
match the manifest) and picks up rustfmt on build.rs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzGQaTFkYtzYR7Hq1jBoGR
…path

The purchase work moved URL-opening to tauri-plugin-opener and dropped the
shell plugin's open grant (shell:allow-open, the plugins.shell config) as
no longer used; main's waiting-screen TikTok link then arrived on the
deprecated shell open, quietly relying on config this branch removes. Port
it to the opener and drop tauri-plugin-shell entirely: every browser
hand-off now goes through the one plugin, hardcoded or checkout-gated, and
the deprecation warning goes with it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzGQaTFkYtzYR7Hq1jBoGR
@mrjeeves
mrjeeves force-pushed the claude/cec-diagnostic-purchase-integration-hgphzb branch from 6900ce0 to 11b44c3 Compare July 12, 2026 23:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants