TASE Logo
Case study 02 / 20
←All Work
TASE ARCHITECTURE

TasedevCaller

9.33M businesses, cold-called by an AI that cites its evidence.

Sector
B2B SaaS · Outbound voice AI
Role
Sole engineer, end to end
Duration
40 days
Year
2026
↓Scroll to explore showcase↓
Tasedev Caller
B2B SaaS · Outbound voice AI
TASE // 02

●METRICS

By the numbers.

Production telemetry, active capacity, and engineering scale measured in live deployment.

01
0M
rows ingested
02
0
state partitions
03
0
API endpoints
04
0
core tables
05
0
backend tests
06
0
days, first commit to last

01 — What it does


What it
does.

Tasedev Caller runs outbound cold-call campaigns with no human dialing. A tenant selects a slice of a shared national directory by industry, state, rating and review count, or uploads their own CSV or XLSX. A worker walks the leads one at a time: it fetches each lead's website, has a language model extract concrete, falsifiable weaknesses from what it actually saw, maps those to services the tenant sells, writes an opener citing the finding, and places the call.

The agent discloses it is AI on the first turn, qualifies the prospect, captures an email, books a calendar slot and honours an opt-out immediately. Outcomes return by webhook and reconcile against the call record. A manual track emails the same directory instead of calling it.

The entity model has two halves that deliberately do not mix. The tenant-owned half is tenants, members, campaigns, leads, calls and meetings, with usage and billing events beside them. The shared half is one canonical row per business, list-partitioned across the fifty states plus the District of Columbia, a cached website analysis keyed by domain, and a global do-not-call list. Tenancy is enforced in three layers: row-level security on every tenant-owned table, a shared directory reachable only through the service role, and a per-tenant audit table over the shared rows. Built solo, schema to dialer, in forty days.

02 — Module surface


21
screens.

Every discrete surface designed, engineered, and shipped in production. Zero placeholder concepts — 100% functional software.

21 OF 21 SURFACES SHIPPED
01SURFACE

Overview dashboard

02SURFACE

Campaigns

03SURFACE

Quick Dial

04SURFACE

CSV and XLSX upload

05SURFACE

Directory filter preview

06SURFACE

Directory import

07SURFACE

Industry breakdown

08SURFACE

Outreach inbox

09SURFACE

Lead detail and history

10SURFACE

Email composer

11SURFACE

Notes

12SURFACE

Suppression

13SURFACE

Calls log

14SURFACE

Call statistics

15SURFACE

Call transcripts

16SURFACE

Meetings

17SURFACE

Billing and plans

18SURFACE

Identity, voice and services settings

19SURFACE

Usage

20SURFACE

Voice webhook

21SURFACE

Payments webhook

03 — Technical highlight


CORE ARCHITECTURE

The analysis-to-pitch pipeline

ARCH
Signals in, closed tag vocabulary, evidence per tag, spoken copy out.
↳Signals in, closed tag vocabulary, evidence per tag, spoken copy out.

This is where an unreliable generative step is made safe enough to speak aloud to a stranger. One HTTP fetch pulls the lead's homepage and extracts cheap deterministic signals: title, meta description, viewport tag, scheme, response time, and visible text capped at 80 KB of HTML and 3,500 characters.

Those signals, the directory record and the tenant's own service catalog go to the model under a prompt that permits only a closed set of fifteen weakness tags and demands one sentence of falsifiable evidence per tag, with worked examples of what passes ("no viewport meta tag was found") and what does not ("mobile experience could be improved"). Anything outside the tag set is dropped on the way back, and recommended services are intersected against the tenant's catalog, so the model cannot invent a weakness the system has no vocabulary for or sell a service the tenant does not offer.

A second step turns the surviving evidence into spoken copy with the business name and city left as placeholders, so it caches for seven days per tenant, industry and service and personalises per lead at dial time. Analyses cache ninety days per domain, so ten tenants pitching one business pay for one analysis. The closed tag vocabulary is what makes the rest work: it turns free text into something a scoring function, a cache key and a service mapping can all be built on, and it is why a failed fetch degrades to a weaker pitch instead of a fabricated one.

ARCH
Signals in, closed tag vocabulary, evidence per tag, spoken copy out.
↳Signals in, closed tag vocabulary, evidence per tag, spoken copy out.

04 — Architecture


SYSTEM TOPOLOGY

How it
runs.

INFRASTRUCTURE RUNTIMEPROD VERIFIED

Four processes run under Docker Compose behind a reverse proxy that terminates TLS on the host: a Next.js standalone server, a FastAPI application on uvicorn with two workers, an ARQ worker, and Redis with append-only persistence. Postgres is external and managed, reached through a transaction-mode pooler with the driver's statement cache disabled. Only the proxy is internet-facing; the worker and Redis sit on an internal network with no published ports.

CONSTRAINTS: 4 TOTALZERO COMPROMISE
01 / 04ENFORCED

Webhooks enqueue durable jobs

An in-process background task dies with the process and leaves a call unreconciled. A job id derived from the call id survives a restart and makes provider retries idempotent for free.

SPEC CONSTRAINT
02 / 04ENFORCED

Concurrency is a sorted set, not a counter

A counter can only be corrected by hand once it drifts. Keying each in-flight call by id and pruning expired entries on every read means a dropped webhook or a killed worker releases its own slot.

SPEC CONSTRAINT
03 / 04ENFORCED

One shared directory, per-tenant state beside it

Copying a national dataset per tenant multiplies storage by tenant count; putting tenant ids on shared rows breaks isolation. Partitioning by state keeps each query inside one child table, with row-level security enabled on all 52 partitions explicitly.

SPEC CONSTRAINT
04 / 04ENFORCED

Billing events insert first, then act

Writing the event id with a conflict-do-nothing and checking whether the insert returned a row separates already processed from not yet. Transient failures answer 5xx so the provider keeps retrying instead of dropping a subscription change.

SPEC CONSTRAINT
01 OF 04

05 — Integrations


ECOSYSTEM MAP

What it
talks to.

Every third-party API, external boundary, data pipeline, and payment rail hardened and operating in production.

06

GATEWAYS

18+

SERVICES

ZERO UNCHECKED SINKVERIFIED API
  • 01

    Voice and telephony

    3 SERVICES
    Vapi: outbound callingin-call orchestrationstructured outcome extraction
  • 02

    Speech

    2 SERVICES
    Deepgram for phone-tuned transcription and default voicesElevenLabs for premium voices
  • 03

    Language models

    3 SERVICES
    OpenAI gpt-4o-mini: website analyzerpitch writerin-call reasoning
  • 04

    Scheduling

    3 SERVICES
    Cal.com v2: event type resolutionavailability lookupbooking
  • 05

    Email and payments

    2 SERVICES
    Resend for confirmations and outreachStripe Checkout and subscription webhooks
  • 06

    Identity, data, delivery

    5 SERVICES
    Supabase auth and PostgresSentryDocker ComposeCaddyGitHub Actions

06 — Problems solved


DIAGNOSTIC LOG & ROOT CAUSE ANALYSIS

What broke,
and how we found it.

Feature lists show what was built. These post-mortems show how obscure edge cases and silent production bugs get diagnosed and permanently resolved.

01 / 03RESOLVED IN PROD

Every call was voicemail, and none of them were

01 // SYMPTOM

Calls to international numbers connected and then ended within seconds, marked as voicemail. The prospect never heard the agent speak.

02 // ROOT CAUSE

Some carriers put a press-1-to-accept screen in front of an incoming call. To an answering-machine detector working from the audio envelope, that is voice followed by silence, precisely the signature of a recorded greeting and a beep. Every screened call was classified as a machine and hung up before the agent's first turn.

03 // ARCHITECTURAL FIX

Answering-machine detection was removed and the silence timeout raised from twelve to thirty seconds so the carrier screen has room to clear. Tuning thresholds was rejected: the screen is indistinguishable from a greeting on the signal the detector uses. The accepted cost, occasionally speaking into a real voicemail, is bounded by a hard duration cap.

02 / 03RESOLVED IN PROD

The dialer stopped, and nothing was wrong

01 // SYMPTOM

Campaigns placed a handful of calls and went quiet. Nothing was logged, the campaign was still active, leads stayed pending, restarting the worker changed nothing.

02 // ROOT CAUSE

Global concurrency was a single counter, incremented before placing a call and decremented when the end-of-call event arrived. Any path that skipped the decrement left it permanently high. Once it reached its ceiling, the guard refused every subsequent call indefinitely, and because it held a number rather than a set of call identities, nothing could ever correct it.

03 // ARCHITECTURAL FIX

The counter became a sorted set keyed by call id and scored with an expiry. Every read prunes expired entries, so a dropped event or a crashed worker releases its own slot, and release by id is idempotent. A compensating decrement was rejected because it repairs only the failure paths that were anticipated.

03 / 03RESOLVED IN PROD

Bookings worked, emails arrived, the dashboard read zero

01 // SYMPTOM

A test call booked a real calendar slot and both confirmation emails were delivered, yet the dashboard reported zero calls and zero meetings.

02 // ROOT CAUSE

The calendar API returns a booking start time as an ISO string; the Postgres driver's binary protocol requires a datetime for a timestamptz column and will not coerce it. The meeting insert raised, and because lead, call and meeting were written in one transaction, the rollback discarded the two inserts that had succeeded. The booking and the emails were side effects outside the transaction, so they survived.

03 // ARCHITECTURAL FIX

A coercion helper parses ISO strings, including a trailing Z, into timezone-aware datetimes at both insert sites. Widening the column to text was rejected because it would turn every downstream time comparison into a string comparison. The same pass coerced an event id the v2 API now returns as an integer.

01 OF 03

07 — Stack and outcome


CORE TECH TOOLKIT // 23 DEPENDENCIES

Built
with.

Every dependency is chosen deliberately for raw execution speed, strict type safety, zero cold-start latency, and battle-tested reliability under high concurrent load.

  • Python 3.12
  • FastAPI
  • ARQ
  • asyncpg
  • Postgres (Supabase)
  • Redis 7
  • Next.js 14
  • React 18
  • TypeScript
  • Tailwind
  • Vapi
  • OpenAI
  • Deepgram
  • ElevenLabs
  • Cal.com v2
  • Resend
  • Stripe
  • Sentry
  • Docker Compose
  • Caddy
  • GitHub Actions
  • DuckDB
  • pytest
// COMMERCIAL & OPERATIONAL OUTCOME
MEASURED IMPACT

"The platform went from schema to a working dialer in forty days, with 9.33 million directory rows ingested across 52 partitions and every safety property, disclosure on the first turn, immediate opt-out, and evidence before pitch, enforced in code rather than in prompt text."

Status: 100% Operational & Scaled
TASE ARCHITECTURE VERIFIED ✓
NEXT PRODUCTION ENGAGEMENT

Have one
like this?