Public
DLX Designs lead qualification engine + React dashboard
aidashboardleadsmenswear
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

DLX Designs · Verified Lead Intelligence Engine

Production-ready lead-generation and strict qualification engine for DLX Designs — a luxury bespoke traditional menswear brand targeting high-net-worth clients, grooms and corporate executives in Lagos & Abeokuta, Nigeria.

It ingests real inbound traffic, filters out low-budget seekers with strict semantic rules, stores only verified high-intent leads, and renders them as scored lead cards in a live dashboard.

Live dashboard: Try the app Ingest endpoint: POST /api/ingest

Architecture

Rendering mermaid diagram...
  • Dashboard: client-side React + Hono backend (App Router-equivalent), Twind/Tailwind styling.
  • Database: val-scoped PostgreSQL-compatible SQLite. Supabase mirror optional.
  • Qualifier: deterministic heuristic (zero-config) + optional free-tier AI refinement.

The strict qualification engine

Runs in backend/worker/qualifier.ts and never fabricates data.

Layer 1 — hard disqualifiers (instant reject): cheap, affordable, under 20k/20k, discount, thrift, okirika.

Layer 2 — scoring matrix (0–100): baseline 25, high-tier signals add points — bespoke +18, groom/chieftaincy +20, cashmere +15, wedding +14, 3-piece +12, executive +14, lekki/victoria island +10, lagos/abeokuta +6, etc. Pass threshold: ≥ 50. Sub-threshold leads are rejected.

Layer 3 — AI refinement (optional, zero-config by default): the engine is deterministic-first — the strict heuristic above is authoritative and needs no AI key, no external call, no cost, so no provider can ever block it. If you add a free-tier key, that provider refines the score and writes a natural buying signal (tried in order: GEMINI_API_KEY, GROQ_API_KEY, OPENAI_API_KEY). A provider failing just falls back to the heuristic — never an error.

Endpoints

MethodPathPurpose
GET/Dashboard
GET/dashboardDashboard (alias)
GET/api/leadsVerified leads (JSON, strongest first)
POST/api/ingestIngest & qualify an inbound lead — 201 on pass, 422 on reject
POST/api/leads/:id/statusAdvance pipeline stage (or set one) — records history
GET/api/analyticsPipeline / source / signal analytics (the learn layer)

POST /api/ingest request body:

{ "name": "Oluwatosin Adeyemi", "gmail": "tosin@example.com", "source": "nigerianmenswear.com", "message": "I need a bespoke 3-piece groom suit for my chieftaincy ceremony in Abeokuta" }

Only passing leads persist. Rejected and duplicate leads are returned (422) and never stored.

The growth engine loop

A verified lead is more than a row — it is a story with evidence:

  1. Huntcron/hunt.ts polls a real configured source (DLX_HUNT_URL) and feeds genuinely captured inquiries through the qualifier. It never invents people or signals; rows without evidence are ignored.
  2. Verify — every lead records where it came from (source, source_url), exactly what was said (evidence), and when (created_at).
  3. Qualify — strict scoring (0–100); only ≥ 50 passes.
  4. Prioritize — the dashboard sorts strongest first and shows live pipeline counts.
  5. Recommend — each lead carries a action, chosen from the actual signal: book consultation, contact to confirm budget, or nurture.
  6. Track — leads move through new → qualified → contacted → responded → consultation → quoted → deposit_paid → ordered → won/lost. Every transition is recorded in history.
  7. Learn/api/analytics reports conversion by stage and top sources and signals that actually produce qualified opportunities.

Capture & feed real inquiries (get it live today)

Option A — website ingestion. A ready, branded enquiry form is hosted at /capture (or embedded by iframing it). It posts each submission to /api/ingest, which qualifies and stores it. Direct API for a custom site:

POST https://dlx-leads.val.run/api/ingest Content-Type: application/json { "name": "…", "gmail": "…", "phone": "…", "message": "…", "source": "…", "source_url": "…" }

Option C — JSON / Google Sheet feed (autonomous, scheduled every 15 min). The hunt poller accepts a published Google Sheet CSV directly, no code:

  1. In your sheet, make row 1 a header that includes gmail (plus optional name, phone, message, source, source_url).
  2. File → Share → Publish to web → choose the sheet → format CSV → copy the link.
  3. Set that link as DLX_HUNT_URL (and DLX_HUNT_TOKEN if it's private/behind auth).

Each run, the engine ingests every new row, qualifies it, and skips duplicates. Rows without an email are ignored — nothing is invented.

Option B — email intake (live inbound hunting). Forward any organic inquiry (DM, WhatsApp, web message, marketplace lead) to the engine's email address and it is qualified, evidence-tagged, and tracked automatically:

dlxdesigns-e7b272d2a81611f19be51607ee4eb77e@valtown.email

See docs/growth-corridors.md for the 50-verified growth corridors (marketplaces, fashion platforms, directories, fashion-week hubs, forums, and press) — each mapped to an acquisition, observation, or partnership role the engine can consume.

Connect Instagram (real DM/comment capture)

The engine side is built and tested. To connect Meta (one-time, your login):

  1. Create a Meta for Developers app (https://developers.facebook.com).
  2. Add the Instagram product and connect your Instagram Business account.
  3. Create a token with the instagram_business_basic, instagram_business_manage_messages, and pages_messaging permissions (a long-lived User or Page token).
  4. Set these on the val: 👉 Add INSTAGRAM_VERIFY_TOKEN here: https://www.val.town/x/dlxdesigns/dlx-lead-engine/environment-variables?key=INSTAGRAM_VERIFY_TOKEN 👉 Add META_APP_SECRET here: https://www.val.town/x/dlxdesigns/dlx-lead-engine/environment-variables?key=META_APP_SECRET
  5. In Meta → Developer App → Webhooks, subscribe the Instagram object to the callback URL: https://dlx-leads.val.run/api/instagram/webhook using your INSTAGRAM_VERIFY_TOKEN as the verify token.

Real DMs/comments then push into the engine automatically. Because Instagram DMs carry no email, each becomes a signal (/api/signals); reply to capture the email, then promote it to a verified lead with POST /api/signals/:id/promote.

Google Business Profile (real local-channel capture)

Reviews, Q&A, and "do you make…" messages on your Google Business Profile are high-intent local signals. Capture them in one call — they become scored prospects source-tagged google-business-profile in the Command Center, ready to draft and convert:

POST https://dlx-leads.val.run/api/gbp Content-Type: application/json { "reviewer": "Adaeze Okafor", "message": "Do you make bespoke 3-piece groom suits for Lagos weddings?", "email": "…", "phone": "…", "permalink": "https://maps.google.com/…" }

Manual route (no credentials): a VA or owner copies each new review/Q&A/message and posts it to /api/gbp (or the dashboard capture form with source: google-business-profile), and the automaton takes it from there. Automated pull of your GBP inbox requires Google OAuth on your account — that part is yours to connect when ready; everything after capture is handled here.

Configuration (environment variables)

Everything runs out of the box with zero environment variables. The qualification engine is fully deterministic. The following optional keys unlock the AI refinement layer (free tiers are preferred — none require billing) and the Supabase mirror:

  • GEMINI_API_KEY — free tier (Google AI Studio key, no card required). Recommended.
  • GROQ_API_KEY — free tier. Ignored unless Gemini is absent or fails.
  • OPENAI_API_KEY — requires active OpenAI billing; only used as a last resort.
  • SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY — mirror verified leads to your Supabase dlx_verified_leads table (native SQLite store stays authoritative).
  • DLX_HUNT_URL — JSON or published-CSV feed the hunt poller watches for genuine inquiries (JSON: { "leads": [ { name, gmail, phone, message, source, source_url } ] }).
  • DLX_HUNT_TOKEN — optional bearer token sent to the hunt source (Authorization: Bearer …).
  • INSTAGRAM_VERIFY_TOKEN — random string you invent; Meta must echo it on webhook verification.
  • META_APP_SECRET — optional; enables X-Hub-Signature-256 verification on Instagram webhooks.
  • DLX_BRAND_NAME — whitelabel brand shown in capture copy + drafts (default: DLX Designs).
  • ENABLE_AUTOSEND — set to 1 to let the nurture automaton actually email first touches; OFF (dry-run) by default.

👉 Add GEMINI_API_KEY here: https://www.val.town/x/dlxdesigns/dlx-lead-engine/environment-variables?key=GEMINI_API_KEY 👉 Add GROQ_API_KEY here: https://www.val.town/x/dlxdesigns/dlx-lead-engine/environment-variables?key=GROQ_API_KEY 👉 Add OPENAI_API_KEY here: https://www.val.town/x/dlxdesigns/dlx-lead-engine/environment-variables?key=OPENAI_API_KEY 👉 Add SUPABASE_URL here: https://www.val.town/x/dlxdesigns/dlx-lead-engine/environment-variables?key=SUPABASE_URL 👉 Add SUPABASE_SERVICE_ROLE_KEY here: https://www.val.town/x/dlxdesigns/dlx-lead-engine/environment-variables?key=SUPABASE_SERVICE_ROLE_KEY 👉 Add DLX_HUNT_URL here: https://www.val.town/x/dlxdesigns/dlx-lead-engine/environment-variables?key=DLX_HUNT_URL 👉 Add DLX_HUNT_TOKEN here: https://www.val.town/x/dlxdesigns/dlx-lead-engine/environment-variables?key=DLX_HUNT_TOKEN 👉 Add INSTAGRAM_VERIFY_TOKEN here: https://www.val.town/x/dlxdesigns/dlx-lead-engine/environment-variables?key=INSTAGRAM_VERIFY_TOKEN 👉 Add META_APP_SECRET here: https://www.val.town/x/dlxdesigns/dlx-lead-engine/environment-variables?key=META_APP_SECRET

Supabase setup (optional)

Create the mirror table by running database/schema.sql in the Supabase SQL editor. The table uses gen_random_uuid() ids, enforces a score BETWEEN 0 AND 100 check, has a gmail UNIQUE constraint, and enables Row-Level Security (locked to service-role access by default). The val writes via PostgREST with the service-role key and resolution=merge-duplicates.

File structure

database/
  schema.sql                ← Supabase/PostgreSQL schema (mirror table)
backend/
  config.ts                 ← whitelabel brand + runtime config
  pipeline.ts               ← sales pipeline stages + next-stage logic
  hunt.ts                   ← autonomous ingestion from a real configured source
  outbound.ts               ← prospect queue: score, auto-draft, guarded send, convert
  instagram.ts              ← Meta webhook receiver for real IG DMs/comments
  worker/
    qualifier.ts            ← strict qualification engine (disqualifiers + scoring)
    ingest.ts               ← ingest worker (bridge inbound → store)
    llm.ts                  ← optional AI adapter (free tier Gemini / Groq / OpenAI)
cron/
  hunt.ts                   ← scheduled hunt poller (every 15 min)
  automate.ts               ← nurture automaton: nudge hot leads + auto-send (guarded)
email/
  lead-intake.ts            ← email-triggered lead intake (forward inquiries here)
docs/
  growth-corridors.md       ← 50 acquisition/observation/partnership corridors
  operating-model.md        ← how the automaton runs + per-client deployment model
lib/
  store.ts                  ← SQLite persistence + Supabase mirror + pipeline + analytics
frontend/
  components/App.tsx        ← dashboard layout + empty state + pipeline strip
  components/LeadCard.tsx   ← verified-lead card with evidence, action & stage
  components/LeadForm.tsx   ← inline lead-capture form
scripts/
  selftest.ts               ← end-to-end qualifier + store self-test
index.ts                    ← Hono HTTP backend (dashboard + /api/*)

Integrity guarantees

  • No hardcoded, fake, or mock contacts anywhere. Every record comes from a real POST /api/ingest submission that passed strict qualification.
  • Empty store → dashboard shows “Awaiting live inbound high-intent signals…”, never fake cards.
  • Duplicate emails are rejected (UNIQUE), budget seekers are dropped, sub-50 intent is dropped.

Running the self-test

scripts/selftest.ts exercises the full pipeline with synthetic example inputs (high-intent pass, low-budget reject, no-signal reject, duplicate reject) and is safe to run repeatedly.