No benchmark, user count, or production support volume was recorded for this take-home project.
Architecture and source evidence onlyReviewed 2026-08-31Case 10 / Take-home support assistant
Spur Chat
Spur Chat is a bounded streaming support interface for Lumio, a fictional brand, built as a take-home and presented without pretending its suspended backend is a working live assistant.
- Role
- Full-stack engineer
- Built at
- Take-home assignment
- Contribution
- Interface, API, streaming, retrieval, and recovery
- Status
- Take-home

Measured, with the denominator attached
Proof before polish.01 / What it is
A deliberately small support surface for a fictional brand.
Spur Chat was a take-home project for a fictional direct-to-consumer brand.
It retrieves catalogue and policy context, then streams a bounded support response in the browser.
A shopper asking catalogue or policy questions inside a small direct-to-consumer support widget, and an evaluator inspecting a bounded take-home implementation.
I built the responsive chat interface, Node and TypeScript API, retrieval scope, PostgreSQL session history, SSE stream parser, request deduplication, failure taxonomy, feedback controls, and deployment documentation.
Contribution record
02 / Product proof
See the actual product before reading the argument.
Real desktop capture


Desktop and mobile surfaces expose the fictional Lumio assistant, conversation list, input, and recovery affordances.
- Transport
- Server-Sent Events over POST
- Parser
- Buffered line framing
- Events
- chunk, done, and error
The frontend reads POST response chunks, buffers incomplete lines, and handles chunk, done, and error SSE events without requiring WebSockets.
- Frontend
- HTTP 200
- Backend health
- Service Suspended
- Complete chat turn
- Could not run
The frontend remains available, but health and message requests cannot complete while the backend service is suspended.
03 / Problem and responsibility
A polished chat shell does not prove that the backend can complete a turn.
A generic assistant can answer smoothly while ignoring the catalogue and policy constraints it is supposed to represent.
The useful scope was narrow: show retrieval, response streaming, and a visible boundary without pretending the exercise was a deployed client system.
- Frontend
- Responsive chat, buffered SSE parsing, typing and error states, session recovery, feedback, and request deduplication.
- Backend
- Node and TypeScript API, retrieval scope, PostgreSQL history, stream events, health check, and failure handling.
- Delivery
- Separate Vercel and Render deployment, exact-origin CORS diagnosis, documentation, and truthful live-state reporting.
04 / Research that changed the build
Research only matters here when it changed a decision.
- 01
SSE versus WebSockets
The product needs one-way incremental output after a POST body, not a permanent bidirectional socket.
The client uses fetch plus ReadableStream and parses SSE frames from the POST response. - 02
Buffered stream parsing tests
Network chunks do not align with event or line boundaries, so parsing each received chunk independently loses or corrupts data.
The client carries an incomplete-line buffer and only parses complete data frames. - 03
Bounded context and session recovery
A support conversation needs enough history to remain coherent without resending an unbounded transcript.
History is persisted by session and the model receives a bounded context window. - 04
Deployment failure taxonomy
A healthy frontend, suspended backend, exact CORS-origin mismatch, mid-stream loss, and malformed event are different failures.
User-visible errors and docs distinguish reachability, configuration, and stream completion instead of showing one generic typing state.
05 / Architecture
Keep retrieval scope visible beside the streamed answer.
The client sends the support question, the backend retrieves the relevant brand material, and the response streams with that scope attached.
The public story names the project as a take-home and makes no user, client, or production-scale claim.
- 01Chat clientSends a message and optional session identifier
- 02Support APIValidates, deduplicates, retrieves bounded Lumio context
- 03SSE streamEmits chunk, done, or error events over the POST response
- 04Session storePersists messages for refresh and later history recovery
- 05FeedbackAttaches an up or down record to an AI message
06 / Decisions and trade-offs
What I chose, what I rejected, and what the choice costs.
Use WebSockets or wait for one blocking JSON reply.
The parser must handle partial frames, while the transport matches one-way answer streaming without socket infrastructure.
Treat every message as an isolated stateless completion.
The backend and database contract grow, while refresh recovery and duplicate-send handling become possible.
Call the suspended deployment a working demo or fabricate a streamed answer.
The public proof is weaker, while the current live state is accurate.
07 / Evidence
The interface is reachable. The backend and complete turn are not.
No benchmark, user count, or production support volume was recorded for this take-home project.
No publishable outcome or usage denominatorNo user, customer, traffic, answer-quality, or support-outcome number is published. Current proof is limited to source architecture, real interface captures, frontend reachability, and a failed backend health check.
08 / What failed
The failures are part of the architecture record.
01 Frontend and backend were deployed separately
- What I saw
- The interface loaded while the assistant could not complete a reply.
- Why
- Vercel continued serving the client after the Render backend became unavailable and is now suspended.
- What changed
- The public action now says View the interface and the case study labels interaction unverified.
- Still true
- The live assistant remains unusable until a backend and database are restored and checked end to end.
02 One trailing slash broke CORS
- What I saw
- Browser requests failed even while the backend health endpoint responded.
- Why
- CORS origin matching is byte-exact, and the configured frontend URL included a trailing slash.
- What changed
- Deployment docs require the exact origin without a trailing slash and separate health from browser-origin checks.
- Still true
- Future domain or preview URLs still need explicit allowed-origin verification.
03 A stream could close without done
- What I saw
- The interface could remain in a typing state after the connection ended mid-response.
- Why
- Transport completion was treated as equivalent to receiving a semantic done event.
- What changed
- The parser tracks completion and reports a specific error when the stream closes before done.
- Still true
- The unavailable backend prevented a fresh production completion check in this batch.
09 / Limits and future
What the product cannot do yet, beside what may come next.
Current limitations
- Lumio is fictional, and Spur Chat was a take-home assignment rather than a client product.
- The frontend returned HTTP 200 on 2026-08-31, but the backend service was suspended and one complete chat turn could not be verified.
- The current captures show the genuine entry state and do not prove answer quality, retrieval quality, users, customers, or traffic.
- Separate frontend and backend deployment leaves availability, CORS, and database state as independent failure surfaces.
Deliberate boundaries
- Imply that the fictional brand was a client.
- Add a usage number that was never measured.
Restore backend service
Re-establish the API and PostgreSQL, then rerun health, exact-origin preflight, one complete streamed turn, history recovery, and feedback.
Capture a verified complete turn
Replace the entry-state-only proof after a successful chunk-to-done stream is observed and recorded without private data.
Co-located deployment
Evaluate whether one deployment boundary would reduce CORS and split-availability failures without overbuilding the take-home.
10 / Stack and sources
The systems underneath it, and where this account comes from.
- TypeScript
- streaming responses
- retrieval
- web client