A customer must click a URL and see their own data within 30 minutes of the meeting starting. The Vite + React + TS + TanStack stack, token streaming for perceived speed, zod-validated agent endpoints, an “evals as UI” page, and the demo-engineering discipline that keeps a credible prototype from leaking secrets or stalling the room.
The 30-minute rule
FDE prototypes live or die by one rule: a customer must be able to click a URL and see their own data within 30 minutes of the engineering meeting’s start. Not a Figma, not a deck — a working surface over their data. This is demo-driven development: every cycle ends with a live demo on customer data inside the customer’s environment, which kills the “works on my laptop” failure mode and forces scope discipline. This lesson is the credible-prototype stack — fast enough to edit live in front of the room, structured enough not to leak secrets or fall over.
The senior framing: the prototype is a “gravel road,” not a paved highway — ship the smallest thing that solves one real workflow, accept rough edges, productize the path only after you’ve proven the route. You are not building production frontend; you are building the shortest credible path from the customer’s data to a clickable answer, with just enough hardening (validation, secret hygiene, an evals page) that it survives the demo and earns the next meeting.
The stack the research converges on: Vite + React 18 + TypeScript for the app, TanStack Router for type-safe file-based routes (the route tree as “the application contract”), TanStack Query for REST/GraphQL data fetching, and a small FastAPI/Express service that proxies to the LLM, the vector DB, and the CRM/ticketing connector from lesson 4. Vite is the choice because HMR happens in tens of milliseconds — you can edit a component live while the customer’s team watches, which is the actual superpower of a forward-deployed demo. The right spine to learn it is Full Stack Open Parts 0–7 (SPA fundamentals, REST/GraphQL, state, React Router, TypeScript); a junior who’s done Parts 0–7 plus one TS project can ship a “looks-like-product” demo on day two of an engagement.
Why type-safe routing matters for an FDE specifically: when you’re editing under time pressure in front of a customer, a typo in a route param or a missing search param is the kind of error that breaks the demo in the worst moment. TanStack Router makes the route tree and its params part of the type system, so the compiler catches the break before the customer does. Interview angle. OpenAI FDE system design weights real-time UX, streaming, tenant isolation, and frontend/product architecture — not just backend scale — so being fluent in the prototype frontend is a graded skill, not a nice-to-have.
The full prototype stack, end to end: Vite + React 18 + TypeScript + TanStack Router (file-based) + TanStack Query on the client, a small FastAPI/Express proxy in the middle that holds secrets and wraps the lesson-2 envelope, and the LLM + vector DB + CRM/ticketing connector behind it. The FDE arc of Full Stack Open — Parts 0–7 — maps onto exactly this: SPA fundamentals (Part 0–1), communicating with a server (Part 2–3), state management (Part 6), React Router (Part 7), and TypeScript (Part 9). You don’t need Parts 10–13 (React Native, CI/CD, containers, relational DBs) to ship a credible demo; you need the front-to-back request path working in days.
tsx
1// FDE prototype shape: a typed route + a streamed agent call. ~30 minutes to data.2import { createFileRoute } from '@tanstack/react-router'34export const Route = createFileRoute('/customer/$accountId')({5 loader: ({ params }) => fetchAccount(params.accountId), // type-safe params6 component: AccountView,7})89function AccountView() {10 const account = Route.useLoaderData()11 const [answer, setAnswer] = useState('')1213 async function ask(q: string) {14 // stream tokens so the demo FEELS fast (perceived latency = quality)15 const res = await fetch('/api/agent', {16 method: 'POST',17 body: JSON.stringify({ accountId: account.id, q }),18 })19 const reader = res.body!.getReader()20 const dec = new TextDecoder()21 for (;;) {22 const { value, done } = await reader.read()23 if (done) break24 setAnswer((a) => a + dec.decode(value)) // render incrementally25 }26 }27 return <Chat account={account} onAsk={ask} answer={answer} />28}
Streaming: perceived latency is the demo’s quality signal
Stream tokens with stream=true on the chat completion, render incrementally, and the demo feels fast even when total latency is identical — the recurring production lesson is that latency is perceived as quality. A 2-second answer that streams from the first token reads as responsive; the same 2 seconds with a spinner reads as broken. For an FDE this is doubly true: the customer’s first impression of the whole system is formed in the first 500ms of the first demo. Gate the streaming endpoint behind a per-customer rate limiter so a runaway loop in the demo doesn’t blow the API budget or trip the provider’s limits mid-meeting.
The thin proxy: where secrets, validation, and the envelope live
The whole backend of an FDE prototype is a thin proxy — a small FastAPI or Express service that the React app talks to instead of calling the model or the CRM directly. It earns its keep four ways: it holds the secrets (no API key ever ships to the browser), it validates every request with a schema (zod in TS, Pydantic in Python) so a malformed payload returns a clean 422 not a 500 in front of the room, it rate-limits per customer so a demo loop can’t blow the budget, and it’s where the lesson-2 envelope (idempotency key, retries, signature checks) wraps each downstream write. Thirty lines of proxy is what makes the prototype safe to screen-share and safe to hand over.
ts
1// The proxy endpoint: validate -> rate-limit -> call (with the L2 envelope) -> stream.2import { z } from 'zod'34const Ask = z.object({ accountId: z.string(), q: z.string().min(1).max(2000) })56app.post('/api/agent', async (req, res) => {7 const parsed = Ask.safeParse(req.body)8 if (!parsed.success) return res.status(422).json(parsed.error) // clean, not a 5009 if (!rateLimit(parsed.data.accountId)) return res.status(429).end()1011 res.setHeader('Content-Type', 'text/event-stream')12 // secret lives here, on the server -- never in the bundled client13 const stream = await openai.chat.completions.create({14 model: 'gpt-4o', stream: true,15 messages: buildMessages(parsed.data),16 })17 for await (const chunk of stream) res.write(chunk.choices[0]?.delta?.content ?? '')18 res.end()19})
Hardening the prototype just enough
The post-prototype checklist that keeps a gravel road drivable: (1) pin Vite/React/TS versions in package.json so the demo machine and your laptop agree; (2) write the agent-loop endpoint in TypeScript with zod schema validation on every request and the structured output, so a malformed payload returns a clean 422 instead of a 500 in front of the room; (3) wrap every LLM call in the retry envelope from lesson 2; (4) add an “evals as UI” page that runs the 20 golden samples on a button click. That evals page does double duty — it’s your hardening and it’s the demo’s “this is how we know it works” slide, turning the eval-driven discipline of lesson 3 into a customer-facing artifact.
Demo-engineering discipline is its own skill: stand up a sandbox environment with the customer’s data shape (not necessarily their production data), manage secrets so no API key is ever hard-coded into client-side code or a screen-shared file, and respect data boundaries — the metadata-translation-layer pattern from the OpenAI FDE playbook lets the LLM access customer data in place when the customer won’t let you copy production data into your control plane. Interview angle. The client-simulation round will hand you a Salesforce integration that “stopped syncing” and ask you to debug and communicate — the prototype is the surface you debug on, live, while narrating to a non-technical stakeholder.
The evals-as-UI page is the highest-leverage 30 lines in the whole prototype: a button that runs the 20 golden samples against the live agent and renders pass/fail with the diff. It hardens you (you catch a regression before the customer does) and it pre-answers the room’s inevitable “but how do we know it’s actually right?” — converting the eval-driven discipline of lesson 3 into a screen the customer can watch. When a VP asks for proof, you click a button instead of arguing.
tsx
1// evals-as-UI: the "this is how we know it works" page, ~30 lines.2function EvalsPage() {3 const [rows, setRows] = useState<EvalRow[]>([])4 async function run() {5 const res = await Promise.all(6 GOLDEN.map(async (g) => { // GOLDEN = the 20 labeled samples7 const got = await ask(g.input)8 return { ...g, got, pass: grade(g.expected, got) } // code-based grade9 }),10 )11 setRows(res)12 }13 const passRate = rows.filter((r) => r.pass).length / (rows.length || 1)14 return (15 <div>16 <button onClick={run}>Run 20 golden evals</button>17 <p>pass rate: {(passRate * 100).toFixed(0)}%</p>18 {/* render each row's input / expected / got / pass for the customer to see */}19 </div>20 )21}
A junior who finished Full Stack Open Parts 0–7 and one TypeScript project can ship a “looks-like-product” demo on day two of an engagement. — the concrete prototype-velocity bar the research sets.
Case studies: speed and the perceived-quality lever
The cross-company production lesson maps straight onto prototypes. Notion invested heavily in cutting AI chat latency at consumer scale on the framing that “latency is perceived as quality”; the prototype analogue is streaming + a fast HMR loop so the demo never feels slow. Palantir’s COVID-19 deployments were “operational within days” because Deltas shipped the smallest composed capability and demoed on real data immediately — gravel road first. OpenAI’s “eat pain and excrete product” means the prototype isn’t throwaway: the rough demo surface that works at one customer becomes a reusable building block. The time-to-first-value targets from the research are concrete — kickoff → first demo on customer data: 2–7 days; first production rollout: 14–60 days — and the frontend is what makes the 2-day demo possible.
Ship the smallest thing that solves one real workflow; demo it on customer data within a week. The prototype is a gravel road you pave only after you’ve proven the route. — demo-driven development.
Interview prep
FDE rounds test prototype velocity and the judgment around it: “build a credible demo UI fast,” “tie the technical solution to a specific customer use case,” and the client-simulation where you debug a broken integration live. Lead with the 30-minute-to-data instinct, the gravel-road framing, and the streaming/secret-hygiene defaults.
01“How do you get a customer clicking their own data fast?” → Vite + React + TS + TanStack over a thin FastAPI/Express proxy; demo on real data in 30 minutes.
02“Why does the demo feel slow even though latency is fine?” → you’re not streaming; stream tokens from the first one — perceived latency is quality.
03“Where do the API keys live in your prototype?” → never in client code; a tiny proxy holds secrets, validates with zod, rate-limits per customer.
04“How do you keep a live edit from breaking the demo?” → type-safe routing + zod validation so the compiler catches param/payload errors before the customer does.
05“The customer won’t let you copy production data — now what?” → metadata translation layer; let the model access data in place, sandbox with the data shape.
06“How do you show the customer it works?” → an ‘evals as UI’ page that runs the 20 golden samples on click — hardening doubling as the proof slide.
07“What’s your first-week deliverable?” → a clickable prototype over their data plus a 20-sample eval; gravel road, not a paved platform.
08“A Salesforce integration stopped syncing in the demo — what do you do?” → debug live on the prototype surface while narrating the diagnosis to the non-technical stakeholder.
Follow-ups push on judgment and scope: “if the customer pulled the budget, where would you cut?” (keep the one workflow that proves value, drop the rest), “what would you build first in week 1?” (the thin end-to-end walking skeleton: data → agent → answer on screen), and “how do you split frontend work with the customer’s team?” (you own the demo surface and the proxy; they own data access and sign-off). The interviewer wants the muscle memory of having actually shipped a prototype on a customer’s clock — so anchor to one you built and what you deliberately left rough.
Kickoff is in 30 minutes. The customer expects to see something working on their data. What do you build?
AA polished, production-grade frontend with full component architectureBA thin walking skeleton — Vite + React + TS over a small proxy — that takes their data → agent → a streamed answer on screenCA Figma mockup of the eventual product to align on direction first
Your prototype’s answers are correct but the room reacts flatly — there’s a multi-second spinner before each reply. Best fix?
ASwitch to a smaller, faster model to cut total latencyBStream tokens from the first one and render incrementally so the answer feels responsiveCAdd a longer, more detailed loading animation
To move fast, a teammate calls the LLM API directly from the React component with the key in an env var bundled into the client. Why stop them?
AThe key ends up in client-side code — visible in the network tab and leaked the moment you screen-share or hand over the URL; proxy through a tiny server insteadBIt’s fine for a demo — keys in the client are acceptable for prototypesCDirect calls are slower than going through a server
The customer won’t allow their production data to be copied into your cloud, but still wants a working demo. What’s the move?
AInsist that a copy is required to build anything usefulBUse a metadata translation layer so the model accesses customer data in place, and sandbox the prototype against the data shapeCMock up fake data and hope it’s close enough to their real data
You want the prototype to also answer the customer’s “but how do we know it’s actually right?” in the same demo. What do you add?
AA confidence percentage next to each answer from the model’s self-reported certaintyBA longer system prompt instructing the model to be accurateCAn ‘evals as UI’ page that runs the 20 golden samples on a button click and shows pass/fail
Could you stand up a credible, streamed, secret-safe prototype over a customer’s data in under an hour — and defend the gravel-road scope in a client simulation?
New to itGetting thereConfident
Takeaways
The bar: a customer clicks a URL and sees their own data within 30 minutes — demo-driven development.
Stack: Vite + React + TS + TanStack (type-safe routes) over a thin FastAPI/Express proxy.
Stream tokens from the first one — perceived latency is quality; spinner-then-dump lands flat.
Never put secrets in client code; proxy holds keys, validates with zod, rate-limits per customer.
Harden just enough: pin versions, validate, wrap LLM calls in the retry envelope, add an evals-as-UI page.
Gravel road, not paved highway: ship the one workflow that proves value, pave only after the route is proven.
Next: the capstone — an integrated assistant end to end across real systems, and the full FDE interview loop.