The problem
Local service businesses can lose good leads when the first response is slow or when follow-up depends on somebody manually reading every message.
What I built
PoolPulse is a demo workflow for capturing a lead, sending first outreach, processing email replies, extracting sales signals, and moving the lead through explicit stages:
NEW -> CONTACTED -> QUALIFYING -> QUALIFIED -> BOOKED
The demo includes an operator view for inbox threads, pipeline movement, workflow events, and conversion analytics.
Engineering choices
- Inbound replies are idempotent and resolve back to a lead through email thread headers, an explicit lead reference, or sender fallback.
- AI extracts schema-bound qualification fields and drafts natural replies.
- Deterministic rules decide workflow state, unsupported project screening, opt-outs, follow-up timing, and when to hand the conversation to a person.
- Taxonomy normalizers and fallback extraction keep the workflow usable when a model provider is unavailable.
- The model registry supports multiple AI providers.
- The service flow is covered with in-memory database tests for intake, qualification, booking, follow-ups, and email threading behavior.
Implementation detail
The core design was to keep workflow decisions deterministic and let the model handle language and extraction. For example, qualification fields are prioritized in code:
const requiredQualificationFields = [
"budgetRange",
"timeline",
"poolType",
"intent",
]
export function computeMissingFields(fields) {
return requiredQualificationFields.filter((field) =>
isUnknownValue(fields[field])
)
}
Unsupported projects are also rule-based:
if (/\brepair\b|\bpool pump\b|\bheater\b|\bfilter\b|\bleak\b|\bfix\b/.test(text)) {
return {
supported: false,
label: "Repair / service",
reason: "Project is a repair or service request",
}
}
That made the demo easier to inspect: the AI can be wrong about extracted fields, but the state transition logic stays visible.
What I was trying to prove
The problem was speed-to-lead. A local service business can receive a decent inquiry and still lose it because the first reply is late, the follow-up is inconsistent, or nobody knows whether the lead is ready to book.
PoolPulse tried to make that operational loop explicit: capture, reply, extract, decide, follow up, and show the operator what happened.
Current boundary
This is a product demo, not a finished sales system. Deliverability, domain-specific qualification rules, and the booking integration would need a deeper production pass.