VIBN Frontend for Coolify deployment

This commit is contained in:
2026-02-15 19:25:52 -08:00
commit 40bf8428cd
398 changed files with 76513 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
import type { ChatExtractionData } from '@/lib/ai/chat-extraction-types';
export interface ChatExtractionRecord<TData = ChatExtractionData> {
id: string;
projectId: string;
knowledgeItemId: string;
data: TData;
overallCompletion: number;
overallConfidence: number;
createdAt: FirebaseFirestore.Timestamp;
updatedAt: FirebaseFirestore.Timestamp;
}

View File

@@ -0,0 +1,43 @@
/**
* Backend Extraction Output Types
*
* These types define the structured JSON returned by the backend extractor.
* Used ONLY by backend extraction, not by chat.
*/
// Structured item returned by Gemini for each category
export interface StructuredExtractedItem {
id?: string;
sourceText: string;
label?: string;
description?: string;
confidence: number;
importance: "primary" | "supporting";
}
export interface ExtractedInsight {
id: string;
type: "problem" | "user" | "feature" | "constraint" | "opportunity" | "other";
title: string;
description: string;
sourceText: string;
sourceKnowledgeItemId: string;
importance: "primary" | "supporting";
confidence: number;
}
export interface ExtractionOutput {
// Gemini returns rich objects, not just strings
problems: StructuredExtractedItem[];
targetUsers: StructuredExtractedItem[];
features: StructuredExtractedItem[];
constraints: StructuredExtractedItem[];
opportunities: StructuredExtractedItem[];
// These can remain as arrays (empty arrays OK)
insights: ExtractedInsight[];
uncertainties: string[];
missingInformation: string[];
overallConfidence: number;
}

51
lib/types/knowledge.ts Normal file
View File

@@ -0,0 +1,51 @@
export type KnowledgeSourceType =
| 'user_chat'
| 'imported_chat'
| 'imported_ai_chat'
| 'imported_document'
| 'doc'
| 'note'
| 'spec'
| 'research'
| 'other';
export type KnowledgeSourceOrigin =
| 'chatgpt'
| 'gemini'
| 'claude'
| 'cursor'
| 'vibn'
| 'other';
export type KnowledgeImportance = 'primary' | 'supporting' | 'irrelevant';
export interface ChunkMetadata {
chunkIndex: number;
totalChunks: number;
startChar: number;
endChar: number;
tokenCount: number;
}
export interface KnowledgeSourceMeta {
origin?: KnowledgeSourceOrigin;
url?: string | null;
filename?: string | null;
createdAtOriginal?: string | null;
importance?: KnowledgeImportance;
tags?: string[];
chunkMetadata?: ChunkMetadata;
}
export interface KnowledgeItem {
id: string;
projectId: string;
sourceType: KnowledgeSourceType;
title?: string | null;
content: string;
sourceMeta?: KnowledgeSourceMeta;
createdAt: FirebaseFirestore.Timestamp;
updatedAt: FirebaseFirestore.Timestamp;
}

102
lib/types/logs.ts Normal file
View File

@@ -0,0 +1,102 @@
/**
* Logging types for monitoring and debugging
*/
import type { ChatMode } from '@/lib/ai/chat-modes';
/**
* Log entry for project-related events
*
* Stored in Firestore `project_logs` collection for monitoring,
* debugging, and prompt iteration.
*/
export interface ProjectLogEntry {
/** Firestore document ID */
id: string;
/** Project this log belongs to */
projectId: string;
/** User who triggered the event (if available) */
userId: string | null;
/** Event type for filtering */
eventType:
| 'chat_interaction'
| 'extraction'
| 'vision_generation'
| 'mvp_generation'
| 'marketing_generation'
| 'knowledge_import'
| 'batch_extraction'
| 'mode_transition'
| 'error';
/** Chat mode (if applicable) */
mode: ChatMode | null;
/** Project phase (if applicable) */
phase: string | null;
/** Which artifacts were used in this interaction */
artifactsUsed: string[];
/** Whether vector search was used */
usedVectorSearch: boolean;
/** Number of vector chunks retrieved (if applicable) */
vectorChunkCount?: number;
/** Prompt version identifier (for A/B testing) */
promptVersion: string | null;
/** Model used (e.g., 'gemini-2.0-flash-exp') */
modelUsed: string | null;
/** Whether the operation succeeded */
success: boolean;
/** Error message (if failed) */
errorMessage: string | null;
/** Additional metadata (flexible for future use) */
metadata?: Record<string, any>;
/** When this log was created */
createdAt: Date | string;
}
/**
* Input for creating a new log entry
* (id and createdAt are auto-generated)
*/
export type CreateProjectLogInput = Omit<ProjectLogEntry, 'id' | 'createdAt'>;
/**
* Filters for querying logs
*/
export interface ProjectLogFilters {
projectId?: string;
userId?: string;
eventType?: ProjectLogEntry['eventType'];
mode?: ChatMode;
phase?: string;
success?: boolean;
startDate?: Date;
endDate?: Date;
limit?: number;
}
/**
* Aggregated log stats for monitoring
*/
export interface ProjectLogStats {
totalLogs: number;
successCount: number;
errorCount: number;
byEventType: Record<string, number>;
byMode: Record<string, number>;
avgVectorChunks: number;
vectorSearchUsageRate: number;
}

17
lib/types/marketing.ts Normal file
View File

@@ -0,0 +1,17 @@
export interface HomepageMessaging {
headline: string | null;
subheadline: string | null;
bullets: string[];
}
export interface MarketingModel {
projectId: string;
icp: string[];
positioning: string | null;
homepageMessaging: HomepageMessaging;
initialChannels: string[];
launchAngles: string[];
overallConfidence: number;
}

122
lib/types/mvp-plan.ts Normal file
View File

@@ -0,0 +1,122 @@
/**
* Type definitions for AI-generated MVP Plan
* Based on the Vibn MVP Planner agent spec
*/
// Project-level
export type Project = {
id: string;
ownerUserId: string;
name: string;
createdAt: string;
updatedAt: string;
summary: string; // final summary text from planner
};
// Raw vision answers
export type VisionInput = {
projectId: string;
q1_who_and_problem: string;
q2_story: string;
q3_improvement: string;
createdAt: string;
};
// Optional work-to-date summary
export type WorkToDate = {
projectId: string;
codeSummary?: string;
githubSummary?: string;
docsLinksOrText?: string[]; // or JSON
existingAssetsNotes?: string;
createdAt: string;
};
// Trees (Journey / Touchpoints / System)
export type TreeType = "journey" | "touchpoints" | "system";
export type Tree = {
id: string;
projectId: string;
type: TreeType;
label: string;
createdAt: string;
updatedAt: string;
};
// Asset types from agent spec
export type AssetType =
| "web_page"
| "app_screen"
| "flow"
| "component"
| "email"
| "notification"
| "document"
| "social_post"
| "data_model"
| "api_endpoint"
| "service"
| "integration"
| "job"
| "infrastructure"
| "automation"
| "other";
// Each node in any tree
export type AssetNode = {
id: string;
projectId: string;
treeId: string;
parentId: string | null;
name: string;
assetType: AssetType;
mustHaveForV1: boolean;
createdAt: string;
updatedAt: string;
children?: AssetNode[]; // For nested structure
};
// Node metadata (reasoning, mapping back to vision)
export type AssetMetadata = {
assetNodeId: string;
whyItExists: string;
whichUserItServes?: string;
problemItHelpsWith?: string;
connectionToMagicMoment: string;
valueContribution?: string;
journeyStage?: string;
messagingTone?: string;
visualStyleNotes?: string;
dependencies?: string[]; // other AssetNode IDs
implementationNotes?: string;
};
// Context memory events
export type ContextEvent = {
id: string;
projectId: string;
sourceType: "chat" | "commit" | "file" | "doc" | "manual_note";
sourceId?: string; // e.g. commit hash, file path
timestamp: string;
title: string;
body: string; // raw text or JSON
};
// Full AI response from agent
export type AIAgentResponse = {
journey_tree: {
label: string;
nodes: Array<AssetNode & { asset_metadata: AssetMetadata }>;
};
touchpoints_tree: {
label: string;
nodes: Array<AssetNode & { asset_metadata: AssetMetadata }>;
};
system_tree: {
label: string;
nodes: Array<AssetNode & { asset_metadata: AssetMetadata }>;
};
summary: string;
};

12
lib/types/mvp.ts Normal file
View File

@@ -0,0 +1,12 @@
export interface MvpPlan {
projectId: string;
coreFlows: string[];
coreFeatures: string[];
supportingFeatures: string[];
outOfScope: string[];
technicalTasks: string[];
blockers: string[];
overallConfidence: number;
}

257
lib/types/phase-handoff.ts Normal file
View File

@@ -0,0 +1,257 @@
/**
* Phase Handoff Protocol
*
* Defines the structured handoff between phases in the Vibn workflow.
* Each phase (extraction, vision, mvp, marketing) produces a handoff that:
* - Declares confidence and readiness for next phase
* - Separates confirmed facts from uncertain/missing items
* - Provides questions to resolve ambiguity
* - References source evidence
*/
/**
* Phase identifier for handoffs
*/
export type PhaseType = 'collector' | 'extraction' | 'vision' | 'mvp' | 'marketing';
/**
* Structured handoff between phases
*
* Produced by each phase agent to communicate confidence, gaps, and questions
* to the next phase or back to the user.
*/
export interface PhaseHandoff {
/** Which phase produced this handoff */
phase: PhaseType;
/** Is this phase ready to hand off to the next one? */
readyForNextPhase: boolean;
/** Overall confidence score (0-1) for this phase's outputs */
confidence: number;
/** Items that are confirmed and high-confidence */
confirmed: Record<string, any>;
/** Items that are uncertain or low-confidence */
uncertain: Record<string, any>;
/** Items that are completely missing or unknown */
missing: string[];
/** Questions for the user to resolve gaps or ambiguity */
questionsForUser: string[];
/** References to source knowledge items or extractions that support this handoff */
sourceEvidence: string[];
/** Version of the handoff schema (for future evolution) */
version: string;
/** When this handoff was created */
timestamp: string;
/** Optional metadata specific to this phase */
metadata?: Record<string, any>;
}
/**
* Handoff from the Collector phase
*
* After gathering project materials, confirm readiness for extraction.
*/
export interface CollectorPhaseHandoff extends PhaseHandoff {
phase: 'collector';
/** Checklist status */
confirmed: {
/** Has user uploaded documents? */
hasDocuments?: boolean;
/** Number of documents uploaded */
documentCount?: number;
/** Has user connected GitHub repo? */
githubConnected?: boolean;
/** GitHub repo full name (e.g., 'user/repo') */
githubRepo?: string;
/** Has user installed browser extension and linked to project? */
extensionLinked?: boolean;
};
/** Items the user said "no" or "not yet" to */
uncertain: {
/** User declined or hasn't set up extension */
extensionDeclined?: boolean;
/** User doesn't have a GitHub repo yet */
noGithubYet?: boolean;
};
/** What's missing before moving to extraction */
missing: string[]; // e.g., ["documents", "github repo", "extension"]
}
/**
* Handoff from the Extraction phase
*
* After analyzing all chat_extractions, summarize what's known about the product.
*/
export interface ExtractionPhaseHandoff extends PhaseHandoff {
phase: 'extraction';
/** High-confidence product signals */
confirmed: {
/** Product one-liner (if clear) */
oneLiner?: string;
/** Core problem statement */
problemStatement?: string;
/** Target user personas */
targetUsers?: string[];
/** Confirmed features */
features?: string[];
/** Known tech stack */
techStack?: string[];
};
/** Low-confidence or conflicting signals */
uncertain: {
/** Ambiguous or conflicting features */
features?: string[];
/** Unclear business model */
businessModel?: string;
};
/** What's missing to build a solid product model */
missing: string[]; // e.g., ["target market size", "pricing strategy"]
}
/**
* Handoff from the Vision phase
*
* After creating canonicalProductModel, declare what's locked vs tentative.
*/
export interface VisionPhaseHandoff extends PhaseHandoff {
phase: 'vision';
confirmed: {
/** Core value proposition (locked) */
valueProposition?: string;
/** Primary user persona (locked) */
primaryPersona?: string;
/** Must-have features for MVP */
mustHaveFeatures?: string[];
};
uncertain: {
/** Nice-to-have features (not decided for MVP) */
niceToHaveFeatures?: string[];
/** Unclear scope decisions */
scopeDecisions?: string[];
};
missing: string[]; // e.g., ["competitive analysis", "pricing model"]
}
/**
* Handoff from the MVP phase
*
* After creating mvpPlan, declare what's ready to build vs needs clarification.
*/
export interface MVPPhaseHandoff extends PhaseHandoff {
phase: 'mvp';
confirmed: {
/** Locked feature scope */
featureScope?: string[];
/** Tech stack decisions */
techStack?: string[];
/** Build timeline estimate */
timelineEstimate?: string;
};
uncertain: {
/** Features with unclear requirements */
unclearFeatures?: string[];
/** Technical risks or unknowns */
technicalRisks?: string[];
};
missing: string[]; // e.g., ["API design", "database schema"]
}
/**
* Handoff from the Marketing phase
*
* After creating marketingPlan, declare launch readiness.
*/
export interface MarketingPhaseHandoff extends PhaseHandoff {
phase: 'marketing';
confirmed: {
/** Launch channels */
launchChannels?: string[];
/** Target launch date */
launchDate?: string;
/** Marketing messaging */
messaging?: string;
};
uncertain: {
/** Unconfirmed distribution channels */
uncertainChannels?: string[];
/** Budget constraints */
budgetConstraints?: string;
};
missing: string[]; // e.g., ["landing page copy", "email sequences"]
}
/**
* Union type for all phase handoffs
*/
export type AnyPhaseHandoff =
| CollectorPhaseHandoff
| ExtractionPhaseHandoff
| VisionPhaseHandoff
| MVPPhaseHandoff
| MarketingPhaseHandoff;
/**
* Helper to create a minimal phase handoff
*/
export function createPhaseHandoff(
phase: PhaseType,
partial: Partial<PhaseHandoff>
): PhaseHandoff {
return {
phase,
readyForNextPhase: false,
confidence: 0.5,
confirmed: {},
uncertain: {},
missing: [],
questionsForUser: [],
sourceEvidence: [],
version: '1.0',
timestamp: new Date().toISOString(),
...partial,
};
}

96
lib/types/phases.ts Normal file
View File

@@ -0,0 +1,96 @@
/**
* Phase Tracking for Vibn Projects
*
* Projects progress through phases with specific agents:
* 1. Gathering → Collect and analyze all project materials
* 2. Vision → Extract and validate Product Vision Board
* 3. Scope → Define V1 MVP features
* 4. Blueprint → Technical architecture design
* 5. Build → Implementation (future)
*/
export type ProjectPhase =
| 'gathering' // Phase 1: Collecting context and analyzing materials
| 'vision' // Phase 2: Extracting vision board
| 'scope' // Phase 3: Defining V1 features
| 'blueprint' // Phase 4: Technical design
| 'build'; // Phase 5: Implementation
export type PhaseStatus =
| 'not_started'
| 'in_progress'
| 'completed';
export interface PhaseProgress {
phase: ProjectPhase;
status: PhaseStatus;
startedAt?: FirebaseFirestore.Timestamp;
completedAt?: FirebaseFirestore.Timestamp;
insights?: GatheringInsight[]; // For gathering phase
visionBoard?: VisionBoardData; // For vision phase
scope?: ScopeData; // For scope phase
blueprint?: BlueprintData; // For blueprint phase
}
export interface GatheringInsight {
id: string;
source: string; // "Patient History Overview"
sourceType: 'document' | 'github' | 'session' | 'conversation';
sourceId: string; // Document/session ID
insight: string; // "Using evidence-based diagnostic methods"
extractedAt: FirebaseFirestore.Timestamp;
confirmed: boolean; // User validated this
confirmedAt?: FirebaseFirestore.Timestamp;
usedInVision: boolean; // Phase 2 marked this as used
category?: 'feature' | 'user' | 'problem' | 'competitor' | 'tech' | 'progress';
}
export interface VisionBoardData {
vision: string; // One-sentence vision
who: string; // Target users
need: string; // Problem they face
product: string; // Solution features
validation: string; // Go-to-market strategy
completedAt?: FirebaseFirestore.Timestamp;
approved: boolean;
approvedAt?: FirebaseFirestore.Timestamp;
}
export interface ScopeData {
v1Features: string[];
timeline: string;
priorities: {
mustHave: string[];
shouldHave: string[];
niceToHave: string[];
};
completedAt?: FirebaseFirestore.Timestamp;
}
export interface BlueprintData {
techStack: string[];
architecture: string;
database: string;
apis: string[];
completedAt?: FirebaseFirestore.Timestamp;
}
// Helper to determine which agent to use
export function getAgentForPhase(phase: ProjectPhase): string {
const agentMap: Record<ProjectPhase, string> = {
gathering: 'GATHERING_AGENT',
vision: 'VISION_AGENT',
scope: 'SCOPE_AGENT',
blueprint: 'BLUEPRINT_AGENT',
build: 'BUILD_AGENT'
};
return agentMap[phase];
}
// Helper to get next phase
export function getNextPhase(currentPhase: ProjectPhase): ProjectPhase | null {
const phaseOrder: ProjectPhase[] = ['gathering', 'vision', 'scope', 'blueprint', 'build'];
const currentIndex = phaseOrder.indexOf(currentPhase);
return currentIndex < phaseOrder.length - 1 ? phaseOrder[currentIndex + 1] : null;
}

View File

@@ -0,0 +1,37 @@
export type ProjectStage =
| 'idea'
| 'prototype'
| 'mvp_in_progress'
| 'live_beta'
| 'live_paid'
| 'unknown';
export interface CanonicalProductModel {
projectId: string;
workingTitle: string | null;
oneLiner: string | null;
problem: string | null;
targetUser: string | null;
desiredOutcome: string | null;
coreSolution: string | null;
coreFeatures: string[];
niceToHaveFeatures: string[];
marketCategory: string | null;
competitors: string[];
techStack: string[];
constraints: string[];
currentStage: ProjectStage;
shortTermGoals: string[];
longTermGoals: string[];
overallCompletion: number;
overallConfidence: number;
}

View File

@@ -0,0 +1,40 @@
import type { CanonicalProductModel, ProjectStage } from '@/lib/types/product-model';
import type { MvpPlan } from '@/lib/types/mvp';
import type { MarketingModel, HomepageMessaging } from '@/lib/types/marketing';
import type { PhaseHandoff } from '@/lib/types/phase-handoff';
export type { CanonicalProductModel, ProjectStage } from '@/lib/types/product-model';
export type { MvpPlan } from '@/lib/types/mvp';
export type { MarketingModel, HomepageMessaging } from '@/lib/types/marketing';
export type { PhaseHandoff } from '@/lib/types/phase-handoff';
export type ProjectPhase =
| 'collector'
| 'analyzed'
| 'vision_ready'
| 'mvp_ready'
| 'marketing_ready'
| 'complete';
export interface ProjectPhaseData {
canonicalProductModel?: CanonicalProductModel;
mvpPlan?: MvpPlan;
marketingPlan?: MarketingModel;
/** Phase handoffs for smart transitions */
phaseHandoffs?: Partial<Record<'collector' | 'extraction' | 'vision' | 'mvp' | 'marketing', PhaseHandoff>>;
}
export interface PhaseScore {
overallCompletion: number;
overallConfidence: number;
updatedAt: string;
}
export interface ProjectPhaseScores {
extractor?: PhaseScore & { knowledgeItemId?: string };
vision?: PhaseScore;
mvp?: PhaseScore;
marketing?: PhaseScore;
}

107
lib/types/vector-memory.ts Normal file
View File

@@ -0,0 +1,107 @@
/**
* Types for AlloyDB vector memory (knowledge_chunks table)
*/
/**
* A semantic chunk of a knowledge_item with vector embedding
*/
export interface KnowledgeChunk {
/** UUID primary key */
id: string;
/** Firestore project ID */
projectId: string;
/** Firestore knowledge_item ID */
knowledgeItemId: string;
/** Index of this chunk within the parent knowledge_item (0-based) */
chunkIndex: number;
/** Text content of this chunk */
content: string;
/** Source type (e.g., 'imported_ai_chat', 'imported_document', etc.) */
sourceType: string | null;
/** Importance classification (for filtering) */
importance: 'primary' | 'supporting' | 'irrelevant' | null;
/** When this chunk was created */
createdAt: string;
/** When this chunk was last updated */
updatedAt: string;
}
/**
* Database row shape (snake_case from PostgreSQL)
*/
export interface KnowledgeChunkRow {
id: string;
project_id: string;
knowledge_item_id: string;
chunk_index: number;
content: string;
source_type: string | null;
importance: 'primary' | 'supporting' | 'irrelevant' | null;
created_at: string;
updated_at: string;
}
/**
* Result of a vector similarity search, includes similarity score
*/
export interface KnowledgeChunkSearchResult extends KnowledgeChunk {
/** Similarity score (0-1, higher = more similar) */
similarity: number;
}
/**
* Options for vector search
*/
export interface VectorSearchOptions {
/** Maximum number of results to return */
limit?: number;
/** Minimum similarity threshold (0-1) */
minSimilarity?: number;
/** Filter by source type(s) */
sourceTypes?: string[];
/** Filter by importance level(s) */
importanceLevels?: ('primary' | 'supporting' | 'irrelevant')[];
/** Whether to include embedding in results (default: false) */
includeEmbedding?: boolean;
}
/**
* Input for creating a new knowledge chunk
*/
export interface CreateKnowledgeChunkInput {
projectId: string;
knowledgeItemId: string;
chunkIndex: number;
content: string;
embedding: number[];
sourceType?: string | null;
importance?: 'primary' | 'supporting' | 'irrelevant' | null;
}
/**
* Batch input for creating multiple chunks at once
*/
export interface BatchCreateKnowledgeChunksInput {
projectId: string;
knowledgeItemId: string;
chunks: {
chunkIndex: number;
content: string;
embedding: number[];
sourceType?: string | null;
importance?: 'primary' | 'supporting' | 'irrelevant' | null;
}[];
}