# Vibn — Product Blueprint & Go-to-Market Architecture

> Status: Draft v3 · Owner: Mark · Last updated: 2026-06-04
> v3 sharpens the wedge to **custom tools** for local businesses (not
> websites/marketing), makes onboarding **expertise-first → dashboard** (no pitch
> generator), and moves the targeting/"gold rush" recommendation into the
> dashboard. v2 (services+margins+pitch onboarding) is superseded; v1 (founder/
> build-first) before it.
>
> Implemented so far (FE, against mocks + typed contracts): the contractor
> onboarding flow — `app/(onboarding)/onboarding/onboarding-agency*.{tsx,ts}` +
> the front-door fork in `page.tsx`. Backend + dashboard pending (handoff doc).

---

## 1. Positioning

**Vibn is the operating system for a new breed of local-business consultant — it
helps them find local SMBs, build them the *custom tools* they actually need
(without writing code), and bill for it profitably — so those businesses stop
paying for a stack of expensive SaaS apps that don't talk to each other.**

The wedge is **custom tools, not websites/marketing.** Every local business is
overpaying for generic SaaS that half-fits; the consultant builds one tool that
fits their workflow exactly.

Think **Harvest for AI vibe coding**: the place a consultant runs the whole
client business — find, build, host, invoice.

Two audiences, one engine — but a clear hero:
- **PRIMARY · The new consultant / freelancer / small studio.** Often not a deep
  engineer (a marketer, designer, or hustler starting a "websites + marketing for
  local business" practice). Vibn is their unfair advantage. **They are the buyer.**
- **SECONDARY · The SMB owner doing it themselves.** Same engine, no markup. Served
  by self-serve, not chased.
- **De-emphasized:** startup founders. That lane (Lovable, v0, Bolt, Replit) is a
  bloodbath and is *not* where our infrastructure points.

### Why this wedge (the infra already leans here)
- `market_categories_suggest` returns **Google Business Profile** categories — a
  *local business* construct.
- `market_research_run` pulls local **business leads, TAM, competitors** (DataForSEO).
- Missinglettr lists **Google Business** among its 12 platforms — local social + GBP.
- The "owner" persona pitch is *"replace the stack of tools you rent"* — SMB ops.
- The Cadence CRM template = contacts + scheduling; domains + Stripe = every SMB.

None of this was built for startups. It was built for **local SMBs and the people
who serve them.** This is a focus, not a pivot.

---

## 2. The two front doors

Opposite motivations require opposite openings:

| Door | Who | First question they're asking | Opening |
|---|---|---|---|
| **"Personal"** | SMB owner / self-builder | *"Can I see my thing built?"* | **Build-first** — straight to a live themed preview (§6) |
| **"Agency"** (HERO) | New consultant | *"Can I do this? What do I build? Who needs it? How do I get a client?"* | **Contractor-first** — set up the agency, state your expertise, land in a dashboard of local targets (§4) |

The homepage leads with the consultant promise and routes self-builders to the
simpler path — it does **not** treat them as equals.

> Reversal from v1: "get to a live preview ASAP" is right for a self-builder and
> *wrong* for a consultant. A consultant is evaluating a **business**, not a build
> tool. Lead with the contractor parts; building happens later, per client.

---

## 3. The lifecycle = one client engagement

For the consultant, the product lifecycle is the shape of **a single client
engagement**, run once per SMB client:

```
DISCOVER  →  BUILD  →  REFINE  →  GROW
the pitch    deliver    iterate    the retainer
(win it)     the site   with client (recurring $)
```

It's driven by two orthogonal axes (kept distinct in code — today they're conflated):

| Axis | Controls | Decided |
|---|---|---|
| **Engagement stage** | The *path* (research/pitch vs build vs grow) | Per client, by where the deal is |
| **SMB domain** (trades, salon, dental, food, fitness…) | The *look* — template family + theme | Inferred from the business type |

A consultant runs many clients at different stages simultaneously.

---

## 4. Contractor-first onboarding — "Set up your AI agency"

Onboarding is short and has one job: learn **who the consultant is** and **what
they love building**. The moment we know their sweet spot, we drop them into
their **dashboard** — where the local-business recommendations live as an
ongoing feature (not a one-shot screen). No pitch generator, no terminal
targeting screen in onboarding. *(Implemented: `app/(onboarding)/onboarding/onboarding-agency.tsx`.)*

```mermaid
flowchart TD
    A["1 · Your agency<br/>name · city (Places lookup)"] --> B["2 · Your presence<br/>what does your agency have today? (checklist)"]
    B --> C["3 · Your ideal customer (free text)<br/>'who / what problem do you want to solve?'"]
    C --> D["Open my dashboard →"]
    D --> E["DASHBOARD<br/>AI reads description → recommends local businesses to target"]
```

- **Agency** option details: "I want to do billable AI work for others" (VIBN helps you find local businesses that you can build custom solutions for).
- **Personal** option details: "I want to build my own ideas" (Go from idea to market, and beyond).

### Step contents
1. **Your agency** — name, **city** (global Places-API lookup, §6.x).
2. **Your presence** — "What does your agency have today?" Checklist of assets
   (Website, social media accounts, blog, custom domain, existing billing).
   Light profiling to customize their dashboard experience.
3. **Your ideal customer** *(the heart of it)* — a **free-text** box: *"Is there a
   certain type of business or business problem you are passionate about?"*
   (e.g. "I want to help dentists automate patient booking"). If they are undecided,
   clicking **"I'm not sure right now"** bypasses the step with a neutral default
   ("help any local business automate workflows"). This replaces the old examples list.
   Vibn will help them match with potential customers in their area, and drive awareness of their brand.
4. **→ Dashboard.** CTA "Open my dashboard →" finishes onboarding with
   `{ profile, expertise, tools }` (AI-extracted tool categories, where `expertise`
   holds the ideal-customer string).

### The Local Business Category Lookup & Mapping Pipeline (onboarding)
This is the core "Business Identity & Needs" pipeline run on Step 1 of the self-builder flow, designed to bypass Google's messy administrative category labels:
1.  **Step 1: City Geocoding & Radius Setup:**
    - The user selects their city in Step 1. The frontend retrieves their structured `CityRef` (holding `lat`/`lng` coordinates from Google Places) and sets a default radial search geofence of **50km**.
2.  **Step 2: Geofenced DataForSEO Business Search:**
    - The backend takes the business name (or URL) and queries the **DataForSEO Business Listings Search API** (`/v3/business_data/business_listings/search/live`) using geofenced `"location_coordinate"` radial search:
      `"location_coordinate": "{{lat}},{{lng}},50"`
    - This bypasses Google's strict SAB restrictions, pulling down the full business records (including mobile businesses with hidden addresses like "Wheely Clean Mobile Dental").
    - The server extracts GMB's main `"category"` and `"additional_categories"` arrays.
    - It joins them to our `smb_to_software_mapping_final.json` dataset (the 4,006-item database) to fetch their exact, customized software tool requirements.
3.  **Step 3: Unpacked Category Card Selection ("Which best describes your business?"):**
    - The frontend receives the matched business, and automatically unpacks **both its primary category and all discovered GMB alternative categories** into individual clickable cards.
    - The screen displays: **"Which best describes your business?"**
    - Selecting any card (e.g. *Dental hygienist* or *Teeth whitening service*) instantly loads that specific subcategory's custom presets and advances to Step 2!
    - *Fallback:* If DataForSEO or geocoding fails (e.g. offline dev), it gracefully triggers Google Places Text Search (New) + Gemini 2.5 Flash as an automated fallback reasoning bridge.

### The targeting engine (lives in the dashboard)

### The dashboard (the home screen they land on)
- **Recommended targets** — the AI's local-business recommendations (above),
  refreshable; claim one to start a client/prospect.
- **Clients / prospects** — each SMB; status (prospect → won → live → retainer).
- **Projects** — per client (a custom tool build + hosting/support retainer).
- **Revenue & margin** — what each client costs me vs. what I bill; retainer MRR
  (illustrative until metering lands, then live).
- Building a client's tool is entered **from a client**, not the dashboard root.
- *(To build next — reuses `extractTools` + `mockTargets`; light paper/ink theme.)*

---

## 5. Modes — capability surfaces with enforced tool gating

Three modes (capability surfaces, not vibes). **Refine is not a mode** — it's Build
against an already-live project.

| Mode | Engagement role | Stop condition |
|---|---|---|
| **Collab** | Discover — research + pitch + spec | PRD + decisions + backlog (the spine) |
| **Build** | Deliver the site + refine | A clickable preview / shipped `fqdn` |
| **Grow** | The retainer — distribute + monitor | Scheduled content + live analytics |

### 5.1 Tool gating is enforced, not described
Today "DO NOT WRITE CODE" is a prompt *request* while `fs_write`/`ship`/`shell_exec`
stay in the tool list → the constraint is soft and the prompt re-teaches the
forbidden workflow. Fix: one `MODE_TOOLS: Record<Mode, ToolName[]>` map, read by:
1. **Prompt builder** — filters exposed tool schemas per mode (model can't see what
   it can't call; also cuts ~88 schemas → ~20–30 = token/latency win).
2. **Dispatcher** — rejects out-of-mode calls (guards hallucinated names).
Applied in **both** `vibn-frontend/app/api/chat/route.ts` and the agent-runner.

### 5.2 Allowlist sketch
| Capability | Collab | Build | Grow |
|---|---|---|---|
| Reads (`projects_get`, `apps_*` reads, `get_design_template`) | ✅ | ✅ | ✅ |
| Research (`market_*` 💲, `github_*`, `http_fetch`) | ✅ | ❌ | ✅ (seo/insights) |
| Spine docs — `fs_*` **scoped to `.vibncode/specs/`** | ✅ | ✅ (+ repo) | ✅ (blog/SEO) |
| Design kit / `apps_templates_scaffold` | propose | ✅ full | theme marketing |
| Engineering (`shell_exec`, `dev_server_*`, `apps_create`, `ship`, `databases_*`) | ❌ | ✅ | `apps_create { repo }` only |
| Distribution (`missinglettr_*`, `generate_media`) | ❌ | ❌ | ✅ |
| Destructive (`*_delete`, `apps_volumes_wipe`) | ❌ | ⚠️ confirm | ❌ |

Gating gives each guardrail a home: **money gate** in Collab, **destructive-confirm**
in Build, **untrusted-content rule** in BASE (Collab + Grow read the open web).

### 5.3 Prompt composition
```
BASE   identity · voice · spine/task-ledger contract · infra model · hard rules ·
       untrusted-content rule · project + client/agency state
  +
MODE   { Collab | Build | Grow } — behavior + stop condition + protocols
  +
CONTEXT design kit · decisions/backlog · stage seed · SMB-domain template guidance
```
BASE + MODE must be **shared modules imported by both** the chat route and the
agent-runner (today there are three drifted copies — root of the "loops on task 1"
bug).

### 5.4 Visibility
Modes **auto-select** by stage + project state. The toggle remains a power-user
override. Nobody picks a mode manually.

---

## 6. Build-first door & design-first delivery

The build flow is no longer the front door — but it's still how work gets
*delivered* (and how a self-builder enters). It must be **design-first, not
code-first.**

- **Stop** scaffolding from `create-next-app` + hand-building UI (slow, generic,
  the source of visual-QA loops).
- **Start** from a polished, CSS-variable-themed template family, reskin to the
  SMB's brand via the design-kit token system, then populate content.

### 6.1 Template families (assets in `design-templates/VIBN (2)/`)
| Family | Use | SMB domain |
|---|---|---|
| `vibn-ai-templates` | Shared base library (components + 4 themes) | foundation |
| `vibn-app` | Marketing / landing / lead capture + payments | most local SMB sites |
| `vibn-crm` (Cadence) | Ops: contacts, scheduling, dashboard | trades, salons, clinics |
| `vibn-marketplace` (Atlas) | Listings / booking / two-sided | directories, multi-vendor |

Themes (`minimal` / `dark` / `glass` / `editorial`) + accent come from the SMB's
brand. **Demos must look visibly local-SMB** (a plumber, a salon, a dental office),
never a generic SaaS dashboard.

### 6.2 Wired vs. to-build
- ✅ Design-kit registry, Design tab, token injection, `apps_templates_scaffold`, `get_design_template`.
- ❌ The four families ingested as registered kits (`DESIGN.md` + `tokens.css` + `SKILL.md`).
- ❌ Build recipe rewritten to "scaffold-from-kit first."
- ❌ Build entered per client from the console; SMB brand → kit selection.
- ❌ Real session streamed to a real themed preview (today: `setTimeout` animation + fake URL, answers discarded).

### 6.3 Fork, don't depend
Fork the kit into the client's repo (the READMEs say "fork it") — self-contained,
fully editable.

---

## 7. Grow — the retainer (Missinglettr)

Grow is the consultant's **recurring revenue.** Once a client's site is live, the
consultant runs their marketing as a monthly retainer.

- **Missinglettr API** = one API to post/schedule across 12 platforms (incl. Google
  Business) with shortening, analytics, webhooks. The engine of Grow.
- **My Business Business Information API (GMB)** = used specifically via OAuth 2.0 to manage verified locations, publish Google Local Business posts, and retrieve and reply to reviews (reputation management). Combined with Missinglettr, it forms the core Grow suite.
- **DataForSEO OnPage API Website Auditor** = crawlers that fetch a client's website and return full on-page diagnostics: `cms` auto-detection (Wix, WordPress, Squarespace), SSL status, mobile responsiveness, and broken link counts.
- Capabilities: AI-generated social + blog + **local SEO pages**, styled to match
  the client's design kit, scheduled via Missinglettr; reviews; analytics reporting.
- Existing blocks: `market_seo_analyze`, `generate_media`, `project_recent_errors`
  (monitoring), and `vibn-attribution-package` (UTM → first-touch attribution).
- To build: `missinglettr_*` tool wrapper, content/SEO generation, analytics loop,
  and a **client-facing monthly report** (the retainer's visible value).

---

## 8. Agency / billing layer — "Harvest for AI vibe coding" (CORE, not a fast-follow)

For the consultant ICP, **getting paid is half the value prop.** It cannot be an
afterthought. The most important primitive is the **monthly retainer** (the Grow
fee = the consultant's MRR), not just the one-off project invoice.

### 8.1 Cost sources (all metered, tagged by client/project)
| Cost type | Source |
|---|---|
| AI usage (tokens) | `lib/ai/llm-client.ts` |
| Compute / infra (apps, dev containers, DBs) | Coolify / `lib/dev-container.ts` |
| Domains | `domains_register` / `lib/opensrs.ts` |
| Market research 💲 | `market_research_run` (DataForSEO) |
| Distribution | Missinglettr (usage / subscription) |
| Media | `generate_media` |

### 8.2 Components
1. **Metering ledger** — `{ workspaceId, clientId, projectId, costType, quantity,
   rawCost, ts }`. Seeded by `lib/quotas.ts` + telemetry. Every cost-incurring tool
   emits an event.
2. **Client ↔ project mapping** — agency workspace holds many client projects.
3. **Pricing engine** — per client: **retainer** (recurring), cost-plus markup %,
   or fixed project price. Roll up raw cost → apply pricing → billable.
4. **Invoicing & retainers** — Stripe (in stack): one-off invoices **and recurring
   subscriptions** for retainers; optional client statement/portal.
5. **In-agent cost transparency** — AI surfaces estimated cost *before* spending
   (the money-gate guardrail as a platform concept); every spend is attributable.

### 8.3 Consequence
Accurate per-client cost accounting is needed regardless of when invoicing UI ships,
so **the metering ledger is launch-foundation work** — retrofitting attribution is
painful. Onboarding's "your margins" can be *illustrative* until metering is live,
provided the numbers are honestly labeled.

---

## 9. The spine — single source of truth

**`.vibncode/specs/*.md` (markdown) is the law.** Retire DB `plan_*` tools (or make
them thin markdown writers). The desktop Interactive Backlog already reads markdown;
the session runner already toggles checkboxes; it's git-tracked; it's the artifact
the user sees and edits.
- Task state = `- [ ]` / `- [x]`; all brains obey this.
- `.vibncode/` **must be committed and never removable by `git clean -fd`** (the
  earlier unattended-loop bug).
- The **design kit travels in the spine** — styling source of truth from Build → Grow.
- The spine carries the engagement: Discover writes the spec/pitch, Build consumes
  it + adds the kit, Grow reads product + kit to generate matching marketing.

---

## 10. Hardening (from the prompt/tool audit)

- **Phantom tools:** `apps_envs_set`→`apps_envs_upsert`; `apps_containers_list`→
  `apps_containers_ps`; `plan_decision_log` (Architect; doesn't exist) → remove.
- **Template-literal leak:** `route.ts` ~L306 escaped `\${activeProject.slug}` →
  un-escape so it interpolates.
- **Task-tracking civil war:** route vs shared-body vs runner disagree → markdown
  checkboxes everywhere (§9).
- **Hardcoded project specs:** route ships one project's private spec list
  (COPPA / Missinglettr / Dracula) to every user → generalize/derive.
- **Architect contradiction:** solved by mode gating (§5) + composition (§5.3).
- **Sentry snippet path** unreachable from dev container → inline / ship in scaffold.
- **`request_visual_qa` "Always"** → "for UI work."
- **Infra clarity:** add infra model + first-deploy recipe (resolve `ship` "if
  linked" + `ship` vs `apps_create { repo }`).

---

## 11. Go-to-market sequencing

| Milestone | Scope | Why |
|---|---|---|
| **0 · Foundation** | Spine = markdown everywhere; BASE+MODE shared modules; `MODE_TOOLS` gating; phantom/leak fixes; de-contaminate specs; **metering ledger** | Nothing safe until brains agree on the ledger; metering before any spend |
| **1 · Contractor onboarding (launch front door)** | "Start an AI agency" flow: opportunity → identity (Places city lookup) → presence → **free-text expertise** → dashboard. ✅ FE built against mocks | What the hero ICP evaluates first; short and contained |
| **2 · The dashboard + targeting** | Land them in the dashboard; AI extracts tools from expertise (`analyze-expertise`) → recommends local businesses to target (`targets` via Places Aggregate); claim → prospect | The "gold rush" payoff + ongoing home |
| **3 · Deliver (design-first build)** | Ingest 4 kits → kit-first build recipe → build the client's **custom tool** per client → real preview | Turns a claimed target into a delivered tool |
| **4 · Grow retainer + Missinglettr** | `missinglettr_*`, content/local-SEO, analytics loop, client monthly report | Recurring-revenue hook |
| **5 · Full billing** | Retainers + one-off invoicing (Stripe) + client statements on the metering ledger | Completes "bill for it" |

**Launch line:** Milestones 0 + 1 + 2 (onboarding → dashboard with real
recommendations) + a slice of 3 (one custom tool built end-to-end). Grow/billing
shown as the model, delivered next.

**Build status:** onboarding FE (steps 1–4) is built and compiles clean against
mock data + typed contracts. Backend endpoints + the dashboard are next (see
`VIBN_HANDOFF_TICKETS.md`).

---

## 12. The journeys (consultant serving a local SMB)

### Sofia — the new consultant (the hero path)
Sofia wants to start a side-business building custom tools for local businesses.
She signs up, selects the "Agency" option, names it, sets her city (a global Places lookup),
and declares what assets she has today. Then the
one question that matters: *"Is there a certain type of business or business problem you are passionate about?"* She types
"I want to help local dentists automate patient booking" and clicks **Open my dashboard**. She's
in. Her dashboard already shows local businesses that fit — salons, gyms, auto
shops, dentists — each flagged as stuck on disconnected SaaS and ripe for one
custom tool. She hasn't done any work and already has a target list.

### Joe's Plumbing — the client gets a custom tool (Build)
Sofia claims "plumbers," picks Joe as a client, and builds him a custom
scheduling + invoicing + reporting tool — one app around his workflow, replacing
the three half-fitting SaaS subscriptions he was paying for. Design-first from a
kit, in his colors, live in a day instead of weeks.

### The SMB owner — self-serve (secondary door)
An owner who finds Vibn directly selects the "Personal" option, enters their business name, city, and optional website, gets their business type auto-analyzed by the AI, and goes straight to building:
### The retainer — recurring revenue (Grow)
With Joe live, Sofia adds a marketing retainer. Vibn generates his Google Business
posts, a couple of local-SEO pages, and social content in his brand voice, schedules
it across platforms via Missinglettr, and produces a monthly report Sofia forwards to
Joe. Joe sees leads; Sofia bills a recurring fee.

### Getting paid (Billing)
Every cost on Joe's projects — AI, hosting, his domain, the market research, the
social scheduling — is metered and attributed. Sofia applies her markup, and Vibn
turns the build into a one-off invoice and the marketing into a recurring Stripe
subscription. She's not just delivering work; she's running a business with real margin.

### The SMB owner — self-serve (secondary door)
An owner who finds Vibn directly skips the agency setup and goes build-first:
"a booking tool for my salon" → a quick look confirm → watches it build → lands
in the chat refining it. Same engine, no markup, no dashboard.

---

## 13. Open decisions
1. ~~**Front-door fork**~~ — **DECIDED:** explicit "Agency" vs "Personal" (neutral presentation, no pre-selection bias).
2. **Targeting spend** — the dashboard's recommendations need per-city counts
   (Places Aggregate API) and may touch paid `market_research_run`. Use a
   free/cached read for the first dashboard view; gate any paid run on consent.
3. **`MODE_TOOLS`** as the single source of truth for prompt + dispatcher. (Lean: yes.)
4. **Collab write scope** path-scoped to `.vibncode/`. (Lean: yes.)
5. **Kit ingestion** — one kit per family, themes as overrides. (Lean: yes.)
6. **Pricing model first** — retainer vs cost-plus vs fixed: which to ship first.
   (Lean: retainer + simple markup.)
7. **Launch SMB vertical** — which single domain to polish end-to-end first
   (trades? salon? dental?).
8. ~~**Core brand color**~~ — **DECIDED** (see §14).

---

## 14. Design system (aligned — build everything to this)

The canonical visual spec. All net-new frontend is built to it; the cheaper model
inherits it too.

- **Foundation: warm paper-and-ink** (the differentiator). Product is light
  (`--vibn-paper` bg, `--vibn-ink` text, the warm-neutral ramp); marketing may be
  dramatically dark.
- **One brand color: matured clay-coral**, threaded through *both* marketing and
  product, used **sparingly** (primary action, active state, brand mark, progress,
  the single "next thing"). No second chromatic color.
  - Tokens in `app/globals.css`: `--vibn-coral` `oklch(0.68 0.16 35)` (actions),
    `--vibn-coral-hover`, `--vibn-coral-glow` (the brighter `0.74 0.175 35` for
    glow/focus), `--vibn-coral-soft`, `--vibn-coral-fg`.
  - Added **additively** — existing `--primary`/`--accent` not rewired blind;
    new surfaces use the coral tokens directly and get visual QA.
- **Hard rule:** Vibn chrome accent (coral) ≠ a client app's accent. The product
  chrome is coral; each *built client site* uses its own design-kit accent.
- **Two contexts:** onboarding wizard = dark + coral (existing primitives in
  `app/(onboarding)/onboarding/onboarding-primitives.tsx`); product/console =
  light paper/ink + coral.
- **Client builds** come from the 4 design-kit families (base + app/crm/
  marketplace), CSS-var themed (minimal/dark/glass/editorial), forked into the
  client repo. Demos must look visibly local-SMB.
- **Type:** product = Inter (`--font-inter`); editorial moments may use a serif
  display per the kit.
