⚠ Once submitted this customer will be saved to Supabase and an onboarding email will be sent automatically.
✏️ Edit Customer
Modify fields below — you will review changes before saving.
Custom customers keep the Pro features, can't buy or change plans themselves, and can have extra users. Included leads = Monthly Lead Cap above.
Pro already includes 2,000 leads a month. Each bundle adds 1,000 more, whichever channel they come from.
An add-on to the $180 bundle (one SMS/WhatsApp bundle = $255). It can't be more than the extra bundles above. Fair use: up to 12 messages per lead per month; a longer thread counts as another lead.
These buttons use what is SAVED — save your changes first. Nothing is charged until the customer completes the checkout.
● Fields highlighted in green have been changed
Confirm Changes
Review what will be updated before saving to database.
⚠ These changes will be saved immediately to the database. This action cannot be undone.
LeadhubInternal
?
Overview
LeadHub internal analytics and customer management
🚨
Infra alert
Click to view Infra Health
→
Monthly Recurring Revenue
$0
—
Customers
—
Active
—
Pending
—
Total Leads
—
Messages
Most Active Customers by leads
Loading…
Plan Distribution customers
Loading…
Customers by Industry
Business
Email
Plan
MRR
Leads
Messages
Status
Sales Rep
Loading…
← Back to All Customers
Loading…
Register New Customer
Fill in required fields (*) — you will confirm before saving to database.
Business Details
Sales Information
Founding 50 (optional)
Staff Discount (Owner / Global Admin only — Global Admin up to 40%, Owner up to 70%)
—
Plan — Pricing from leadhubai.io
Starter
✓
$250
per month
Inbox only
150 leads
2 team members
180-day retention
Growth
✓
$399
per month
Inbox + Dashboard
500 leads
5 team members
1-year retention
Pro
✓
$599
per month
Everything
2,000 leads
10 team members
2-year retention
✓ Customer Saved — 14-Day Trial Started
Customer ID:
✓ Registered
✓ Email sent
⏱ 14-day trial
○ Agreement pending
Connection status for every customer across all channels. Green = connected, Yellow = token expiring within 7 days, Red = disconnected or expired, Gray = not set up.
Customer
SMS / WhatsApp
FB
IG
FB Token Expiry
Web Chat
Plan
Actions
Loading…
⚠Low pool — fewer than 3 numbers available. Provision more numbers to avoid onboarding delays.
—
Total Numbers
—
Available
—
Assigned
—
Registering
Number
Area
Status
Assigned Customer
Registered
Assigned
Actions
Loading…
Live TCPA / 10DLC compliance monitor for SMS. Tracks every STOP, HELP, and START
keyword reply, every consent recorded on lead creation, and every outbound send
that was blocked because the recipient had opted out. Meta DMs and WhatsApp have
separate consent systems and don't appear here.
All records retained for 4 years per TCPA / CTIA guidance.
🔍 Phone Lookup
Pull the full consent + message + opt-out history for any phone number (for carrier audits or dispute resolution).
—
Active Consents
—
Active Opt-Outs
—
Opt-Outs (7d)
—
Opt-Outs (30d)
When
Event
Keyword
Phone
Customer
Source
Loading…
Phone
Opted Out
Keyword
Originating Customer
Status
Actions
Loading…
Loading…
💬 Inbound SMS sent to LeadHub-owned numbers that are not yet assigned to a customer. Use this to read verification codes (WhatsApp Business, A2P/10DLC, carrier disputes) before linking the number to a customer. Once a number is assigned, regular inbound SMS goes to the customer's inbox instead.
Auto-refreshes every 15s while tab is open
Loading messages…
Customers who started setup but haven't activated yet. Yellow = inactive 24h+, Red = stuck 7+ days. Click any row to open detail / nudge.
Loading queue…
🎯
Founding 50 Waitlist
Applications pending review · Accept to create their trial
Signups:0 / 50
Pending:0
Remaining:50
Loading applications…
—
—
Owner:—
Email:—
Phone:—
Industry:—
City:—
Volume:—
Applied:—
Source:—
Biggest lead problem
—
🚀Active Trials— accepted customers in their 14-day trial
—
Total Trials
—
Active
—
Onboarded
—
Guided
—
Self-Service
📋 Guided Trial Playbook
Step-by-step guide for onboarding guided trial customers
1Call the CustomerBefore sending email
Introduce yourself and LeadHub AI. Ask the customer:
What services they offer (plumbing, HVAC, roofing, etc.)
How they currently get leads (Facebook, website, referrals)
Which plan interests them: Starter ($250), Growth ($399), or Pro ($599)
Tip: All trials get Pro access for 14 days. They can downgrade when they subscribe.
2Send the Setup EmailStay on the phone
Click the 📧 Send Setup button next to the customer's name. Tell them:
"I just sent you an email from LeadHub AI. Can you check your inbox? It should be there in a few seconds. Click the green button that says 'Complete Your Setup'."
3Walk Through the Setup Steps
The customer will see 3 steps. Walk them through each one:
Step 1 — Consent & Permissions
"Check the boxes to authorize Facebook, Instagram, and SMS access. This lets the AI respond to leads on your behalf. Then click Continue."
Step 2 — Connect Facebook (Optional)
"If you have a Facebook Business page, click Connect to link it. This lets the AI capture leads from Facebook and Instagram DMs. If you don't have one or want to skip, click Skip for Now."
Step 3 — Set Password
"Create a password you'll remember. This is what you'll use to log in to both the mobile app and the dashboard. Must be at least 8 characters with a number and uppercase letter."
4Install the Mobile App
Guide the customer to install the LeadHub AI app on their phone:
📱 iPhone
1. Open Safari → app.leadhubai.io
2. Tap the Share button (⬆️)
3. Tap "Add to Home Screen"
4. Tap "Add"
🤖 Android
1. Open Chrome → app.leadhubai.io
2. Tap the ⋮ menu (top right)
3. Tap "Install app" or "Add to Home Screen"
4. Tap "Install"
"Now log in with the email and password you just created. The first thing you'll want to do is go to Settings → Service Pricing and add your services with prices. The AI uses this to give accurate quotes to your leads."
Tip: Ask them to enable push notifications so they never miss a lead.
5Show the DashboardGrowth & Pro only
If the customer is on Growth or Pro, walk them through the dashboard:
"You also have access to a full dashboard at dashboard.leadhubai.io. Log in with the same email and password. Here you can see:"
Analytics — Lead counts, conversion rates, response times
Leads — Full lead list with search and filters
Service Pricing — Manage your services (also in the app)
Lead Generation — AI creates Facebook/Instagram ads (Pro)
Content Planner — Schedule social media posts (Pro)
Company — Profile, brand assets, billing, and team management
🎯 Before You Hang Up
Confirm they can log in to the app and dashboard
Make sure push notifications are enabled
Remind them: "Your 14-day Pro trial is active — the AI will start responding to leads automatically"
Let them know they can upgrade anytime from the app or dashboard
Give them your direct number/email for follow-up questions
Name
Business
Email
Location
Assigned
Source
Setup
Days
Actions
Loading trials…
—
Total
—
New
—
Contacted
—
FB / IG
—
SMS
Name
Email
Phone
Industry
Plan
Temp
Status
Pipeline
Date
Loading...
Name
Channel
Phone / PSID
Temp
AI Status
Pipeline
Last Message
Date
Loading...
LeadHub AI — Response Configuration
Controls how the AI responds to inbound leads on your LeadHub AI account. Does not affect other customers.
✓ Saved
📋 Inbound Leads Playbook
Complete guide to managing LeadHub AI's own inbound leads
🧭Two tracks per lead: AI Status and Sales Pipeline
Every lead has two independent states. Don't confuse them:
🤖 AI STATUS
Set by the AI automatically as the conversation progresses. You don't change it manually.
NEW
CONTACTED
QUALIFIED
ASSIGNED
BOOKED
COMPLETED
CLOSED_LOST
CLOSED_NO_RESPONSE
SPAM
📋 SALES PIPELINE
Set by YOU as you follow up. This is how LeadHub AI staff track progress toward closing the prospect.
🆕 NEW
👁 REVIEWED
📞 CONTACTED
✅ PROCESSED
🎉 REGISTERED
Temperature (separate again) is how hot the lead is: 🔥 HOT / 🟠 WARM / ❄️ COLD / ⏳ PENDING. Temperature only changes AI behavior — it doesn't progress the pipeline.
Rule of thumb: AI Status = what the bot knows. Sales Pipeline = what YOU've done about it.
📊The full lead cycle
Prospect contacts LeadHub AI via Website chat, FB DM, IG DM, or SMS
↓
Lead created — AI Status: NEW · Pipeline: 🆕 NEW
↓
Leo (the AI) replies in <2 seconds, starts qualifying
↓
AI Status → CONTACTED · Temp starts evolving
↓
Prospect shares details. AI captures name, email, phone, industry
↓
AI Status → QUALIFIED when all qualification info is collected
↓
You open the lead → change Pipeline to 👁 REVIEWED
↓
You call / demo / email → Pipeline: 📞 CONTACTED
↓
Prospect agrees to a plan → Pipeline: ✅ PROCESSED
↓
Click 🎉 Register as Customer → form prefills → complete missing fields → save
↓
Pipeline: 🎉 REGISTERED · Customer account created
🗂️The two tabs
🌐 Website
Prospects who chatted with the bot on leadhubai.io. Columns: Name · Email · Phone · Industry · Recommended Plan · Temp · AI Status · Pipeline · Date. Click any row to see the full chat transcript and change pipeline status.
📱 Leads (FB / IG / SMS)
Prospects who DM'd the LeadHub AI Facebook Page, Instagram account, or texted the LeadHub AI phone number. Columns: Name · Channel · Phone or PSID · Temp · AI Status · Pipeline · Last Message · Date. Click any row to see the message thread and change pipeline status.
🤖 AI Config
Controls how Leo (the AI) responds to LeadHub AI's own inbound leads. This does not affect any customer's AI — each customer configures their own in their dashboard.
🎉Registering a lead as a customer
When a prospect is ready to sign up, click the 🎉 Register as Customer button in the lead detail modal. The button:
Marks the lead as 🎉 REGISTERED in the pipeline
Navigates to Register Customer page
Pre-fills what the AI already captured
Highlights the first empty required field so you know what's missing
Before saving, confirm ALL of these are filled in:
✓ Business NameLegal company name (often missing from FB/IG — ask the prospect on the call if not captured)
✓ Owner / Contact NameWho you're actually selling to
✓ Phone NumberRequired for STOP/HELP/START branded SMS replies and carrier compliance
✓ Type of Business (Industry)Drives AI qualifier checklist. Pick the closest match from the 28-vertical list.
✓ Address (City / State / Zip)Needed for service-area targeting and billing. Full street address can come later.
✓ PlanStarter $250 / Growth $399 / Pro $599. Match to what the prospect agreed to.
✓ Sales PersonWho closed the deal — drives attribution reporting
○ Website, NotesOptional but recommended — helps the AI personalize responses
If the prospect ghosted between AI qualification and your call, message them back in the Inbox before registering. Never register a lead you haven't spoken to directly.
🤖AI Config (Tab: AI Config)
Controls how Leo responds to LeadHub AI's own inbound leads. These settings do not affect any customer's AI.
AI Persona Name
Currently Leo. This is the name Leo signs messages with and how he introduces himself.
AI Response Enabled
Toggle auto-reply ON or OFF. When OFF, leads still come in but you reply manually from the inbox.
Response Delay
Currently set to 2 seconds — fast feels premium for B2B. If you want Leo to feel more human, raise to 8–15 seconds.
AI Greeting
Optional first message. Usually better to leave blank so Leo tailors the opener to the lead's channel and message.
Custom AI Instructions (Niche Prompt)
Leo's full playbook: pitch, pricing, qualification questions, trigger phrases, handoff rules. Updates take effect on the next inbound message — no restart.
📅Daily routine
Open Channels → Inbound Leads. Review overnight leads on both Website and Leads tabs.
Click every 🆕 NEW pipeline lead → read the transcript → change to 👁 REVIEWED so nothing falls through.
Call or email the 🔥 HOT or QUALIFIED ones first → mark 📞 CONTACTED.
When a prospect commits → ✅ PROCESSED, then click 🎉 Register as Customer when contract is signed.
Confirm all register-form fields (see checklist above) before saving.
End of day: Pipeline should have zero 🆕 NEW leads. Everything is at least 👁 REVIEWED.
—
Total
—
New
—
Pending
—
On Hold
—
Closed
+ Create Support Ticket
Customer
Subject
Status
Category
Source
Priority
Assigned
Created
Loading tickets...
—
—
Customer:—
Email:—
Source:—
Created:—
Description
—
Chat History
📌 Environment context
💬 Conversation
—
✏️ Add note
✓ Saved!
🤖
Ops AI Assistant
Read-only · Claude Haiku 4.5 · Can auto-file bug tickets
Enter to send · Shift+Enter for newline
Operational alerts from across the platform — failed Facebook connections, deauth events, expired tokens, and other issues that need attention. Open the customer's record from any alert to take action; acknowledge to keep on the list, resolve to clear it.
✓ No alerts in this view. The platform is healthy — or you've cleared everything that needed attention.
📋 Alerts Playbook
Quick reference for triaging the Alerts page. Full source-of-truth doc in Notion → Alerts.
What status means
Open — fresh alert, nobody's looked at it yet. Acknowledge to claim it, resolve when fixed.
Acknowledged — someone's on it. Still active. Move to Resolved when the underlying issue is actually fixed.
Resolved — the issue was real and is now fixed. Kept for history.
Dismissed — false alarm or no action needed. Kept for history.
What the alert types mean
auth-user / login_* — login service slow or hung. Critical. Check Supabase status first.
monitor_* — usage spike or anomaly (AI generations, webhook flood, lead flood, spam, cost). Verify it's not a real campaign before acting.
capacity_* — runtime infra under pressure. Check the Infra Health page's Runtime canaries; consult the Capacity Playbook.
client_error_* — JS exception in inbox / dashboard / internal app. Customer email + business name are auto-enriched on the right side of the alert row — reach out proactively if it looks impactful.
meta_oauth_* / meta_deauth — Facebook/Instagram connection issue. Open the customer record from the alert to see what state they're in.
Triage workflow
Look at the Active filter (Open + Acknowledged). Anything red severity goes first.
Click Acknowledge on the ones you're claiming — others see you're handling them.
Open the customer record (right-side button) to see context — recent activity, status, history.
Take action (reconnect Meta, refund a flood, etc.). Then click Resolve.
If it was a false alarm, click Dismiss instead. Both clear the row from Active.
When to use ⚡ Bulk action
Only when a known infra event flooded one alert type — e.g. a webhook misconfig that fired 200 alerts for the same root cause. Apply the type pill filter first, then click Bulk action to resolve all of them at once. Bulk action operates on whatever filter you have active — read the confirm prompt carefully.
Industry-keyed AI templates served to customers. Click an industry to view the AI instruction prompt (used by the AI assistant when replying to leads) and the three suggestion cards (shown in Lead Generation when a customer doesn't have enough lead history yet).
—
Industry
Instruction
Suggestions
Customers
Last edited
No industries yet. Click "+ Add Industry" to create the first one.
Self-monitor of LeadHub AI's own infrastructure. Daily check at 08:00 UTC compares key metrics against Supabase Pro-tier thresholds and alerts at 70% (warn) and 90% (critical). See the Tech Stack Scalability doc for what each threshold means.
Refreshed daily at 08:00 UTC by infra-metrics-cron.
📧 Alert Configuration
Where to send alerts and which channels are active. Applies to all thresholds.
✓ Saved
🚨 Active Alerts
Un-acknowledged breaches. Click acknowledge to clear from the banner.
📋 Alert History (last 30)
Every threshold event, including already-acknowledged ones.
🧪 Test & Monitor
Run health checks, API monitor pings, and execute the workflow test suite from the terminal.
📸
Visual QA — Screenshot Tests
Captures 16 screenshots across all 3 apps to verify pages render correctly
# Run from terminal:
cd ~/code/leadhub-tests
TEST_PASSWORD=xxx INTERNAL_PASSWORD=xxx npm run test:visual
# Watch in real-time (opens Chrome):
npm run test:visual:all-headed
# Test one app only:
npm run test:visual -- --app # inbox only
npm run test:visual -- --dashboard # customer dashboard
npm run test:visual -- --internal # internal dashboard
Screenshots saved to leadhub-tests/screenshots/ with HTML report that opens automatically
🔄
Workflow Tests — Business Flow Validation
Test critical paths end-to-end. Run the specific flow you changed.
✓ Copied to clipboard — paste in terminal
Click the card title/body to copy its command. Click ▸ What this checks to expand the full assertion list. Run from ~/code/leadhub-tests/.
Loading usage data...
Manage the Twilio number pool — provision, assign, release.
💡 Active alerts triggered by these thresholds now appear in the Alerts page in the sidebar (filter by type pills like Infra · …).
Alert Thresholds
Adjust these values as you scale. The monitor checks every hour and alerts when usage exceeds these limits.
✓ Saved
Loading plan changes...
📋 Changes & Cancel Playbook
How to handle plan changes and cancellation requests
Status Workflow
🔥 NewJust submitted by customer. Needs immediate attention.
👀 ReviewedYou've seen it but haven't contacted the customer yet.
📞 ContactedYou've reached out to the customer to discuss.
✅ ProcessedFully handled — change applied or cancellation confirmed.
↑When a Customer Changes PlanChange
Plan changes happen automatically via Stripe. When you see a new entry:
Set status to 👀 Reviewed
Verify the change in Stripe dashboard (payment processed?)
Call the customer to confirm and thank them
If upgrading: walk them through new features (dashboard access, AI ads, etc.)
If downgrading: ask why, offer a discount or extend trial if applicable
Set status to 📞 Contacted after call
Once fully confirmed, set to ✅ Processed
💰 How Proration & Billing Works
Stripe handles all proration automatically when a customer changes plan:
Upgrade (e.g., Starter → Growth):
Stripe calculates the price difference for remaining days in the billing cycle and charges the prorated amount to the card on file immediately. Next month charges the new full rate.
Downgrade (e.g., Pro → Growth):
Stripe creates a credit for the unused portion of the higher plan. This credit is automatically applied to the next invoice, reducing what the customer pays next month.
Example: Customer on Pro ($599) downgrades to Growth ($399) with 15 days left → credit of ~$100 applied to next invoice. Next month they pay ~$299 instead of $399.
⚠️ If a Customer Asks About Their Bill
"Why was I charged extra?" → The prorated charge covers the difference for the remaining days on the new plan. It's not a double charge. "When will I see the credit?" → Credits appear on the next invoice automatically. They can verify in Stripe by clicking Manage Billing in the dashboard. "Can I get a refund instead of credit?" → Credits auto-apply to next invoice. For refund requests, contact support.
Script — Upgrade
"Hi [Name], I saw you upgraded to the [Plan] plan — great choice! A prorated charge of [amount] was applied for the remaining days this month, and next month you'll be billed [new rate]. I wanted to make sure you know about [new features]. Do you have any questions?"
✕When a Customer CancelsCancel
Priority: Contact within 1 hour. Cancellations are retention opportunities.
Set status to 👀 Reviewed immediately
Call the customer — don't email first, a call is more personal
→ Offer a downgrade (Pro→Growth saves $200/mo) or a 1-month discount
"Not getting enough leads"
→ Review their setup: is FB connected? Service pricing added? AI enabled? Often fixable.
"Don't have time to manage it"
→ Remind them the AI does everything automatically. Offer a quick training session.
"Closing/selling business"
→ Thank them, process the cancellation, wish them well.
Script — Cancel Call
"Hi [Name], I noticed you submitted a cancellation request. I'm sorry to hear that — I wanted to personally reach out and see if there's anything we can do. What's been your experience so far?"
What Happens After Cancellation
The app keeps working until the end of the billing period
Customer data is retained for 90 days after billing ends
Customer can reactivate anytime during the 90-day window
After 90 days, data is permanently deleted
The customer receives a confirmation email with these details
🎯 Trial → Paid Conversions
When a trial customer subscribes via Stripe, it shows here as a Change (TRIAL → [Plan]).
Call to welcome them as a paying customer
Confirm their plan choice and features
Offer a quick walkthrough of any new features they now have access to
Set to ✅ Processed after confirmation
Date
Customer
Type
Change
Price
Status
Your Customers
Earnings shown at the AE rate (40% of monthly billing for active customers).
Estimated monthly
—
Customer Roster —
Loading…
Commission rate is the AE Y1 rate; renewal commission is 15% lifetime (computed separately at billing time).
See your AE agreement for the full schedule. Numbers update as customers are added, change plan, or cancel.
Role Reference
Owner
Full access. Billing, role assignment, destructive ops. Can view a customer's dashboard (staff view).
Global Admin
All customers, all pages. Can view a customer's dashboard (staff view). Cannot manage staff or change defaults.
Basic Admin
Read/write customers. No infra, no secrets, no SQL.
Support
Read-only customers + reply-as for tickets.
AE / Sales
Only own customers + own commissions. Can register + support own accounts.
Staff Members —
Loading…
Activity —
Loading…
Default Business Hours applied to new accounts
Customers can edit after onboarding. Uses customer's local timezone.
Plan Caps monthly limits
GenerationsDrafts
Starter
Growth
Pro
Trial & Onboarding
Branding & Sender
Flags —
Toggle a flag globally, or target it to specific customers. Changes take effect within 60s.
Loading…
Invite Staff Member
AE-specific
An invite email with a one-time setup link will be sent. The link expires in 72 hours.
📋 Infra Health Playbook
Every option on this page, what it does, and when to use it
🧭What this page is
Infra Health is LeadHub AI's self-monitor — the platform watching itself. A daily cron at 08:00 UTC captures key metrics (DB size, customer count, webhook volume, active cron jobs) and compares them to the Pro-tier limits documented in the Tech Stack Scalability doc. When a metric crosses 70% it warns; at 90% it escalates to critical. This gives us months of runway to plan tier upgrades or architecture changes instead of being surprised by a broken production.
📊The metric cards (top of page)
Each card shows one metric with its current value, a progress bar against the limit, and a percent + severity label.
Database size (8 GB limit)
Supabase Pro includes 8 GB. When this crosses 70% (5.6 GB) start planning the Team plan ($599/mo) upgrade which raises the limit to 100 GB. Writes fail silently once the hard cap is hit.
Active customers (500 watermark)
Not a hard limit — just a "plan your Team plan migration" threshold. At 500 paying customers we should already be on Team for connection count, backup retention, and HIPAA BAA.
Messages processed (30d) — proxy for edge function invocations
Supabase Pro includes 2M edge function invocations/month. We count messages × 2 as a rough proxy (inbound webhook + AI reply). If this crosses 70% consider Team plan or usage-based overages.
pg_cron active jobs (20 soft limit)
pg_cron starts getting fragile past ~20 scheduled jobs. When this crosses 70% we should migrate multi-step workflows to an external queue (Inngest, Upstash QStash, or Temporal).
Color: green = OK (0-69%), amber = warn (70-89%), red = critical (90%+). Progress bar fills proportionally.
📧Alert Configuration card
Alert Email
The address that receives all alert emails and weekly recaps. Defaults to luisf@leadhubai.io. Change anytime; takes effect on the next cron run.
Email toggle
Global on/off for all alert and recap emails. Set to Disabled for maintenance windows or vacation (you'll still see the in-dashboard banner when you log in).
Push (critical)
When enabled, a critical (90%+) alert also triggers a browser push notification to any admin subscribed via the internal dashboard PWA. No push for warns — email only.
Weekly recap
Monday UTC email with green-status confirmation + current usage table. Disable if you find it too noisy.
Save Configuration button
Persists all 4 fields above to the infra_config table. Validates the email format before saving.
⚡ Run Check Now
Triggers the cron function manually — captures current metrics, fires any alerts, snapshots to infra_metrics. Useful for testing after a config change or when investigating an issue.
🚨Active Alerts + Alert History
Active Alerts: threshold breaches that haven't been acknowledged yet. Each row shows the severity icon, human-readable message, timestamp, and an Ack button. The red banner at the top of every dashboard page stays visible until you acknowledge everything here.
Ack button per row: clears that one alert. Use when you've read it, noted it, and don't need to be re-pinged on the next cron cycle.
Ack All button: only appears when there are active alerts. One-click dismiss for everything pending.
Alert History (last 30): every alert ever fired, acknowledged or not, with timestamps. Use this to spot patterns — e.g., "DB size crossed 70% three times in the last month, trending up fast."
🧪Test & Monitor section
Previously lived on the API & Billing page. Moved here because testing is really an infra-quality concern, not a billing one.
Run Health Check
Pings every edge function endpoint and reports live response times. Takes 5-10 seconds. Run after any deployment to verify nothing broke.
Run Monitor Now
Triggers the api-monitor cron (normally hourly) manually. Updates the alert badge and refreshes alert thresholds.
Visual QA panel
Instructions for the Playwright screenshot test suite. Captures 16 screenshots across 3 apps. Run before major releases.
Workflow Tests (20 cards across 4 groups)
End-to-end business flow tests. Click a card body to copy its npm run test:workflows:* command; paste in terminal to run. Click ▸ What this checks on any card to expand the full assertion list for that suite. Cards are grouped by color-coded border:
Core flows (gray border, 12 cards): Onboarding, Trial Signup, Guided Trial, Trial → Paid, Plan Change/Cancel, Team, Pricing, Lead Lifecycle, Support Chat, Custom Limits, Account History. Trial + Lead Lifecycle cards were revised for the 4-consent flow and the AI "don't ask for name on FB/IG" + phone/email/address extraction behaviors.
Compliance (amber border, 4 NEW): SMS Compliance (STOP/HELP/START + business-branded replies), Meta Deauth (HMAC-signed callback), Meta Data Deletion (confirmation_code + status page), Meta 30-day Purge Cron.
Lead pipeline (green border, 2 NEW): Sales Pipeline (new → reviewed → contacted → processed on FB/IG/SMS + Website leads), Register from Lead (status flips to Registered + prefill into pg-register).
Audit tools (blue border, 2 NEW): SMS Phone Lookup (consent + opt-outs + events + CSV export), Infra Health Monitor (self-tests the very cron this page depends on).
A full Run ALL Workflows card (gray, full-width) runs every suite (~80 tests, 6–8 min). Run single cards for quick post-deploy smoke tests; run ALL before tagging a release.
⚠️When to act on alerts
🟡 Warn (70%+)You have 1-2 months of runway. Plan the next tier upgrade, add the relevant migration to the roadmap, and schedule the work for next sprint. No emergency.
🔴 Critical (90%+)Days of runway, not weeks. Upgrade the tier or migrate within 3-7 days. Writes can start failing silently beyond 95% on storage limits.
🔗Related resources
• Tech Stack Scalability & Migration Analysis (Notion) — per-component thresholds and migration triggers
• Supabase Dashboard — ground-truth DB metrics, function logs, usage billing
• Vercel Dashboard — bandwidth, build minutes, function invocations
• infra_config / infra_metrics / infra_alerts — the three DB tables backing this page
📋 Customer Detail Playbook
Guide for managing customer accounts from the detail view
✏️Edit Customer
Click ✏️ Edit Customer to modify any field:
Business info — name, owner, email, phone, website, industry
Plan — Starter ($250), Growth ($399), Pro ($599)
Custom price — override the default plan price for special deals
Status — TRIAL, ACTIVE, PAUSED, CANCELLED
Sales person — reassign to a different rep
Timezone — sets the clock the customer's team sees in the Lead Inbox (see section below)
Monthly Lead Cap — leave blank to use the plan default, or type a custom number (see Monthly Lead Cap below)
Staff discount — % off the price; applies automatically when the customer starts paying (Global Admin up to 40%, Owner up to 70%) — see Custom Plan & Staff Discount below
Custom plan — more users and more leads than a standard plan, billed as one Stripe subscription — see below
How Plan & Price Changes Work
When you change a customer's plan or price from Edit Customer, you need to do two things:
Step 1 — Edit Customer here: Change the plan and/or price → Save. This updates our database so the app and dashboard show the correct plan.
Step 2 — Update Stripe: Go to dashboard.stripe.com → find the customer → update their subscription to match the new plan/price.
Both steps are needed for paying customers. For trial customers (no Stripe yet), only Step 1 is needed.
💰 Special pricing — which tool to use
A % off the normal price (promo, partner, friend & family) → Staff discount in the Edit form. It reaches Stripe by itself at checkout — no manual Stripe edit.
A fixed special price (e.g. Pro at $450) → use a Staff discount with the % that gets there (450 vs 599 ≈ 24.9%). Only the Owner can go above 40%.
More users or leads than the plan allows → Custom plan.
Changing the Monthly Price field alone only changes what our app shows — it does not change what Stripe charges. Editing a subscription amount by hand in Stripe is no longer needed for any of the above.
🎯 Founding 50 members — bill at their locked rate, NOT list price
If the customer detail shows a 🎯 F50 #N badge, they're a Founding 50 member. When setting up their Stripe subscription, use the locked Founding rate, not the regular plan price. The rate depends on the plan: Starter $150 · Growth $250 · Pro $350. The detail page shows the exact figure as "🎯 Bill at $X in Stripe" right under the customer name — always trust that number over this list.
The rate is locked for 60 months from their Accept date. After that, they can be moved to then-current pricing. The badge shows the exact lock-until date and months remaining. Founding 50 customers also get a 30-day trial (standard customers get 14).
📋 Updating Stripe — Step by Step (standard plan changes only)
Custom plans and discounts update Stripe automatically — you don't do these steps for them.
Change the price to the new plan's price (or custom amount)
Choose "Prorate" to adjust the current billing period
Click "Update subscription" to confirm
🧩Custom Plan & Staff Discount
For customers who need more than a standard plan (more users, more leads) or who were promised a discount. Only the Owner and Global Admins can change these settings — the fields are greyed out for everyone else and the server enforces it too. Every change is written to the audit log.
Set up a custom plan
Customer detail → ✏️ Edit Customer. Leave Plan = PRO — custom plans build on Pro, so features don't change.
Extra leads — bundles of 1,000 ($180 each, any channel). Pro already includes 2,000 leads a month.
…of those, expected over SMS / WhatsApp — bundles of 1,000 (+$75 each). It's an add-on to the $180 bundle (one SMS/WhatsApp bundle = $255) and can't be more than the extra bundles above.
Optional: a Staff discount (below). The price box shows the monthly total as you type.
Save Changes → confirm. The form stays open with "✓ Saved".
How it's priced
Monthly = Pro $599 (10 users + 2,000 leads) + $20 × extra users + $180 × extra bundles + $75 × SMS/WhatsApp bundles
15 users, no extra leads → $699
25 users, 4 extra bundles (6,000 leads) → $1,619
…with 1 of those bundles over SMS/WhatsApp → $1,694 · all 4 → $1,919
The 2,000 leads Pro includes carry no SMS/WhatsApp charge. Fair use (contract term, not enforced in code): an SMS/WhatsApp lead covers up to 12 messages a month; a longer thread counts as another lead.
Getting them paying (Stripe)
In the Edit form, the Custom plan billing (Stripe) panel shows the quote. Click Check Stripe: it shows the Stripe mode (test / live), whether the add-on prices are there, and the subscription status. If the prices are missing, a Set up Stripe prices button appears (needed once per Stripe mode — e.g. at go-live).
Create checkout link (or Email checkout link). Open the link first and check the lines and the total. The customer pays with their card; the link works for 24 hours. A discount is attached when the link is created — set it first.
Once they've paid, they're ACTIVE on a custom subscription and their stored monthly price is the real total.
After that, every Save updates Stripe automatically (prorated) — you'll see "✓ Stripe updated — now $X/month". Sync to Stripe is only for retrying after an error.
In Stripe test mode nothing is real — pay with card 4242 4242 4242 4242, any future date and CVC.
Staff discount
Edit Customer → Staff discount: percent, how long (ongoing, or 3 / 6 / 12 / 24 months) and a reason for the audit log. Global Admin up to 40% · Owner up to 70%.
Standard plans: applied automatically at the customer's next checkout (trial → paid) or plan change. They see the discounted price on their billing page. It is not pushed onto a subscription they already have.
Custom plans: attached when you create the checkout link; on an existing custom subscription the auto-sync applies it when you save. It applies to the whole custom total.
A Founding 50 lock can't be combined with a discount. Use Remove Founding lock… in the same section first (asks to confirm, audited) — they lose the locked price.
⚠️ Good to know
The lead cap is not enforced — it sets the price and the usage display; a customer over it isn't blocked.
Custom customers can't buy or change a plan themselves; they see "custom plan — contact us".
Changing a paying customer's custom plan creates a prorated charge or credit in Stripe right away (the review step warns you).
The stored monthly price is rounded to whole dollars; Stripe bills the exact cents.
A customer already paying on a standard subscription can't be converted to custom in-app yet — the checkout link and Sync both refuse.
Don't edit the three add-on prices in Stripe ($20 / $180 / $75) — checkouts refuse to run if a price doesn't match the quote.
🕐Customer Timezone
Every customer has a pinned business timezone. All time-sensitive labels the customer's team sees in the Lead Inbox (message bubbles, job times, follow-up schedules, lead-created labels) render in this zone — so a Tampa owner and their Phoenix team member both see the same "4:55 PM" regardless of where they log in from.
How to update it
Open this customer's detail page
Click ✏️ Edit Customer
Scroll to the Timezone dropdown (below Ad Limit)
Pick the customer's operating zone
Click Save Changes → confirm
Change takes effect the next time the customer's team opens the Lead Inbox (auto-refreshes within 60 seconds via poll, or on page reload).
Available zones
Eastern (default — FL-focused market) · Central · Mountain · Arizona (no DST) · Pacific · Alaska · Hawaii · Puerto Rico (no DST) · UTC
⚠️ When to check it
New customer onboards from outside Florida → confirm zone on day 1
Customer reports "times are wrong by X hours" → the zone is off by X hours
Customer relocates their business → update to the new zone
New customers default to America/New_York; migrated existing customers also default to Eastern — update individually if not in ET
ℹ️ Under the hood
Stored on customers.timezone as an IANA zone string (e.g. America/New_York). The Lead Inbox reads it from /inbox/account and passes it to every time-formatter. All message timestamps are stored as timestamptz (UTC) in the DB, so changing the zone only affects display — no data migration needed.
⚙️AI & System Settings card
The right-hand card next to Business Info (it stacks underneath on a narrow window). AI Response, Response delay, Email notify and Business hours are read-only summaries. The two rows with buttons are staff-only switches — customers can't see or change them.
Address required
Whether the AI treats a service address as a field it must collect before qualifying or handing off a lead. On by default. Turn it off for businesses with no service-area concept (e.g. a nationwide reseller like Globo Mark) so the AI doesn't waste a turn asking for one. Click the button and confirm to flip it.
📲 Push routing — who gets a push notification for a lead
Everyone on the team (default)
Pushes for unowned leads (new comment leads, new form leads, AI flags) go to every team device. Right for teams where agents claim leads themselves.
Assigned agent, else Owner/Admin
A lead's push goes only to the agent it's assigned to. If nobody is assigned yet, only Owner and Admin users get it — agents never do.
The restricted mode also covers WhatsApp appointment confirmed / reschedule / cancel, lead re-engaged and lead closed — they reach only the assigned agent (or Owner/Admin if unassigned).
A push that already names one person (e.g. "New lead assigned to you", "Customer replied" on an owned lead) always goes to just that person, in either mode.
Admin-role logins count. Anyone with the Admin role on the customer's account — including a LeadHub support login — receives unowned-lead pushes in restricted mode. There's no per-person opt-out.
If the assigned agent has notifications off (no registered device), the push is dropped — it does not fall back to the Owner/Admin.
Takes effect immediately; flip it back the same way to undo. Currently on for Globo Mark.
Under the hood: customer_settings.pushMode (ALL | ASSIGNED_OR_ADMIN), enforced in the send-push function. Each push logs a [send-push] route=… line (assignee / admins / all / explicit) — check it if a rep says they didn't get one.
📈Monthly Lead Cap
Set under ✏️ Edit Customer → Monthly Lead Cap. Leave it blank to use the plan default — Starter 150 · Growth 500 · Pro 2,000 a month — or type a number to override it. The hint under the field shows which one applies (it updates as you change the plan or type). A custom value shows a purple Custom badge at the top of the detail page.
How "this month" is counted
Leads created since the 1st of the current calendar month, in the customer's timezone — not a rolling 30 days (changed 2026-09-01). It resets on the 1st. The customer's own dashboard sidebar shows the same number, plus an all-time total.
On a Custom plan
The cap is set by the lead bundles (2,000 + bundles × 1,000) and is read-only in the form while Custom plan is on — change the bundles instead. See Custom Plan & Staff Discount above.
⚠️ It is not enforced yet
Right now the cap is a display number only. Going over it doesn't stop new leads or the AI from replying, and nothing alerts anyone. The AI does log a [ai-respond][lead-cap-dryrun] line on every message with wouldBlock: true/false, so we can see who would be stopped before any hard cap is switched on. Don't promise a customer that a hard limit exists.
🔌Channels Configured & Feature Flags
Channels Configured is a read-only status board for the customer's four channels:
SMS — the assigned Twilio number and area code (or "Not assigned")
Facebook — connected Page name, Page ID and connect date
Instagram — linked through the same Facebook Page
WhatsApp — uses the same Twilio number as SMS; shows "Not enabled" until switched on under Channels → Assign
⚠️ The Instagram "DM permission missing" warning can be a false alarm
It has shown up even after Meta's Advanced Access was approved. Don't treat it as proof DMs are broken — check whether IG DMs are actually arriving as leads before troubleshooting.
Feature Flags sit right under the channels. Every flag is off by default for every customer; staff turn each one on per customer with Enable / Disable. It takes effect on the customer's next request — no redeploy.
Meta Ads (paid Facebook + Instagram) — unlocks the Meta Ads sub-tab in Lead Generation. Staged rollout: enable only for Founding 50 Pros and Pros already running Google Ads successfully.
👥Team Members & who sees what
The Team Members card near the bottom of the page is a read-only list — name, email, role and date added. Customers add and remove people themselves in their own dashboard; you can't edit them here.
Owner / Admin — see every lead on the account and can assign a lead to any team member
Agent — sees only the leads assigned to them
Seats by plan — Starter 2 · Growth 5 · Pro 10 (a Custom plan adds its extra users on top of Pro's 10)
Roles also decide who gets unowned-lead pushes when Push routing is restricted (see above). If a rep says they can't see a lead, first check whether it's assigned to them.
🧰Other buttons on the page
✨ Improve AI Instructions — a wizard to draft and test this customer's AI custom instructions. The greeting is left untouched. Only shown to staff roles with settings access.
📱 SMS Compliance — jumps to SMS Compliance → Phone Lookup for the customer's number. Only shown when they have a phone on file.
🗑 Delete (testing) — hard-deletes the customer and its accounts, releases phone numbers and frees the email. Global Admin only, for test accounts only — never a real customer. It can't be undone.
🔎Support gotchas
"A lead / booking disappeared from the app"
The mobile Lead Inbox only loads leads created in the last 30 days — by design, there's no history view in the app. An older lead, and any booking attached to it, is simply not loaded; nothing has been deleted. (Before 2026-09-02 it loaded only the newest 100 leads, which hid leads within days at busy accounts.)
"Bookings are showing under the wrong person"
When someone schedules a call or visit, the "assigned to" picker now defaults to the person scheduling it (fixed 2026-09-02). It used to default to the account's oldest user — usually the Owner — so a booking made without changing the picker landed under them. Older bookings created that way can be fixed by opening the job in the app (Jobs → tap the booking) and changing the assigned-to person.
"A lead stopped replying — is the AI broken?" (added 2026-09-30)
Not a bug if the lead was flirty, personal, or otherwise not actually asking about the business — the AI now recognizes that, declines once, and closes the lead instead of replying to every follow-up message. If that same person messages again, the AI stays silent for 24 hours rather than restarting — the lead is still there with the message attached, it just won't get a reply until the window passes. A normal "Closed - Not Interested" close from an agent is not affected by this and still reopens instantly, same as always. Applies to every customer automatically, no setting to find. See the Notion "Bot & Spam Protection" page (2026-09-30 update) for the full mechanics.
📧Resend Onboarding Email
Generates a fresh 48-hour onboarding link and sends it to the customer. Use when:
Customer says they didn't receive the original email
The original link expired (48 hours)
Customer needs to redo their setup (consent, Facebook, password)
📄View Contract / Consent
Click View Agreement ▼ to expand the signed document inline. Two types:
Service Agreement
Full contract for customers registered via internal dashboard (onboarding.html)
Trial Consent
Consent record for trial customers from website (trial-setup.html)
📋Account History
Shows the complete activity timeline pulled from Stripe + our database:
📌Account Created — when customer was registered
🚀Trial Started — Pro trial began (14 days; 30 for Founding 50)
Manual plan/price changes via Edit Customer update our database only and do not appear in this history (which comes from Stripe). Only Stripe-processed changes (checkout, subscription updates, payments) show here.
📊Understanding the Stats
Total Leads — all leads captured for this customer, all-time
"X/limit leads this month" (top of the page, next to the price) — leads created this calendar month in the customer's timezone against their monthly cap; resets on the 1st. The small "N all-time" beside it is the lifetime total. Green under 70%, amber from 70%, red from 90%.
Messages — total SMS/DM messages sent & received
Follow-ups — AI-generated follow-up messages
AI Messages — messages generated by the AI
Leads by Status — breakdown of lead pipeline (New, Contacted, Booked, etc.)
Messages by Channel — SMS vs Facebook vs Instagram vs WhatsApp