spb/vquant Public MIT
VibeQuant — AI-powered institutional-grade financial intelligence platform.
TypeScript 84.3%
Python 11.7%
JavaScript 1.6%
CSS 1.5%
HTML 0.7%
1/*2 * =============================================================================3 * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform4 * -----------------------------------------------------------------------------5 * File: shared/schema.ts6 *7 * Author: Simon-Pierre Boucher8 * Contact: contact@spboucher.ai9 * Website: https://www.spboucher.ai10 * Demo: https://www.vquant.ai11 * License: MIT (see LICENSE)12 *13 * Copyright © 2026 Simon-Pierre Boucher. All rights reserved.14 * =============================================================================15 */1617import { sql } from "drizzle-orm";18import { pgTable, text, varchar, timestamp, integer, real, vector } from "drizzle-orm/pg-core";19import { createInsertSchema } from "drizzle-zod";20import { z } from "zod";2122// Re-export shared API types23export type { SearchResult, ClaudeMessage, ClaudeToolCall, ClaudeToolResult, ChatRequest, ChatResponse, ConversationMessage } from "./types";2425// Users table with token-based authentication26export const users = pgTable("users", {27 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),28 displayName: text("display_name").notNull(),29 token: text("token").notNull().unique(),30 createdAt: timestamp("created_at").notNull().defaultNow(),31});3233// Crawled pages table - stores web content34export const crawledPages = pgTable("crawled_pages", {35 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),36 url: text("url").notNull().unique(),37 title: text("title").notNull(),38 content: text("content").notNull(),39 snippet: text("snippet"),40 favicon: text("favicon"),41 crawledAt: timestamp("crawled_at").notNull().defaultNow(),42});4344// Embeddings table - stores vector embeddings for semantic search45export const embeddings = pgTable("embeddings", {46 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),47 pageId: varchar("page_id").notNull().unique().references(() => crawledPages.id, { onDelete: "cascade" }),48 embedding: vector("embedding", { dimensions: 3072 }),49 tokenCount: integer("token_count").notNull(),50 createdAt: timestamp("created_at").notNull().defaultNow(),51});5253// Chat messages table - stores conversation history54export const messages = pgTable("messages", {55 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),56 sessionId: varchar("session_id").notNull(),57 role: text("role").notNull(),58 content: text("content").notNull(),59 sources: text("sources").array(),60 createdAt: timestamp("created_at").notNull().defaultNow(),61});6263// Shared reports table64export const sharedReports = pgTable("shared_reports", {65 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),66 shareId: varchar("share_id").notNull().unique(),67 question: text("question").notNull(),68 answer: text("answer").notNull(),69 toolResults: text("tool_results"),70 sources: text("sources"),71 customPythonFigures: text("custom_python_figures"),72 createdAt: timestamp("created_at").notNull().defaultNow(),73});7475// Conversation sessions table76export const conversationSessions = pgTable("conversation_sessions", {77 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),78 sessionId: varchar("session_id").notNull().unique(),79 userId: varchar("user_id").references(() => users.id, { onDelete: "cascade" }),80 title: text("title").notNull(),81 messages: text("messages").notNull(),82 inputTokens: integer("input_tokens").default(0),83 outputTokens: integer("output_tokens").default(0),84 totalCost: real("total_cost").default(0),85 createdAt: timestamp("created_at").notNull().defaultNow(),86 updatedAt: timestamp("updated_at").notNull().defaultNow(),87});8889// Active users tracking90export const activeUsers = pgTable("active_users", {91 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),92 sessionId: varchar("session_id").notNull().unique(),93 userId: varchar("user_id").references(() => users.id, { onDelete: "cascade" }),94 status: text("status").notNull().default("idle"),95 currentQuery: text("current_query"),96 lastHeartbeat: timestamp("last_heartbeat").notNull().defaultNow(),97 userAgent: text("user_agent"),98 ipAddress: text("ip_address"),99 createdAt: timestamp("created_at").notNull().defaultNow(),100});101102// Analytics metrics103export const analyticsMetrics = pgTable("analytics_metrics", {104 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),105 timestamp: timestamp("timestamp").notNull().defaultNow(),106 totalRequests: integer("total_requests").default(0),107 successfulRequests: integer("successful_requests").default(0),108 failedRequests: integer("failed_requests").default(0),109 activeUsers: integer("active_users").default(0),110 uniqueVisitors: integer("unique_visitors").default(0),111 averageResponseTime: real("average_response_time").default(0),112 peakResponseTime: real("peak_response_time").default(0),113 tokensGenerated: integer("tokens_generated").default(0),114 estimatedCost: real("estimated_cost").default(0),115 toolCallsCount: integer("tool_calls_count").default(0),116 pythonExecutions: integer("python_executions").default(0),117 searchQueries: integer("search_queries").default(0),118 errorCount: integer("error_count").default(0),119 errorRate: real("error_rate").default(0),120 periodType: text("period_type").notNull().default("minute"),121});122123// Request logs124export const requestLogs = pgTable("request_logs", {125 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),126 sessionId: varchar("session_id").notNull(),127 userId: varchar("user_id").references(() => users.id, { onDelete: "cascade" }),128 query: text("query").notNull(),129 responseTime: real("response_time"),130 inputTokens: integer("input_tokens").default(0),131 outputTokens: integer("output_tokens").default(0),132 totalCost: real("total_cost").default(0),133 toolsCalled: text("tools_called"),134 status: text("status").notNull(),135 errorMessage: text("error_message"),136 timestamp: timestamp("timestamp").notNull().defaultNow(),137});138139// Zod schemas for validation140export const insertUserSchema = createInsertSchema(users).omit({ id: true, createdAt: true });141export const insertCrawledPageSchema = createInsertSchema(crawledPages).omit({ id: true, crawledAt: true });142export const insertEmbeddingSchema = createInsertSchema(embeddings).omit({ id: true, createdAt: true });143export const insertMessageSchema = createInsertSchema(messages).omit({ id: true, createdAt: true });144export const insertSharedReportSchema = createInsertSchema(sharedReports).omit({ id: true, createdAt: true });145export const insertConversationSessionSchema = createInsertSchema(conversationSessions).omit({ id: true, createdAt: true, updatedAt: true });146export const insertActiveUserSchema = createInsertSchema(activeUsers).omit({ id: true, createdAt: true });147export const insertAnalyticsMetricSchema = createInsertSchema(analyticsMetrics).omit({ id: true, timestamp: true });148export const insertRequestLogSchema = createInsertSchema(requestLogs).omit({ id: true, timestamp: true });149150// TypeScript types151export type User = typeof users.$inferSelect;152export type InsertUser = z.infer<typeof insertUserSchema>;153154export type CrawledPage = typeof crawledPages.$inferSelect;155export type InsertCrawledPage = z.infer<typeof insertCrawledPageSchema>;156157export type Embedding = typeof embeddings.$inferSelect;158export type InsertEmbedding = z.infer<typeof insertEmbeddingSchema>;159160export type Message = typeof messages.$inferSelect;161export type InsertMessage = z.infer<typeof insertMessageSchema>;162163export type SharedReport = typeof sharedReports.$inferSelect;164export type InsertSharedReport = z.infer<typeof insertSharedReportSchema>;165166export type ConversationSession = typeof conversationSessions.$inferSelect;167export type InsertConversationSession = z.infer<typeof insertConversationSessionSchema>;168169export type ActiveUser = typeof activeUsers.$inferSelect;170export type InsertActiveUser = z.infer<typeof insertActiveUserSchema>;171172export type AnalyticsMetric = typeof analyticsMetrics.$inferSelect;173export type InsertAnalyticsMetric = z.infer<typeof insertAnalyticsMetricSchema>;174175export type RequestLog = typeof requestLogs.$inferSelect;176export type InsertRequestLog = z.infer<typeof insertRequestLogSchema>;177