Wiki · Workflow companion

Customer quote

Daily ops. Customer asks for pricing; AI drafts a quote; Mike approves; rendered HTML/PDF lands in the customer's inbox in under 15 minutes. Three HITL gates keep the loop tight.

Real · Daily ops
What this is

From "can I get pricing?" to a signed PDF in fifteen minutes

The customer quote workflow is the most-run flow on the platform. Customers email or call asking for pricing on assemblies, often by their own internal SKU. The AI gathers context (who they are, what they typically buy, current cost basis, AR status), proposes line-by-line pricing, Mike reviews, the system renders an HTML artifact + PDF, and the email goes out.

The contract is stored in workflow_definitions WHERE workflow_type='draft_quote' — risk level 2 (low-med), expected duration 15 minutes, three HITL gates at steps 1, 2, and 4.

The defining property: nothing about pricing is invented. Every line traces to pricing_master, assembly_cost_rollup, or an explicit override that Mike typed into chat. The AI narrates; the database decides.

When to use it

Trigger conditions

Worked example

Customer Z requests pricing on assembly A123

Scenario

Cardinal Foods (NS customer #1843) emails: "Can you quote A123 — Right Start Foods Breakfast Burrito assembly — for 5,000 cases monthly starting July?"

Mike opens chat, types "Draft quote: Cardinal, A123, 5,000 cases/mo July onwards". The draft_quote workflow starts. Within 90 seconds the AI has pulled Cardinal's customer 360 (30-day order history, AR aging — they're current, their typical bid eligibility), looked up A123's current cost rollup ($3.42 landed), proposed $4.18 per case (22% gross margin per Mike's standard), and rendered a side-by-side comparison.

Mike skims, taps Approve lines, then Approve send. The HTML quote artifact lands at /quote/Q2026-0512, the PDF goes into R2, and the email lands in Cardinal's inbox with a tracked link. Total wall-clock: 11 minutes.

Step-by-step what happens

The five beats

  1. 01

    Gather context (auto)

    The get_customer_360 chat tool pulls the customer record from the D1 mirror, the trailing-90-day order history, current AR aging buckets, and any flags from customer_health_scores. This becomes the prompt context for the line-builder.

    Reads customers, so_lines, customer_health_scores, ar_aging
    Time ~600ms
  2. 02

    Build lines (HITL)

    propose_quote looks up each assembly's cost in assembly_cost_rollup, applies the customer's negotiated margin band (or the platform default if none), and writes draft rows to quote_lines with status='draft'. A proposed_action row lands in Mike's queue.

    Writes quotes, quote_lines (draft), proposed_actions
    HITL step 1
  3. 03

    Approve lines (HITL)

    Mike taps Approve in /proposed-actions.html. The quote rows flip to status='approved' and the atomic claim (R560 pattern) prevents double-approval. Mike can edit individual lines before approving — those edits write back to the same quote_lines rows.

    Writes quote_lines.status='approved'
    Time Mike approves within 5–30 min typically
  4. 04

    Render PDF (auto)

    render_quote_pdf generates the HTML artifact (Pages Function at /quote/) and converts to PDF via Browser Rendering. Both land in R2 under quotes//. The HTML link is what gets put in the email body.

    Writes R2 quotes/
    Time ~4–8s
  5. 05

    Send to customer (HITL)

    A draft email row in outbound_email_log with status='pending_review'. Mike skims, taps Send, the email goes out via Email Routing. Event quote.sent is appended to the events ledger. The customer-facing tracked link is logged for open/click tracking.

    Writes outbound_email_log, events
    HITL step 4 (send)
Outcomes

What's different after the workflow runs

Quote artifact
Live
HTML + PDF in R2
Customer
Notified
Email tracked
Quote lines
Persisted
D1 audit trail
Cycle time
~15 min
Mike's bottleneck
Failure modes

What can go wrong and how to recover

Cost basis missing

If assembly_cost_rollup doesn't have a row for the requested assembly, the proposer refuses to invent a margin. Mike sees a "no cost basis" error and has to add the cost first (vendor cost update workflow).

Customer on credit hold

If the customer's customer_health_scores.risk_tier is red, the workflow surfaces a warning band but doesn't block. Mike decides; this is a soft guardrail not a hard one.

PDF render times out

Browser Rendering occasionally hits 30s. The HTML artifact still works — Mike can send just the link. Re-trigger PDF via POST /admin/quotes//regen-pdf.

Mike never sends

Most common quiet failure. The outbound_email_log dashboard has a "pending_review > 24h" filter to catch these. Daily 9am digest highlights them too.

Related

Adjacent workflows + diagrams

For developers

Code paths + invariants

ConcernWhere
Workflow contractworkflow_definitions WHERE workflow_type='draft_quote'
Customer 360src/chat_tools/impls.ts get_customer_360
Line buildersrc/chat_tools/impls.ts propose_quote
PDF renderrender_quote_pdf — Browser Rendering binding
HTML artifactpages-functions/quote/[id].ts
HITL gatessteps 1, 2, 4 — see hitl_gates_json
Cost rollup invariantnever invent margin — refuse if assembly_cost_rollup empty
Email sendCloudflare Email Routing — outbound_email_log first