← projects
Side project · shipping · salsa-collective.com

tanda — Salsa Collective Lead Intake

AI-powered Gmail inbox that never loses a lead

Go 1.23Supabase PostgresLM Studio (local LLM)Gmail OAuth2Lovable admin UI
// 01 — problem

A salsa studio takes class, private-lesson, and event inquiries through their Gmail inbox. Messages slip between threads, replies stall, and there is no shared record of who owes a customer what — the community pays the price.

// 02 — approach
  • 01Go worker polls the studio Gmail inbox (webhook later) and dedupes by gmail_message_id.
  • 02Each new message is parsed by a local LLM (LM Studio, OpenAI-compatible API) into structured lead fields: intent, style, level, confidence.
  • 03Transactional write to Postgres: leads, email_threads, and a draft_responses row with approval_status=pending.
  • 04Lovable admin UI talks only to Supabase — list/filter leads, edit drafts, approve, assign tasks. The worker never exposes an HTTP API.
  • 05On approval, the worker sends the reply via Gmail and stamps sent_at; task assignee notifications work the same way.
// 03 — result

Every inbound email becomes a triaged lead with a pre-written reply in seconds. No customer mail is ever sent without a human approving it in Lovable, and the worker runs on a Mac or small VM with no inbound ports.

// 03b — architecture
Tanda worker-only architecture: Gmail → Go worker → LM Studio + Supabase, with Lovable admin UI reading Supabase directly.
Worker-only architecture — Lovable talks to Supabase directly; the Go worker has no HTTP API.
// 04 — key decisions
Why local LLM

Lead data is personal. LM Studio on the LAN keeps inference on-prem, removes a recurring cost line, and lets the studio swap models freely.

Why no HTTP API

Lovable talks to Supabase directly with the JS client. Skipping a worker API removes an auth surface, a deploy target, and an entire class of integration bugs.

Why drafts default to pending

Auto-send is a one-way door with customers. Drafts always land as approval_status=pending so a human is in the loop before anything leaves the studio inbox.

// 05 — further reading