Technical Track Record
Case 05: DNA Clotilde ā AI-Powered Sales Enablement
Briefing
Sales teams often lose momentum when switching between lead context and structured sales methodologies (SDR/Closer). DNA Clotilde was conceived as a copilot assistant that reduces cognitive load by delivering scripts, objection handling, and real-time meeting audio summaries, while preserving brand voice and tone.
Technical Deep Dive
I implemented an SSE (Server-Sent Events) streaming architecture to deliver a fluid, responsive chat experience with token cancellation for cost optimization. The AI engine uses dynamic prompt engineering to adjust tone, formality, and objectives based on operating mode (SDR or Closer). I also integrated an asynchronous transcription pipeline with AssemblyAI and Vercel Blob, enabling analysis of real conversations and extraction of insights with structured citations (T#) to ensure factual traceability.
Insight & Objection Matrix
Documentation
Monorepo with frontend (Vite + React + TS) and backend (Express + SSE) for a commercial assistant (SDR/Closer), featuring response streaming, next-action suggestions, and audio transcription support.
Features
- SSE streaming chat with response cancellation
- SDR/Closer mode, tone, formality, and objective configurable
- Automatic suggestions by objective (action chips)
- Quick templates per objective and mode
- Image and text attachments to enrich context
- Audio transcription via URL or upload (AssemblyAI + Vercel Blob)
- Embeddable widget via query param
?widget=commercial(client-simulated responses) - Per-message feedback (š/š) and session export
- UI with design system tokens and microinteractions (GSAP)
Summary
- Overview
- Architecture
- Core Flows
- Technical Stack
- Repository Structure
- Running Locally
- Environment Configuration
- API
- Deploy
- Observability and Logs
- Security and Privacy
- Limits and Quotas
- Troubleshooting
- Tests and Quality
- Maintenance
- Internal References
Overview
The project delivers a chat experience focused on commercial activities (SDR/Closer), with LLM-generated answers via SSE streaming. The frontend maintains local conversation state and provides operational features (templates, suggestions, export, transcription), while the backend concentrates streaming and integrations with OpenAI and AssemblyAI.
The monorepo also includes serverless functions for Vercel deployment (frontend/api), enabling operation without the Express backend in production when desired.
Architecture
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā CLIENT (Browser) ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā Frontend (Vite + React) ā ā
ā ā - UI, state (Zustand), templates, suggestions ā ā
ā ā - SSE client, cancellation, export ā ā
ā ā - Transcription (URL / upload) ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā ā ā
ā ā /api (prod) ā ā
ā ā¼ ā¼ ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā Vercel Functions ā ā Express Backend ā ā
ā ā frontend/api/* ā ā backend/src ā ā
ā ā - /api/chat/stream (SSE) ā ā - /chat/stream (SSE) ā ā
ā ā - /api/transcriptions ā ā - /transcriptions ā ā
ā ā - /api/blob/upload ā ā - /blob/upload ā ā
ā ā - /api/analyze ā ā - /diagnostics/llm ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā ā ā
ā ā¼ ā¼ ā
ā OpenAI / LLM AssemblyAI ā
ā ā ā ā
ā āāāāāāāāāāāāāāāā Vercel Blob āāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāCore Flows
1) SSE streaming chat
- Endpoint:
POST /chat/stream(backend) orPOST /api/chat/stream(Vercel) - SSE format with events
open,ping,error,suggestions, andend - Frontend consumes the stream, aggregates chunks, and reports UX metrics (time to first token and total)
Example payload:
{
"message": "I need an outreach script",
"mode": "SDR",
"tone": "brief",
"formality": "informal",
"objective": "qualify",
"attachments": [
{ "kind": "text", "content": "Lead context...", "name": "context.txt" },
{ "kind": "image", "content": "data:image/png;base64,..." }
]
}Returned events (example):
event: open
data: {}
data: {"chunk":"Hello!"}
event: suggestions
data: {"suggestions":["Ask about budget", "..." ]}
event: end
data: {}2) Templates and suggestions
- Predefined templates by mode:
GET /templates?mode=SDR|Closer - Automatic suggestions emitted by the backend when a response is valid
3) Audio transcription
URL flow:
- Frontend calls
POST /transcriptions(backend) orPOST /api/transcriptions(Vercel) withaudio_url - Backend creates a transcription on AssemblyAI and returns
{ id, status } - Frontend polls
GET /transcriptions/:idorGET /api/transcriptions/:id
File flow:
- Frontend uploads to Vercel Blob via
POST /api/blob/upload - Receives a public blob URL
- Creates transcription via
POST /api/transcriptionswithaudio_urlpointing to the blob
4) Analysis with citations (serverless)
- Endpoint:
POST /api/analyze - Objective: transcript analysis with fixed structure and citations (T# for transcript, W# for Web)
- Optional Web support via Tavily (
enableWeb=true) - Truncates transcripts at 20k characters and applies chunking (800 with 120 overlap)
Minimum payload:
{
"query": "Summary with risks and next steps",
"transcriptText": "..."
}5) LLM provider
LLM_PROVIDER controls the engine used in the Express backend:
openai_chat(default): real streaming via Chat Completions, with model fallback when streaming is restricted.openai_assistants: uses Assistants API v2 with ephemeral threads and polling; streaming is simulated by chunking the final response.
Technical Stack
| Layer | Technology | Version | Notes |
|---|---|---|---|
| Frontend | React | 18.3.1 | SPA with SSE streaming and interactive UX |
| Frontend | Vite | 5.4.x | Build and dev server with /api proxy |
| Frontend | TypeScript | 5.9.x | Static typing |
| Frontend | Tailwind CSS | 4.1.x | Design system tokens and utilities |
| Frontend | Zustand | 4.5.x | State store for chat and UI |
| Frontend | GSAP | 3.13.x | Microinteractions and motion |
| Backend | Node.js | 20.x | Defined in .nvmrc |
| Backend | Express | 4.19.x | API and SSE |
| Backend | Zod | 3.23.x | Payload validation |
| Backend | pino | 9.x | Structured logging |
| Integrations | OpenAI | Chat/Assistants API | Streaming and model fallback |
| Integrations | AssemblyAI | v2 | Audio transcription |
| Storage | Vercel Blob | ā | Direct client upload |
| Web Search | Tavily | ā | Optional in /api/analyze |
Repository Structure
.
āāā backend
ā āāā src
ā ā āāā index.js # Express API, SSE, integrations
ā ā āāā config.js # Environment variables
ā ā āāā llm # OpenAI Chat + Assistants adapter
ā ā āāā utils # errors, retries, SSE parser
ā āāā test # Tests (Vitest + Supertest)
āāā frontend
ā āāā api # Serverless functions (Vercel)
ā āāā src
ā ā āāā ui # Components and hooks
ā ā āāā store # Zustand slices
ā ā āāā utils # SSE, transcription, logging
ā āāā e2e # Playwright
āāā docs
ā āāā design-system.md # Tokens and guidelines
āāā README.mdRunning Locally
Prerequisites:
- Node.js 20.x (
.nvmrc) - npm 8+
Steps:
- Install dependencies at the repo root
npm install- Start frontend and backend in dev mode
npm run devDefault ports:
- Backend:
http://localhost:3001 - Frontend:
http://localhost:5174
Build and run backend:
npm run build
npm run startEnvironment Configuration
Express Backend (backend/src/config.js)
| Variable | Default | Usage |
|---|---|---|
PORT | 3001 | Backend port |
CORS_ORIGIN | * | Express CORS |
OPENAI_API_KEY | ā | OpenAI key (required) |
OPENAI_BASE_URL | https://api.openai.com/v1 | OpenAI endpoint |
OPENAI_MODEL_PREFERRED | gpt-4o-mini | Preferred model (streaming) |
OPENAI_MODEL_FALLBACK | gpt-4o-mini | Streaming fallback model |
OPENAI_MODEL | gpt-4o-mini | Legacy config compatibility |
OPENAI_FALLBACK_MODEL | gpt-4o-mini | Legacy config compatibility |
OPENAI_TEMPERATURE | 0.7 | Model temperature |
OPENAI_MAX_TOKENS | 800 (chat) / 1800 (analyze) | Max tokens |
OPENAI_ASSISTANT_ID | ā | Assistants API (if LLM_PROVIDER=openai_assistants) |
LLM_PROVIDER | openai_chat | openai_chat or openai_assistants |
ASSEMBLYAI_API_KEY | ā | AssemblyAI key (transcription) |
ASSEMBLYAI_BASE_URL | https://api.assemblyai.com/v2 | AssemblyAI base |
LOG_LEVEL | info | pino log level |
Frontend (Vite)
| Variable | Default | Usage |
|---|---|---|
VITE_BACKEND_URL | http://localhost:3001 | Backend base in dev |
VITE_TRANSCRIBE_TIMEOUT_MS | 120000 | Total transcription timeout |
VITE_TRANSCRIBE_INITIAL_DELAY_MS | 1000 | Initial polling delay |
VITE_TRANSCRIBE_MAX_DELAY_MS | 5000 | Max polling delay |
VITE_TRANSCRIBE_BACKOFF_FACTOR | 1.5 | Polling backoff |
VITE_MAX_UPLOAD_MB | 500 | Preventive upload limit |
VITE_DEBUG_UI | false | Visual debug for metrics |
Vercel Functions (frontend/api)
| Variable | Default | Usage |
|---|---|---|
OPENAI_API_KEY | ā | OpenAI key |
OPENAI_BASE_URL | https://api.openai.com/v1 | OpenAI base |
OPENAI_MODEL | gpt-4.1 | Model for /api/chat/stream and /api/analyze |
OPENAI_TEMPERATURE | 0.7 | Temperature |
OPENAI_MAX_TOKENS | 800 | Max tokens |
ASSEMBLYAI_API_KEY | ā | Transcription |
ASSEMBLYAI_BASE_URL | https://api.assemblyai.com/v2 | AssemblyAI base |
TAVILY_API_KEY | ā | Optional web search for /api/analyze |
CHAT_STREAM_TIMEOUT_MS | 90000 | Serverless stream timeout |
Notes:
- In production, the frontend ignores
VITE_BACKEND_URLwhen pointing tolocalhostand uses/api(Vercel). - Do not commit
.env.
API
Express Backend
GET /health
- Returns
{ status: "ok" }.
POST /chat/stream (SSE)
- Accepts:
{ message, mode, tone, formality, objective, attachments } - Returns
text/event-stream, heartbeat every 15s.
GET /templates
- Query:
?mode=SDR|Closer - Returns predefined templates by objective.
POST /feedback
- Body:
{ rating: "up"|"down", reason?: string } - Logs feedback only.
GET /diagnostics/llm
- Streaming diagnostics for preferred model.
- Returns
canStream,recommendation, and details.
POST /transcriptions
- Body:
{ audio_url, speaker_labels?, language_code? } - Returns
{ id, status }.
GET /transcriptions/:id
- Returns transcription status and content.
POST /blob/upload
- Token proxy for Vercel Blob upload.
POST /transcriptions/upload
- Proxy for direct AssemblyAI upload (legacy).
Vercel Functions
POST /api/chat/stream
- Serverless SSE stream.
- Implements dedicated rate limit and timeout.
POST /api/transcriptions
GET /api/transcriptions/:id
POST /api/blob/upload
- File upload to Vercel Blob (token issuance).
POST /api/transcriptions/upload
- Deprecated endpoint (returns
410).
POST /api/analyze
- Structured analysis with T# and W# citations.
Deploy
Option 1: Monorepo with Express backend
- Run
npm run buildat the root. - Run
npm run startin the backend. - Publish the Vite frontend output (
frontend/dist).
Option 2: Vercel (serverless)
- Functions in
frontend/apireplace the Express backend. - Frontend uses
/apiautomatically in production. - Configure environment variables in Vercel per the table above.
Observability and Logs
- Express backend uses
pinoandpino-httpwith structured logs. - Serverless functions use JSON logs and
requestIdfor tracing. - Frontend logs UX metrics without PII (
logUX).
Security and Privacy
- No authentication and no data persistence in v1.
- In-memory rate limit per IP (5 min window).
- CSP configured in
vercel.jsonto limit origins. - UI renders text only, no arbitrary HTML, preventing XSS.
- Avoid sending PII or secrets in chat.
Limits and Quotas
- Chat input: 2000 characters.
- Text attachment: up to 1 MB.
- Image attachment: up to 4 MB.
- Transcription upload: preventive limit
VITE_MAX_UPLOAD_MB(default 500 MB). - Rate limit: 60 req/5min (general) and 30 req/5min (chat).
Troubleshooting
MISSING_API_KEY: configureOPENAI_API_KEYorASSEMBLYAI_API_KEY.- Streaming not allowed: use
OPENAI_MODEL_FALLBACKor adjust the model. TIMEOUT: increaseCHAT_STREAM_TIMEOUT_MSor reduceOPENAI_MAX_TOKENS.- Transcription errors: ensure the audio URL is public and accessible.
Tests and Quality
Backend:
npm run test -w backend
npm run lint -w backendFrontend:
npm run test -w frontend
npm run e2e -w frontend
npm run lint -w frontend
npm run lint:stylesMaintenance
npm auditandnpm audit fixfor security.- Update dependencies periodically.
- Review tokens and guidelines in
docs/design-system.md.
Internal References
- Design system:
docs/design-system.md - Plan and requirements:
prd.md,plan.md