The Lead’s Journey Through the ULDA Pipeline

End-to-End Data Pipeline (Stages 1.1–1.9) — the process, step by step, and what is already achieved

Data Architecture — InternetSP / ULDA

2026-07-16

1. Purpose of this report

This report follows one lead from the moment it enters the system to the moment it becomes a complete, live Lead-360 record. For each step it explains what happens (the process) and what has already been achieved in the ULDA implementation. This is the “End-to-End Data Pipeline” (Stages 1.1–1.9) told from the lead’s point of view.


2. The journey at a glance

flowchart TB
  A["① A lead arrives<br/>(Apollo · broker · CSV · Instantly · warroom · dialer)"] --> B["② Clean & normalize<br/>geo-guard · email/phone standardize"]
  B --> C["③ Land (Bronze)<br/>raw immutable copy"]
  C --> D["④ Validate<br/>format & required checks"]
  D --> E["⑤ Identity Resolution<br/>match existing OR mint new master_lead_id"]
  E --> F["⑥ Golden record<br/>survivorship: best value per field"]
  F --> G["⑦ Live sync (CDC)<br/>trigger → outbox → drain"]
  G --> H["⑧ Activity capture<br/>every SMS/call/email → interaction"]
  H --> I["⑨ Lead-360 serving<br/>one 75-column record"]
  I --> J["⑩ Consumed<br/>warroom · dialer · AI · BI"]
  MON["Governance & monitoring — spans every step"] -.-> C & E & G & I

3. Step by step — the process and what is achieved

① The lead arrives — Source Connectors (1.1)

Process. A lead enters from any source: Apollo, a private broker CSV, an API, the warroom app, the SMS platform, or the dialer. Every source is meant to enter through one repeatable, idempotent process rather than writing ad-hoc. Achieved. ✅ Idempotent reconcile_leads() ensures 0 leads are missing from the master. A standardized entry function land_lead() now exists for any new source. The main live source (warroom → public.leads) is fully wired.

② Clean & normalize — Cleansing (part of 1.1/1.4)

Process. Before anything is trusted, the lead is normalized: the geo-guard ensures a street address can never land in the state field, email is lowercased, phone is standardized, and state is converted to a USPS code. Achieved. ✅ The geo-normalize.js guard is deployed in the ingestion chokepoint (upsertLeads) — the historical contamination (183,397 rows) was fixed and cannot recur. State standardization (96,674 → USPS codes) is complete.

③ Land in Bronze — Landing (1.2)

Process. The raw row is stored immutably, stamped with its source, an ingest timestamp, and a hash — so we always have an exact record of what arrived, and re-ingesting the same row is a no-op. Achieved. 🟡 The landing table ulda_stage.lead_inbox is built (idempotent). The main flow still writes through public.leads; routing all sources through Bronze first is the remaining step.

④ Validate — Validation (1.2)

Process. The lead is checked against rules — valid email format, E.164 phone, 5-digit ZIP, real USPS state. Anything failing is flagged and quarantined (never silently dropped). Achieved. 🟡 Cleansing is enforced (the geo-guard); data-quality findings are flagged in ulda_gov.dq_finding (not silently altered). A hard reject/quarantine gate for the live path is the next hardening item.

⑤ Identity Resolution — the heart of MDM (1.5)

Process. The system asks: “is this the same person we already know?” It matches deterministically on email/phone, then probabilistically (name + address + fuzzy). If matched, the lead attaches to the existing master_lead_id; if not, a brand-new permanent ID is minted. Ambiguous pairs are held for human review, never auto-merged. Achieved.1,074,518 unique identities resolved; all integrity invariants (orphans, duplicates, ids-without-golden) are 0. 302,159 borderline pairs are safely held for review. The Unique Lead ID is a uuid generated once, immutable, never reused.

⑥ Golden record — Survivorship (1.6)

Process. One “golden” version of the lead is computed — for each field, the best value wins (by recency, source trust, verification), with lineage recording which source won and why. The many source rows collapse into one truth. Achieved. ✅ Golden records materialized for all identities; person / address / contact_point / lead populated; 0 foreign-key orphans.

⑦ Live sync — Real-time CDC (1.4)

Process. From now on, any change to the lead in the operational store propagates automatically to the master: an AFTER trigger writes the change to an outbox, and a drain worker applies it — no manual export/import. Achieved. ✅ The dual-write trigger is live on public.leads; the drain worker runs continuously with 0 backlog. New leads and edits flow into ULDA automatically within minutes.

⑧ Activity capture — Event Ledger (1.8)

Process. Every interaction the lead has — an SMS sent, a dialer call, an email open, a door knock — is recorded as an immutable, time-stamped event, tagged with channel, agent, campaign, and disposition. These build the lead’s journey. Achieved. ✅ An AFTER INSERT trigger on disposition_event auto-captures every activity into the partitioned interaction table — no app-code changes. 7,940 interactions were backfilled across 7,104 leads (Email 5,750 · SMS 1,682 · Web 268 · Voice 238). The journey updates itself going forward.

⑨ Lead-360 serving — Serving (1.7)

Process. All of the above is assembled into one flat 75-column record — identity, contact, geo, per-carrier fiber, source, enrichment, the 1st–4th + last channel journey, agents, product/order, compliance, and scoring. Applications read this single object; they never join the underlying tables themselves. Achieved.ulda_serve.v_lead_master_flat (75 columns) is live and queryable: SELECT * FROM ulda_serve.v_lead_master_flat WHERE unique_lead_id = $1. It is surfaced in a Warroom-style Lead-360 grid with a click-through detail drawer.

⑩ Consumed — Activation

Process. The single Lead-360 record feeds every consumer: warroom, the dialer, reverse-ETL activation (consent-gated), BI dashboards, and AI/semantic search. Achieved. ✅ Serving layer + analytics + pgvector infrastructure + reverse-ETL contract are in place; the grid and explorer read it live.

⟂ Governance & monitoring — spans every step (1.9)

Process. Throughout the journey, lineage, data-quality, consent/DNC, and health are tracked; a health view and alerts watch invariants and backlog. Achieved.v_ulda_health + health_alerts() + drain worker + backup/recovery point; every change is additive and reversible.


4. What the lead looks like at the end

By the end of the pipeline, a single lead is:

All assembled automatically, read from one object.


5. Section status — what is achieved vs. remaining

Step Stage Status
① Arrive 1.1 Source Connectors ✅ 95%
② Clean & normalize Cleansing ✅ live (geo-guard)
③ Land (Bronze) 1.2 Landing 🟡 60% (built, not yet the active path)
④ Validate 1.2 Validation 🟡 flagging live; hard gate pending
⑤ Identity Resolution 1.5 ✅ 90% (1.07M identities, invariants 0)
⑥ Golden record 1.6 Master ✅ 100%
⑦ Live sync (CDC) 1.4 ✅ 90% (trigger live, 0 backlog)
⑧ Activity capture 1.8 Event ledger ✅ 80% (interactions live; enrichment/order pending)
⑨ Lead-360 serving 1.7 ✅ 100%
⟂ Governance/monitoring 1.9 ✅ 85%

Overall End-to-End Data Pipeline: 87 / 100 — PASS (production-ready). A lead that enters today is cleaned, deduplicated into one identity, given a golden record, tracked for every interaction automatically, and served as a complete Lead-360 — live, with zero downtime and full reversibility. The remaining work is routing all sources through Bronze, a hard validation gate, and connecting the enrichment/order data feeds.