This repository has been archived on 2026-06-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
master-ai/VIBN_HANDOFF_TICKETS.md

15 KiB
Raw Permalink Blame History

Vibn — Backend Handoff Tickets (for Sonnet)

Companion to VIBN_PRODUCT_BLUEPRINT.md. These are the backend / plumbing tasks to hand to a cheaper model (latest Sonnet, standard reasoning; use high reasoning only on T2/T3/T6, which Opus should also review).

Rule of the seam: the frontend is already built against typed contracts + mock data. Implement endpoints to the exact shapes; do not change the contract types or the frontend components. When an endpoint is live, swap the mock call for a fetch — that's the only frontend edit allowed.

Disjoint write scope: these tickets touch app/api/**, lib/**, the agent runner, and the prompt files — NOT the onboarding .tsx UI (except the one documented mock→fetch swap in T11).


Milestone 0 — Foundation (do first; nothing is safe until these land)

T1 — One task ledger: markdown everywhere · ⚠️ Opus review

Problem: three prompts disagree on task tracking (route.ts says plan_* are retired; the agent-runner coder.ts says call plan_task_complete; the session runner toggles markdown). This causes the "loops on task 1" bug. Do: make .vibncode/specs/*.md markdown checkboxes (- [ ] / - [x]) the single source of truth in all three. Retire the DB plan_* tools (or make them thin markdown writers). Ensure .vibncode/ is committed and never removed by git clean -fd. Files: vibn-frontend/app/api/chat/route.ts, vibn-agent-runner/src/prompts/coder.ts, vibn-agent-runner/src/agent-session-runner.ts. Accept: a delegated run that completes a task flips the markdown checkbox AND the desktop Interactive Backlog reflects it; no prompt references plan_*.

T2 — Extract BASE + MODE prompt modules · ⚠️ Opus review

Do: factor the shared prompt into BASE (identity, voice, spine/task-ledger contract, infra model, hard rules, untrusted-content rule, project state) + three MODE deltas (Collab / Build / Grow). Both route.ts and the agent-runner import the same modules. See blueprint §5.3. Accept: one source of truth for BASE/MODE; route + runner import it; Architect ("Collab") no longer contains the code/deploy body.

T3 — MODE_TOOLS map + enforced gating · ⚠️ Opus review

Do: one MODE_TOOLS: Record<"collab"|"build"|"grow", ToolName[]> (blueprint §5.2). Filter exposed tool schemas per mode in the prompt builder AND reject out-of-mode calls in the dispatcher. Apply in route + runner. Accept: Collab cannot call ship/shell_exec/apps_create (not in schema + dispatcher rejects); market_research_run only callable in Collab; tool count per turn drops to ~2030.

T4 — Phantom-tool + template-literal fixes (mechanical)

Do: in route.ts: apps_envs_setapps_envs_upsert; apps_containers_listapps_containers_ps; remove plan_decision_log (doesn't exist); un-escape the \${activeProject.slug} at ~L306 so it interpolates. Accept: every tool name in prose exists in the registry; no literal ${activeProject.slug} in the compiled prompt.

T5 — De-contaminate hardcoded specs

Do: the 10-file spec manifest in route.ts (~L346357, COPPA/Missinglettr/ Dracula) ships to every user. Derive it from the active project, or replace with a generic "read whatever exists in .vibncode/specs/." Accept: a fresh project's prompt contains no GetAcquired-specific spec names.

T6 — Metering ledger foundation · ⚠️ Opus review

Do: a per-event usage ledger { workspaceId, clientId, projectId, costType, quantity, rawCost, ts } (blueprint §8.2). Emit an event from every cost-incurring tool (AI tokens, deploys, domains, market research, media, Missinglettr). Build on lib/quotas.ts. Accept: every billable action writes a ledger row tagged by project; a query can total raw cost per client per period. (Invoicing UI is T16 — not now.)


Milestone 1 — Onboarding + dashboard endpoints (implement to the contracts)

Contracts: vibn-frontend/app/(onboarding)/onboarding/onboarding-agency-types.ts. Mock to replace: …/onboarding-agency-mock.ts. Flow reminder: onboarding ends at ideal customer → dashboard; the targeting recommendation lives in the dashboard (T8), not onboarding. Steps are: Identity (T7b) → Presence → Ideal Customer (T7) → POST (T9) → Dashboard (T10).

T7 — POST /api/agency/analyze-expertise { text }

Returns: { tools: string[] }. Do: an LLM call that maps the consultant's free-text ideal customer / problem description to canonical tool-category labels that match smb_to_software_mapping (so they join in T8). The FE mock is extractTools() (keyword stub) — replace with the LLM, keep the output shape. Accept: "I want to help dentists automate booking" -> ["Appointment Scheduling Software"] (or better); labels exist in the mapping. Matches them with potential customers in their area, and drives brand awareness.

T7b — GET /api/agency/cities?q= (city autocomplete)

Returns: CityRef[] (global). Do: proxy Places API (New) Autocomplete (places:autocomplete, restrict to localities/cities) for predictions, then Place Details (New) to resolve each into CityRef (name = locality, region = admin area level 1 short name, country + countryCode = ISO alpha-2, lat/lng = location). Key stays server-side. The frontend CityLookup already calls this and falls back to the seed list when absent. Accept: typing "Vic" returns Victoria BC and global matches (not a fixed list).

T7c — POST /api/agency/places/search { name: string, city: CityRef }

Returns: PlaceMatch[] (top 3 matching businesses). Do (Three-Stage AI Category Resolver):

  1. Stage 1: Google Places Lookup (Physical Context):
    • Query Places API (New) Text Search using GOOGLE_PLACES_API_KEY with ${name} ${city.name} ${city.region} to find matching business entities.
    • Extract: id, displayName, formattedAddress, primaryType (e.g., "health"), and types.
  2. Stage 2: DataForSEO Website Lookup (Digital Context):
    • If the business has a website, query DataForSEO's OnPage/Database APIs (or scrape the URL, falls back to raw query if offline) to retrieve the website's meta-title, description, and domain tags.
  3. Stage 3: AI Assessment (The Reasoning Bridge):
    • Feed both Stage 1 (Google Places categories/types) and Stage 2 (website title, description, domain tags) into a Gemini LLM call (gemini-3.5-flash).
    • Prompt:
      Google Places details:
      - Name: {{displayName}}
      - Primary Type: {{primaryType}}
      - Types: {{types}}
      
      Website Details:
      - Title: {{scrapedTitle}}
      - Description: {{scrapedDescription}}
      
      Based on the above, select the single most relevant category ID (gcid) for this business from our canonical mapping list. Return only the raw GCID string (e.g., "gcid:dental_hygienist" or "gcid:plumber").
      
    • Map the returned GCID to one of our 5 baseline categories: "service" (trades/FSM), "appointments" (scheduling), "food" (dining), "retail" (pos/shop), or "events".
    • Retrieve the matched GCID's exact "softwareNeeds" list from smb_to_software_mapping_final.json and return it in presetTools. Accept: looking up "Wheely Clean" (which Google labels "health") correctly maps to "gcid:dental_hygienist" via AI assessment (by reading their teeth whitening website title), loading their actual dental scheduling, billing, and EHR/EMR custom blocks on Step 2! Shows loading spinner during execution.

T8 — POST /api/agency/targets { city: CityRef, tools: string[] } (powers the dashboard)

Returns: TerritoryOpportunity[], sorted by opportunityScore desc. Do: intersect tools with each SMB type's softwareNeeds (smb_to_software_mapping_final.json) to pick candidate niches; for each, get business counts via the Places Aggregate API (:computeInsights, INSIGHT_COUNT) filtered by the niche's Places type (mapped from gcid) within the city's area (circle around city.lat/lng). opportunityScore = demand × weak/no-software gap × low Vibn saturation, biased by tool-fit. Treat "Reporting / Dashboard Software" as a universal need. Mirror mockTargets; set matchedTools per result. Accept: real per-city counts for any city worldwide; vibnClaimedCount from our DB; honest numbers only (no fabricated scarcity — blueprint honesty guardrail).

T9 — POST /api/agency AgencyOnboardingResult { profile, expertise, tools }

Returns: { workspaceSlug }. Do (DB Storage Spec):

  1. Workspace row: Insert a new row into fs_workspaces.
    • name = profile.name
    • slug = derived slug from profile.name (idempotently deduplicated)
    • Store all metadata inside a structured agency_onboarding JSONB field in fs_workspaces.data (or related column):
      {
        "city": {
          "id": "victoria-bc",
          "name": "Victoria",
          "region": "BC",
          "country": "Canada",
          "countryCode": "CA",
          "lat": 48.4284,
          "lng": -123.3656
        },
        "hasWebsite": true,
        "websiteUrl": "yoursite.com",
        "hasSocials": true,
        "hasBlog": false,
        "hasCustomDomain": false,
        "hasExistingClients": false,
        "expertise": "I want to help dentists automate booking",
        "tools": ["Appointment Scheduling Software"]
      }
      
  2. Workspace member row: Link the signed-in NextAuth user (userId) as the 'owner' of this workspace in fs_workspace_members.
  3. Provisioning: Trigger the standard workspace provision pipeline (Gitea org, Coolify project boundary via lib/workspaces.ts) asynchronously so the tenant stands up. Accept: round-trips the posted result; a new row is created in fs_workspaces and fs_workspace_members; metadata is saved perfectly in JSONB; and the workspace slug is returned. (No pitch, no claimed territory — those were removed from onboarding.)

T10 — The dashboard (the screen they land on) · ⚠️ Opus may build

Do: the agency dashboard at /[workspace] (light paper/ink theme). On load, call T7 (analyze-expertise, or use stored tools) + T8 (targets for their city) and render the recommended local businesses to target (the gold-rush list with businesses / weak-software / claimed + matched-tools chips). Plus clients/ prospects, projects, retainer MRR. Claiming a target creates a prospect. Accept: lands from onboarding seeded with their ideal-customer description; shows real recommendations; claim → prospect. (FE craft — likely an Opus task; reuses extractTools + mockTargets until T7/T8 are live.)

T11 — Wire onboarding + dashboard to the endpoints

Do: CityLookup already calls GET /api/agency/cities (T7b) with a seed fallback — just stand up the route. Implement finishAgency in page.tsx to POST T9 and route to /[workspace]. In the dashboard, swap extractTools/ mockTargets for T7/T8. No styling changes to onboarding. Accept: the flow runs end-to-end on real data; onboarding behavior unchanged.

T12 — Preserve homepage intent through auth

Do: if the homepage hero captures input, persist it across Google OAuth (localStorage/draft, like vibn:firstName) so onboarding resumes seeded. Accept: typing on the homepage → sign in → onboarding has the value.


Milestone 2 — Design-first delivery (the custom tool)

T13 — Ingest the 4 design-kit families

Do: register vibn-ai-templates, vibn-app, vibn-crm, vibn-marketplace (in design-templates/VIBN (2)/) into the design-kit registry: one kit per family, themes as overrides; add DESIGN.md + tokens.css (+ SKILL.md) per the existing lib/scaffold/open-design/design-systems/<id>/ structure. Accept: get_design_template returns each; they appear on the Design tab.

T14 — Build recipe: scaffold-from-kit first

Do: rewrite the Build mode recipe so building a client's custom tool starts from a kit (fork into the client repo) + token reskin, instead of create-next-app. The tool is scoped from the consultant's expertise + the client's softwareNeeds; SMB domain → family; client brand → accent. Accept: a build starts from a polished themed template, not an empty Next app.

T17 — Onboarding hardening note (low priority)

Do: page.tsx has pre-existing unused imports (useState/useEffect/ useMemo on line 3) flagged as warnings — not from the agency work. Clean up if touching the file. Accept: no behavior change.


Milestone 3+ — Grow & billing (later)

T15 — missinglettr_* tool wrapper

Do: wrap the Missinglettr API (workspaces.create, posts.create, analytics). Grow mode only. Accept: can schedule a multi-platform post; metered (T6).

T16 — Stripe retainers + invoicing

Do: on the metering ledger, roll up cost → apply pricing (retainer / cost-plus / fixed) → Stripe one-off invoice + recurring subscription for retainers. Accept: an agency can invoice a client and start a monthly retainer.

T18 — Google Business Profile (GMB) OAuth & Token storage

Do: add https://www.googleapis.com/auth/business.manage to the NextAuth Google Provider config. Upon user sign-in, save the authorized OAuth access_token and refresh_token in fs_users.data. On the backend, write a helper to list GMB locations for the authorized user and support posting Google Local Business posts. This is the core engine for automated GBP posting and review management in Grow mode. Accept: signing in with Google requests the GMB permission; tokens are securely saved in fs_users.data and are queryable by the server.

T19 — DataForSEO OnPage API Website Auditor

Do: implement a backend helper to post and retrieve data from DataForSEO's OnPage API (/v3/on_page/task_post -> /v3/on_page/summary). Extract domain-wide metrics: domain_info.cms (to auto-detect what builder they are renting), domain_info.ssl_info, page_metrics.broken_links, and favicon availability. ⚠️ Hard constraint: DataForSEO's OnPage crawler strictly requires the target URL to include the protocol (e.g., must be "https://allardcontractorsltd.com" or "http://...", NOT a bare domain). Ensure the server-side payload prepends "https://" automatically when creating the crawler task. Expose this audit dataset to the dashboard so consultants can auto-generate SEO health audits for their prospects. Accept: posting a scan request triggers the DataForSEO crawl; returns unified CMS, SSL, and link metrics; tags them to the client's project row.


Notes for the implementer

  • Don't touch the onboarding .tsx files except T11's documented swap.
  • Keep onboarding-agency-types.ts as the contract; if a shape must change, change it there and flag it (the UI depends on it).
  • Honesty guardrail (T8/T9): never show fabricated market/scarcity numbers.
  • Flag T1/T2/T3/T6 for an Opus review pass before merge.