
Sandesh Shrestha
Sep 2026 - Present/Advanced
Live Demo
Codebase is confidential
Case Study: ARG Smart Reply - Human-Approved AI Lead Automation
Project at a Glance
- Role: Full-Stack / Automation Engineer (API, Puppeteer worker, AI drafting, dashboard, deploy)
- Duration: Sep 2026 - Present
- Live: app.americasrealtygroup.org
- Stack: React, Vite, TypeScript, Express, Prisma, PostgreSQL, Redis, BullMQ, Puppeteer, OpenAI/OpenRouter, Docker, Nginx, Bull Board
- Scale: ~55,000 lines of code, 25 Prisma models, multi-queue worker with browser automation lanes
- Client context: America's Realty Group - SmarterContact inbox automation with strict human approval gates
Problem
Real-estate lead inboxes move fast. Manually answering every SmarterContact conversation does not scale, but fully autonomous AI senders destroy trust and compliance. ARG needed automation that drafts like a skilled SDR, never sends without a human click, and still follows up when leads go quiet.
What I Built
End-to-end reply loop with a hard human gate
- Puppeteer worker logs into SmarterContact and crawls the inbox on a schedule
- Passive GraphQL interception (reads what the browser already requests - does not invent brittle private API calls)
- AI drafts a reply, or classifies a hard decline and closes the conversation with no draft
- Operators review/edit in the dashboard and Approve or Deny
- Only Approve enqueues a rate-limited send job; Deny disqualifies without redraft spam
Follow-up cadence that respects silence
- Hourly scan for conversations where we sent last and got no reply for 48h+
- Automatic multi-step follow-up sequence with policy controls
- Send caps (hourly/daily) and emergency pause switches for operational safety
Operator dashboard
- Login, Dashboard, and Leads views with near-real-time polling
- Draft review UX tied to the exact conversation in SmarterContact
- Bull Board queue visibility for poll, send, follow-up, and scan jobs
Production-hardened automation
- Same TypeScript codebase, two entrypoints: API server + worker
- Redis browser lease so only one Chromium owner runs at a time across container restarts
- Docker Compose production path (ALB or self-managed TLS via Nginx/Let's Encrypt)
- Strict CORS in production, structured logging, smoke scripts for selectors/send paths
Architecture Highlights
SmarterContact (browser)
^
| Puppeteer lanes (poll / send / follow-up / backfill)
|
Redis + BullMQ workers <-----> Postgres (Prisma domain)
|
v
Express API <-----> React dashboard (approve / deny / edit)
|
v
Nginx TLS @ app.americasrealtygroup.org
Hard Problems I Solved
- Browser automation that survives production: Chromium crashes, singleton locks, and session expiry are normal. Built lease + recovery paths so a dead tab does not brick the whole worker.
- AI that knows when to shut up: Decline detection closes conversations permanently instead of inventing "just checking in" spam.
- Trust boundary: Nothing outbound without Approve. Follow-ups are explicit policy, not sneaky autonomy.
- Queue correctness under concurrency: DraftRequest as source of truth, leases during long AI calls, discard superseded drafts when a newer inbound arrives.
- Selector/DOM fragility: Smoke tests and archived discovery contracts document SmarterContact shapes so UI changes are diagnosable.
Results & Impact
- Live at app.americasrealtygroup.org for America's Realty Group operators
- Lead replies draft continuously while humans stay in control of every send
- Quiet leads get a disciplined follow-up cadence instead of falling through cracks
- Ops can pause queues instantly when the market or inbox behavior changes
What This Shows About Me
- I build automation systems with safety, rate limits, and human control - the difference between a demo bot and a production SDR engine
- I am comfortable owning Puppeteer + queues + AI + React admin in one vertical slice
- I design for failure modes (browser death, API flakiness, superseded drafts), not happy-path scripts
- I can take a messy third-party web app and turn it into a reliable internal product
Links
Note: The codebase is confidential and not publicly available.