feat: complete live-verified GTM onboarding flow & places autocomplete search proxies
This commit is contained in:
@@ -15,8 +15,8 @@
|
||||
* data: {"type":"error","error":"..."}
|
||||
*/
|
||||
import { NextResponse } from "next/server";
|
||||
import { authSession } from "@/lib/auth/session-server";
|
||||
import { query } from "@/lib/db-postgres";
|
||||
import { requireWorkspacePrincipal } from "@/lib/auth/workspace-auth";
|
||||
import { query, queryOne } from "@/lib/db-postgres";
|
||||
import { callVibnChat } from "@/lib/ai/vibn-chat-model";
|
||||
import { VIBN_TOOL_DEFINITIONS, executeMcpTool } from "@/lib/ai/vibn-tools";
|
||||
import {
|
||||
@@ -303,9 +303,13 @@ Each project has a persistent \`vibn-dev\` container. Edit files via \`fs_*\` an
|
||||
**Dev servers (preview URL via \`*.preview.vibnai.com\` wildcard):**
|
||||
- \`dev_server_start { projectId, command, port: 3000 }\` is a **one-shot** call. It kills old processes on the port, checks the port is free, sets HOST=0.0.0.0 + PORT, launches your command, and returns a clickable \`previewUrl\`. Do NOT pre-flight with \`devcontainer_status\`, \`fs_list\`, \`dev_server_logs\`, or manual \`shell_exec\` kills — the function handles all of that. Just call it. The error tells you what to fix: \`PORT_BUSY\` → pick 3001–3009; \`npm: command not found\` → project needs \`npm install\` first.
|
||||
- **Port:** The primary frontend service MUST ALWAYS be bound to port \`3000\`. Do not use any other port for the user-facing UI. If you are spinning up secondary services (like an API or Storybook) alongside it, you may bind them to ports \`3001–3009\`, but port \`3000\` is reserved exclusively for the primary visual preview.
|
||||
- **Directory:** The command runs from the root \`/workspace\` directory, but your project code is inside \`/workspace/${activeProject.slug ?? "<slug>"}/\`. You MUST \`cd\` into your project folder first! Example: \`command: "cd ${activeProject.slug ?? "<slug>"} && npm run dev"\`.
|
||||
- **Directory:** The command runs from the root \`/workspace\` directory, but your project code is inside \`/workspace/\${activeProject.slug ?? "<slug>"}/\`. You MUST \`cd\` into your project folder first! Example: \`command: "cd \${activeProject.slug ?? "<slug>"} && npm run dev"\`.
|
||||
- \`dev_server_stop\` / \`dev_server_list\` / \`dev_server_logs\` — use only AFTER a failed start, and only to diagnose the error the function returned. Never on success.
|
||||
|
||||
**Verify the page actually renders:**
|
||||
- After \`dev_server_start\` returns a \`previewUrl\` AND \`healthCheck.status === 200\`, call \`browser_console { url: previewUrl }\` to capture frontend console errors.
|
||||
- **CRITICAL:** Next.js HMR overlay syntax errors do NOT crash the \`dev_server_start\` command. Even if \`dev_server_start\` returns \`Status: success\`, you MUST call \`browser_console\` to verify that there are no red syntax error overlays on the screen. If \`browser_console\` returns errors, fix them with \`fs_edit\` before declaring done. A green \`healthCheck\` plus a clean console is the real "done" signal for UI work.
|
||||
|
||||
**HMR through the proxy (apply when scaffolding):**
|
||||
- **Vite (verified working):** in \`vite.config\` set \`server: { host: '0.0.0.0', port: <3000-3009>, strictPort: true, hmr: { clientPort: 443, protocol: 'wss', host: '<the previewUrl host, no protocol>' } }\`. The \`hmr.host\` is REQUIRED — without it Vite's HMR client can guess the wrong host and the WS handshake fails through Traefik. Default localhost binding looks fine locally but breaks HMR through the proxy.
|
||||
- **Next dev:** \`next dev -p 3000 -H 0.0.0.0\` (WSS HMR works automatically through the proxy without extra config).
|
||||
@@ -339,13 +343,82 @@ For NEW repos / branches: \`gitea_repos_list\`, \`gitea_repo_get\`, \`gitea_repo
|
||||
- Compose stack weird → \`apps_repair { uuid }\` re-applies Traefik labels + port forwarding.
|
||||
- Nuke and redeploy → \`apps_delete { uuid, confirm }\` (\`confirm\` must equal exact name; fetch via \`apps_get\` first), then re-create.
|
||||
|
||||
## Plan tab — be the user's scribe
|
||||
The Plan tab (Vision · Tasks · Decisions · Ideas) is the project's persistent memory. Capture things in the moment so the user doesn't context-switch.
|
||||
- \`plan_vision_set\` PROACTIVELY when the user articulates or refines the high-level business case, elevator pitch, or primary objective of what they're building. The Objective is your north star and is separate from the technical Blueprint.
|
||||
- \`plan_document_update\` PROACTIVELY when the user asks you to write, edit, or update a specific Technical or Product Specification document inside the Blueprint. You MUST use this tool to overwrite specific sections of the Blueprint. The valid document IDs are exactly: \`stories\`, \`acceptance\`, \`success\`, \`ui_design\`, \`tech_context\`, \`data_model\`, \`file_structure\`, \`tasks\`, and \`checklist\`. Do NOT use \`fs_write\` or \`ship\` to edit markdown files when asked to update the plan—the plan lives in the database. Don't ask permission. One-liner ack ("Updated the UI Design spec"), and move on.
|
||||
- \`plan_task_add\` when you commit to multi-step work, the user says "remind me to X", or a chain ends with an obvious user follow-up (add Stripe webhook URL). One task per real next-action.
|
||||
- \`plan_task_edit\` to update a task or change its status. Put a task in "review" status when you finish it, unless the user explicitly said it is "done".
|
||||
- \`plan_idea_add\` sparingly, only for something worth remembering that isn't a task or decision.
|
||||
## Product Requirements Docs & Spec Sheets (.vibncode/specs/)
|
||||
The project's requirements, features list, specifications, and backlog checklists live in \`.vibncode/specs/\` as plain, Git-tracked Markdown files on disk. This is the single source of truth for all requirements:
|
||||
1. \`01-master-prd.md\`: Executive Summary, Vision, Mission, and Master Checklist Backlog.
|
||||
2. \`02-user-experience.md\`: UX Principles, Target Personas, and User Journeys.
|
||||
3. \`03-api-and-integrations.md\`: REST/GraphQL endpoint specs, webhook payloads, and Missinglettr API.
|
||||
4. \`04-compliance-security.md\`: COPPA Children's privacy, encryption, and Stripe billing compliance.
|
||||
5. \`05-data-model.md\`: Database schema, tables, references, and database indexes.
|
||||
6. \`06-mobile-experience.md\`: Responsive design viewports and touch targets.
|
||||
7. \`07-provider-os.md\`: Session logs, provider listing controls, and administrative workflows.
|
||||
8. \`08-ui-requirements.md\`: Style guidelines, Dracula theme values, and UI layout tokens.
|
||||
9. \`09-open-source-references.md\`: Recommended NPM dependencies and code check guidelines.
|
||||
10. \`10-growth-automation.md\`: Growth campaign trigger rules and distribution schedulers.
|
||||
|
||||
### How to Utilize and Maintain Specs:
|
||||
- **Prior Reference:** BEFORE starting any task or writing code, ALWAYS read the matching spec sheet (e.g., read \`05-data-model.md\` when setting up a database) using \`fs_read\` so you adhere exactly to the planned requirements and avoid drift.
|
||||
- **Proactive Documenting:** Write, refine, and update these spec sheets whenever you co-design, make architectural choices, or when the user clarifies requirements. Use standard file tools (\`fs_write\`, \`fs_edit\`) directly on \`.vibncode/specs/\` markdown files.
|
||||
- **Checklist Backlog Management:** Under section \`## 4. Development Checklist Backlog\` in \`01-master-prd.md\` (or relevant spec files), tasks are maintained as standard markdown checkmarks: \`- [ ] Task Description\` (open) or \`- [x]\` (done).
|
||||
- **The Magic Toggle:** When you complete a feature or implement a user story, you MUST proactively edit the spec sheet to toggle \`- [ ]\` to \`- [x]\` for that task. Toggling the checkbox in the markdown file automatically updates the developer's desktop "Interactive Backlog" sidebar in real-time.
|
||||
- **Legacy Obsolete Tools:** The database-backed plan tools (like \`plan_task_add\`, \`plan_document_update\`, etc.) are fully retired and obsolete—NEVER call them. Work exclusively with standard \`fs_\` file tools on the \`.vibncode/specs/*.md\` files!
|
||||
|
||||
### Standard Templates for AI Delegation:
|
||||
Whenever you are co-designing or tasked with creating a new feature's implementation plan or task backlog, you MUST initialize and write them according to these exact formats:
|
||||
|
||||
#### 1. Implementation Plan Format (\`.vibncode/tasks/plan-template.md\`):
|
||||
\`\`\`markdown
|
||||
# Implementation Plan: [FEATURE NAME]
|
||||
|
||||
**Branch**: \\\`[###-feature-name]\\\` | **Date**: [DATE] | **Spec**: [link]
|
||||
|
||||
**Input**: Feature specification from \\\`/specs/[###-feature-name]/spec.md\\\`
|
||||
|
||||
## 1. Summary
|
||||
*Briefly describe the primary requirement and technical approach.*
|
||||
|
||||
## 2. Technical Context
|
||||
- **Language/Version**: [e.g., Node.js v20, Python 3.11]
|
||||
- **Primary Dependencies**: [e.g., Next.js, Prisma, TailwindCSS]
|
||||
- **Storage**: [e.g., PostgreSQL, Redis]
|
||||
- **Testing**: [e.g., Jest, Vitest, Playwright]
|
||||
|
||||
## 3. Project Structure Layout
|
||||
\\\`\\\`\\\`text
|
||||
specs/[###-feature]/
|
||||
├── plan.md # This file
|
||||
├── research.md # Phase 0 output
|
||||
├── data-model.md # Phase 1 output
|
||||
└── tasks.md # Phase 2 output
|
||||
\\\`\\\`\\\`
|
||||
|
||||
## 4. Complexity & Constraints
|
||||
- [e.g. Performance goals, scalability, memory limit]
|
||||
\`\`\`
|
||||
|
||||
#### 2. Tasks Backlog Format (\`.vibncode/tasks/tasks-template.md\`):
|
||||
\`\`\`markdown
|
||||
# Tasks Backlog: [FEATURE NAME]
|
||||
|
||||
**Prerequisites**: plan.md (required), spec.md (required)
|
||||
|
||||
## 1. Format Guideline: \\\`[ID] [P?] [Story] Description\\\`
|
||||
- **[P]**: Can run in parallel (different files, no dependencies)
|
||||
- **[Story]**: Which user story this task belongs to (e.g., US1, US2)
|
||||
- Include exact file paths in task titles
|
||||
|
||||
## 2. Phase 1: Setup & Foundations (Prerequisites)
|
||||
- [ ] T001 Initialize database schemas and Prisma migrations
|
||||
- [ ] T002 Setup API routes and express middleware structures
|
||||
|
||||
## 3. Phase 2: User Story 1 - Core Implementation (Priority: P1)
|
||||
- [ ] T003 [P] [US1] Create [Model] in src/models/[file].ts
|
||||
- [ ] T004 [US1] Build /api/v1/resource endpoint in src/routes/[file].ts
|
||||
|
||||
## 4. Phase 3: Polish & Verification
|
||||
- [ ] T005 [P] Run linter and formatting checks
|
||||
- [ ] T006 Validate end-to-end user journeys
|
||||
\`\`\`
|
||||
|
||||
## Hard rules (non-negotiable)
|
||||
- **Cite the tool result, don't claim from memory.** Before stating "I edited X" or "the server is running," you must point to a tool result from THIS turn. If you can't, say "I have not yet made that change — running the tool now" and then run it. A claim without a citable tool result is a hallucination.
|
||||
@@ -394,10 +467,17 @@ function lastToolResultsHadFailure(messages: ChatMessage[], lookback = 3) {
|
||||
export async function POST(request: Request) {
|
||||
await ensureChatTables();
|
||||
|
||||
const session = await authSession();
|
||||
if (!session?.user?.email) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
const principal = await requireWorkspacePrincipal(request);
|
||||
if (principal instanceof NextResponse) return principal;
|
||||
|
||||
const userRow = await queryOne<{ data: { email?: string } }>(
|
||||
`SELECT data FROM fs_users WHERE id = $1 LIMIT 1`,
|
||||
[principal.userId],
|
||||
);
|
||||
if (!userRow?.data?.email) {
|
||||
return NextResponse.json({ error: "Unauthorized user" }, { status: 401 });
|
||||
}
|
||||
const sessionEmail = userRow.data.email;
|
||||
|
||||
let body: {
|
||||
thread_id: string;
|
||||
@@ -428,7 +508,7 @@ export async function POST(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
const email = session.user.email;
|
||||
const email = sessionEmail;
|
||||
|
||||
// Verify thread belongs to user, and capture its project scope (if any).
|
||||
const threads = await query<{ id: string; project_id: string | null }>(
|
||||
@@ -756,6 +836,7 @@ export async function POST(request: Request) {
|
||||
// This is more reliable than a prompt rule against a "do-er" model.
|
||||
function isConversational(msg: string): boolean {
|
||||
const m = msg.trim();
|
||||
if (m.length > 60) return false; // Long/detailed messages are action statements or bug reports, not simple chit-chat
|
||||
if (m.length < 3) return true; // single word / emoji
|
||||
if (m.endsWith("?")) return true; // explicit question
|
||||
// Short phrases that are status checks or greetings
|
||||
@@ -779,12 +860,10 @@ export async function POST(request: Request) {
|
||||
if (aborted) break;
|
||||
round++;
|
||||
|
||||
// On round 1, withhold tools if the message looks conversational.
|
||||
// The model must answer in text first; tools unlock from round 2.
|
||||
const toolDefs =
|
||||
mcp_token && !(round === 1 && firstMessageIsConversational)
|
||||
? VIBN_TOOL_DEFINITIONS
|
||||
: [];
|
||||
// Keep tool definitions active in the schema to avoid model confusion and
|
||||
// MALFORMED_FUNCTION_CALL gateway crashes, but let our system instructions
|
||||
// guide the model to respond in plain text for conversational inputs.
|
||||
const toolDefs = mcp_token ? VIBN_TOOL_DEFINITIONS : [];
|
||||
|
||||
// Every 8 silent rounds or 12 tool calls, gently nudge the model to surface a one-liner
|
||||
// status before continuing. This is the user's only signal of
|
||||
@@ -1049,6 +1128,25 @@ export async function POST(request: Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Last-resort guard: the model produced NO user-facing text and NO
|
||||
// tools (e.g. a "thinking" turn that returned only reasoning with an
|
||||
// empty answer part). The tool-tray recovery above doesn't cover this
|
||||
// case, so without this the user gets a silent blank bubble. Emit a
|
||||
// short deterministic fallback so every turn says *something*.
|
||||
if (
|
||||
!aborted &&
|
||||
assistantText.trim().length === 0 &&
|
||||
!anyToolsExecuted
|
||||
) {
|
||||
const fallback =
|
||||
"I didn't produce a response for that — I may have spent the turn " +
|
||||
"reasoning without writing an answer. Could you rephrase or add a " +
|
||||
"bit more detail?";
|
||||
assistantText = fallback;
|
||||
assistantTextSegments.push(fallback);
|
||||
emit({ type: "text", text: fallback });
|
||||
}
|
||||
|
||||
// Persist final assistant message. We include `textSegments`
|
||||
// alongside the legacy concatenated `content` so the client
|
||||
// can render reloaded threads with the same per-round bubble
|
||||
|
||||
Reference in New Issue
Block a user