Skip to content

How we build product workflows

Velyn Dental relies on a few engineering basics: clear triggers, fast responses, useful records, and fallbacks when a dependency fails.

What we are building: Product workflows that answer calls, save the record, and prepare follow-up without hiding what happened from the practice.

Core Principles

Background Work With Clear Triggers

Some work should happen without anyone babysitting the screen: answering calls, saving transcripts, and preparing follow-up.

→ Event-driven architecture with scheduled checks, explicit thresholds, and traceable actions.

Models Are Only Part of the Product

The hard parts are reliability, latency, fallbacks, and the rules around when to alert or hand off.

→ Streaming pipelines, fallback chains, and state machines that handle edge cases gracefully.

Latency Changes Trust

A voice workflow that waits too long feels broken. A callback task that shows up hours late is not useful.

→ Parallel processing, warm connections, predictive caching, and aggressive optimization.

Designed for Early Scale

Serverless-first architecture keeps small launch traffic simple and gives busy periods room to grow.

→ Vercel Functions + edge compute, connection pooling, and usage-based pricing that scales linearly.

Fail Gracefully, Always

APIs time out. Networks drop. Models can fail. The product needs a clear fallback instead of a silent dead end.

→ Circuit breakers, fallback responses, retry logic with exponential backoff, and monitoring at every layer.

Ship Fast, Learn Faster

Real use teaches what demos cannot. We optimize for small releases, visible monitoring, and fast correction.

→ Feature flags, canary deployments, real-time monitoring, and weekly release cycles.

Architecture Patterns

These patterns recur throughout Velyn Dental. They keep call handling, handoffs, and follow-up work understandable under stress.

1

Event-Driven Monitoring

Problem

How do you know when to take action without constantly asking?

Solution

Scheduled background jobs (cron) that check state and act when conditions are met.

Real Example

Velyn Dental runs a scheduled job every 30 minutes. When it is 7 a.m. in a practice's time zone, it emails the team a digest of the calls and callback tasks that came in after hours. A per-practice, per-day claim keeps the email from going out twice.

// Vercel cron runs every 30 minutes
export async function GET(req: Request) {
  const practices = await getDigestTargets();
  const due = practices.filter((p) => isSevenAmLocal(p.timezone, new Date()));

  for (const practice of due) {
    // One claim per practice per day, so a retried run can't double-send
    const claimed = await claimDigest(practice.id, localDateKey(practice.timezone));
    if (!claimed) continue;

    const digest = await buildAfterHoursDigest(practice.id);
    await emailTeam(practice.recipients, digest);
  }

  return Response.json({ practices: due.length });
}
2

Streaming Pipelines

Problem

Voice AI needs <2s latency. Sequential processing takes 5-10s.

Solution

Stream every layer: transcription → LLM → synthesis. Start speaking before the LLM finishes thinking.

Real Example

Velyn Dental streams Google speech-to-text into Claude (via AWS Bedrock), which streams to voice synthesis — targeting sub-2-second latency.

// Stream LLM response to voice synthesis
const stream = anthropic.messages.stream({
  model: "claude-haiku-4-5-20251001",
  messages: conversationHistory,
  max_tokens: 300,
});

for await (const event of stream) {
  if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
    // Synthesize and play immediately
    await synthesizeAndStream(event.delta.text);
  }
}
3

Checked Decisions

Problem

How do you keep a model from acting on a bad guess?

Solution

Every model decision is checked before it is used. A failed check means fall back, not guess.

Real Example

Before Velyn Dental uses Claude's routing decision on a live call, policy and grounding checks run against the practice's published facts. A failed check is logged and the call goes to a safe default route.

interface Decision {
  shouldAct: boolean;
  confidence: number; // 0-100
  reasoning: string;
}

function makeDecision(context: Context): Decision {
  const signals = analyzeSignals(context);
  const confidence = calculateConfidence(signals);

  // Only act if confidence > 80%
  return {
    shouldAct: confidence > 80,
    confidence,
    reasoning: explainDecision(signals),
  };
}
4

State Persistence

Problem

What did the product already tell the user, caller, or team?

Solution

Important interactions persist to the database. Decision engines check history before acting.

Real Example

Velyn Dental can use previous call records from the same number so staff do not start from scratch.

// Pull recent calls from the same number before the team calls back
const priorCalls = await db.callLog.findMany({
  where: {
    practiceId: practice.id,
    from: call.from,
    createdAt: { gte: subDays(new Date(), 30) },
  },
  orderBy: { createdAt: "desc" },
  take: 3,
});

// Staff see what the caller already asked about, not a blank slate
return { ...task, priorCalls };

Key Technical Decisions

Every choice is a trade-off. Here's what we chose and why.

Serverless over containers

AI workloads are spiky. Serverless scales to zero during off-hours and handles 100x spikes instantly. No DevOps overhead.

PostgreSQL over NoSQL

Relational data (practices, calls, tasks) with strong consistency requirements. Prisma provides type-safe queries.

Monorepo over microservices

Small team, shared types/utilities. Microservices add coordination overhead we don't need at this scale.

Telnyx over custom WebRTC

Telephony is complex. Telnyx handles PSTN connectivity, HIPAA-eligible transport under a signed BAA, and reliability. We focus on AI logic.

Managed model APIs over self-hosted models

Inference cost ($0.03/min) is negligible vs engineering time. Self-hosting adds operational complexity without ROI.

Monitoring > Testing

Unit tests catch syntax errors. Production monitoring catches real user problems. We invest heavily in Datadog + Sentry.

What we do differently

The product keeps working between visits

Customers should not have to keep checking the same screen. The product watches the narrow workflow it was built for, then shows a clear record when something needs attention.

  • •Keep answering calls and tracking tasks in the background
  • •Open with the details that explain why a call needs attention
  • •Prepare the follow-up: answer the call, save the transcript, create the task
  • •Keep the history attached for whoever touches it next

Example: A front desk should not have to wonder whether a patient called after hours. Velyn answers the call, saves the transcript, and creates the callback task before anyone opens the office.

That requires telephony, speech recognition, state management, handoff rules, and task delivery. That is the product work we build.

What's next

Right now Velyn catches what matters and shows the record. The next step is handling more of the follow-through, such as appointment booking, while keeping the practice in control.

We ship what works today and add more automation only where trust is earned.

Want to see this approach in action?

We use cookies to enhance your browsing experience and analyze site traffic. Accept, reject, or customize below.

Read our Privacy Policy and Terms of Service