About this app
UCSD Process Discovery is a voice-interview platform for finding repetitive administrative work, extracting evidence-backed process records, and turning those records into a ranked automation backlog for forward deployed engineering.
This page describes the production architecture, privacy boundaries, data flow, and model routing used by the application. It reflects the current runtime configuration without exposing API keys, secrets, participant records, or admin console data.
System at a glance
Admin console Interview participant
templates, campaigns, invites email link -> consent -> mic check
| |
| Resend email v
| browser <-> Vapi WebRTC voice call
| |
v v
Neon Postgres <----- Vapi webhooks / sweeps ----- call artifacts
|
v
analysis queue: redact -> extract -> score -> embed -> cluster -> rollup
|
v
backlog, heatmap, systems, synthesized themes, dossiers, reports, AskArchitecture
The web application is a Next.js App Router deployment on Vercel. The admin console manages templates, campaigns, invitations, consent documents, interviews, analysis results, and exports. The interview participant flow is token based: the participant opens a personal invitation link, accepts the consent notice, passes the microphone check, and starts the voice interview.
The realtime audio call does not run through Vercel. The participant browser connects directly to Vapi over WebRTC using the Vapi browser SDK. The app assembles a transient Vapi assistant immediately before each call. That assistant includes the current interview template, consent script, participant context, resume state, configured voice, model choice, per-call duration cap, and tool definitions, but it does not include server secrets.
Vapi sends status updates, tool calls, transcripts, summaries, and end-of-call reports back to /api/vapi/webhook. The webhook endpoint verifies the org-level Vapi secret, stores every webhook behind an idempotency gate, updates the call session, and kicks off the finalization path. Cron sweeps reconcile missed or delayed events, so webhooks are the fast path and polling is the durability backstop.
Neon Postgres is the source of truth. It stores campaigns, invitations, interview state, call sessions, stitched transcripts, redacted transcripts, analysis runs, process records, embeddings, clusters, themes, consent events, and email events. Postgres also acts as the queue for analysis work: each run has a stage cursor, retry count, lease, cost ledger, and status.
Participant flow
- Invitation: Resend sends a magic link from the verified sender. Links are personal, expire by campaign policy, and rotate whenever they are resent or copied.
- Consent: the participant accepts a versioned written consent notice before any call starts.
- Voice session: the app mints a call session and transient Vapi assistant. The participant speaks with the voice agent in the browser.
- Tool calls:the agent records spoken consent, marks sections complete, and can pause at the participant's request.
- Resume: if the participant pauses or disconnects, the next call receives a progress summary and resumes at the next unfinished section.
- Completion: the transcript is stitched across sessions, the invitation is marked complete, a receipt can be sent, and analysis is queued.
Voice stack
| Layer | Current implementation | Purpose |
|---|---|---|
| Realtime call transport | Vapi browser SDK over WebRTC | Keeps low-latency audio off the Vercel request path. Campaigns can set the hard call cap up to 43,200 seconds. |
| Conversation model | Vapi-native Anthropic, default claude-sonnet-4-6 | Runs the live voice interview and adapts the template questions into natural conversation. |
| Optional conversation override | Campaign claude_model can use custom:<id> with INTERVIEW_CUSTOM_LLM_URL | Allows an OpenAI-compatible endpoint, such as the Triton gateway, to power the live interview after latency testing. |
| Transcription | Deepgram nova-3 through Vapi | Produces the call transcript; template key terms are passed through to improve campus jargon recognition. |
| Voice | Campaign voice provider/voice id, default Vapi Elliot | Speaks the interviewer side of the conversation. |
| Operational Vapi analysis | Minimal summary and coverage JSON inside Vapi | Provides lightweight call-quality signals only. Authoritative extraction happens server-side after redaction. |
Analysis pipeline
The analysis pipeline is deliberately staged so each expensive or risky task has a narrow job. A run can resume from its last completed stage and can be re-run without changing prior successful runs until the new run succeeds. Pipeline version: 1.0.
| Stage | What it does | Output |
|---|---|---|
| Redact | Applies deterministic regex rules, then asks a redaction model to identify names and personal identifiers that should be removed. | Versioned redacted transcript. |
| Extract | Inventories recurring work processes, extracts one structured process record per process, and captures non-process theme mentions. Evidence quotes are required for factual process claims. | Process records, theme mentions, evidence, unknowns. |
| Score | Computes effort, pain, feasibility, confidence, and routing signals from extracted facets. | Priority fields used by the backlog. |
| Embed | Embeds redacted transcript chunks, process records, and theme mentions. | pgvector-searchable corpus for clustering and Ask. |
| Cluster | Joins similar process records across interviews, with LLM adjudication in the ambiguous range. | Canonical process clusters and membership. |
| Rollup | Aggregates clusters, department heatmaps, systems, and campaign-level theme synthesis. Themes are rebuilt from active successful analysis runs, then enriched with requirement implications and follow-up questions. | Backlog, heatmap, systems, themes, and analytics views. |
Each run has a hard cost circuit breaker of $5.00. On-prem Triton stages are recorded as zero marginal LLM cost; direct/cloud model usage is estimated from token counts.
Model routing
Analysis calls use model specs in the form onprem:<id>, cloud:<id>, or anthropic:<id>. Bare model IDs are treated as direct Anthropic models for backward compatibility. The current environment reports:
| Purpose | Current primary model | Fallbacks | Why this role uses it |
|---|---|---|---|
| Live voice conversation | claude-sonnet-4-6 via Vapi-native Anthropic, unless a campaign overrides it | Campaign-specific override | Optimized for low-latency turn-taking and natural interviewing rather than bulk analysis. |
| Redaction | onprem:api-gemma-4-26b | onprem:api-gpt-oss-120b, cloud:claude-sonnet-4-6 | Fast entity listing after regex redaction; this is the only analysis model stage that sees raw transcript text. |
| Process extraction | cloud:claude-sonnet-4-6 | onprem:api-gpt-oss-120b | Produces strict structured output for recurring processes, evidence, unknowns, systems, time, volume, and route signals. |
| Cluster adjudication | onprem:deepseek-v4-flash-max | onprem:api-gpt-oss-120b, cloud:claude-sonnet-4-6 | Resolves ambiguous semantic matches between process records when vector similarity alone is not decisive. |
| Themes | onprem:api-gemma-4-26b | onprem:api-gpt-oss-120b, cloud:claude-sonnet-4-6 | Consolidates raw theme mentions into campaign-level findings with descriptions, source breadth, requirement implications, recommended follow-up, and cited evidence. |
| Dossiers | onprem:deepseek-v4-flash-max | Manual regenerate action uses the configured dossier model. | Produces deeper opportunity write-ups for FDE review after a backlog item is selected. |
| Ask the interviews | onprem:api-gemma-4-26b | None by default for chat synthesis. | Uses retrieval over analyzed records and redacted transcript chunks, then returns cited answers grounded in the campaign corpus. |
| Embeddings | onprem:api-tgpt-embeddings | Can be changed with EMBEDDING_MODEL after vector schema validation. | Powers semantic search, clustering, Ask retrieval, and theme/process similarity. Only redacted text is embedded. |
| QA harness | cloud:claude-sonnet-4-6 | Development-only | Drives synthetic test interviews where roleplay quality matters more than production cost. |
Prompt versions: redact v1, extract v1, cluster v1, themes v1, dossier v1.
Privacy and data boundaries
- Raw transcript text is stored so administrators can audit interviews, but the analysis pipeline redacts before downstream extraction, embeddings, clustering, and Ask retrieval.
- Deterministic regex rules remove common identifiers such as SSNs, UCSD PID- shaped IDs, emails, phone numbers, and dates before the redaction model runs.
- The redaction model is instructed to remove third-party names and personal identifiers while preserving systems, departments, job roles, buildings, and process vocabulary.
- Campaigns can anonymize reports so FDE-facing views refer to people by role and department rather than name or email.
- Theme synthesis and Ask use active successful analysis outputs; failed and superseded analysis runs are not counted in current campaign themes.
- Audio recording is campaign-controlled. If retention is configured, recording URLs are purged by the retention cron while transcripts remain.
- Consent is versioned and captured twice: click-through consent before the call and spoken confirmation during the call.
Operations and reliability
The app uses Vercel Cron and Postgres leases instead of a separate queue service. The call sweep reconciles Vapi calls, the analysis sweep resumes queued or lease-expired analysis runs, reminders send pending follow-ups, the retention job removes expired recordings, and the nightly recluster job keeps campaign rollups current.
All important external inputs are made idempotent. Vapi webhooks are stored before processing, email sends are logged as email events, analysis stages are wipe-and-rewrite or versioned where appropriate, and successful re-analysis supersedes prior successful runs only after the new run completes.
Release Notes
2026-06-30 — Public About page, release notes, and richer theme synthesis
- Made this About page publicly accessible at /admin/about so stakeholders can review the platform architecture without console access.
- Made the How to use guide publicly accessible at /admin/guide with the same public navigation and sign-in affordance.
- Added the public About and How to use sections to signed-out and signed-in application navigation.
- Added release notes and refreshed the architecture, analysis, privacy, operations, and model-routing documentation.
- Upgraded Themes from raw one-off observations into campaign-level synthesized themes with source breadth, evidence links, requirement implications, and recommended follow-up actions.
- Theme consolidation now ignores failed or superseded analysis runs so re-analysis does not double-count stale theme mentions.
2026-06-29 — Higher runtime caps and resilient analysis budgets
- Raised the Vapi per-call hard cap to 43,200 seconds, matching Vapi's documented 12-hour maximum, while keeping the default target interview length concise.
- Made the per-run analysis cost ceiling configurable with a $5 default instead of a hardcoded $0.75 breaker.
- Re-ran the Atlassian EOL interview that had failed on the old analysis ceiling; it now completes analysis successfully.
2026-06-24 — Campaign cleanup and stale-rollup protection
- Added campaign-admin participant removal with explicit confirmation and cleanup of related interview, call-session, transcript, recording, and analysis data.
- Refreshing campaign clusters, themes, and dossier freshness after deletion prevents aggregate views from retaining removed participant data.
2026-06-11 — Email delivery observability
- Added Resend webhook ingestion and email event tracking so invitation status can distinguish sent mail from delivered, bounced, complained, or failed mail.
- Kept the production sender on the existing interviews@brettcpollak.com domain while improving delivery-state visibility.