import { pgTable, serial, varchar, text, boolean, integer, timestamp, jsonb, } from 'drizzle-orm/pg-core'; import { relations } from 'drizzle-orm'; // ============================================ // 用户表 // ============================================ export const users = pgTable('users', { id: serial('id').primaryKey(), // 用户唯一标识 userId: varchar('user_id', { length: 64 }).notNull().unique(), // 基本信息 email: varchar('email', { length: 255 }).notNull().unique(), password: varchar('password', { length: 255 }).notNull(), nickname: varchar('nickname', { length: 64 }).notNull(), avatar: varchar('avatar', { length: 512 }), // 套餐和状态 plan: varchar('plan', { length: 20 }).default('free'), // free, pro, enterprise status: varchar('status', { length: 20 }).default('active'), // active, inactive, banned emailVerified: boolean('email_verified').default(false), // 登录信息 lastLoginAt: timestamp('last_login_at', { withTimezone: true }), // 时间戳 createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(), }); // ============================================ // 验证码表 // ============================================ export const verificationCodes = pgTable('verification_codes', { id: serial('id').primaryKey(), // 邮箱 email: varchar('email', { length: 255 }).notNull(), // 验证码 code: varchar('code', { length: 6 }).notNull(), // 类型: register(注册), login(登录), reset(重置密码) type: varchar('type', { length: 20 }).notNull(), // 过期时间 expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(), // 是否已使用 used: boolean('used').default(false), // 创建时间 createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(), }); // ============================================ // 用户设置表 // ============================================ export const userSettings = pgTable('user_settings', { id: serial('id').primaryKey(), // 关联用户 userId: varchar('user_id', { length: 64 }).unique(), // CCH 配置 cchUrl: varchar('cch_url', { length: 512 }).notNull().default('http://localhost:13500'), cchApiKey: varchar('cch_api_key', { length: 512 }), cchApiKeyConfigured: boolean('cch_api_key_configured').default(false), // 默认设置 defaultModel: varchar('default_model', { length: 64 }).default('claude-sonnet-4-20250514'), defaultTools: jsonb('default_tools').$type().default(['web_search', 'code_execution', 'web_fetch']), // AI 行为设置 systemPrompt: text('system_prompt'), // 系统提示词 temperature: varchar('temperature', { length: 10 }).default('0.7'), // 温度参数 (0-1) // 偏好设置 theme: varchar('theme', { length: 20 }).default('light'), language: varchar('language', { length: 10 }).default('zh-CN'), fontSize: integer('font_size').default(15), // 全局字体大小 (12-20) enableThinking: boolean('enable_thinking').default(false), saveChatHistory: boolean('save_chat_history').default(true), // 时间戳 createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(), }); // ============================================ // 对话表 // ============================================ export const conversations = pgTable('conversations', { id: serial('id').primaryKey(), // 对话唯一标识 conversationId: varchar('conversation_id', { length: 64 }).notNull().unique(), // 关联用户 userId: varchar('user_id', { length: 64 }), // 对话信息 title: varchar('title', { length: 255 }).notNull().default('新对话'), summary: text('summary'), // 模型和工具配置 model: varchar('model', { length: 64 }).notNull(), tools: jsonb('tools').$type().default([]), enableThinking: boolean('enable_thinking').default(false), // AI 行为设置(对话级别,可覆盖全局设置) systemPrompt: text('system_prompt'), // 对话专属系统提示词 temperature: varchar('temperature', { length: 10 }), // 对话专属温度参数 // 统计信息 messageCount: integer('message_count').default(0), totalTokens: integer('total_tokens').default(0), // 状态 isArchived: boolean('is_archived').default(false), isPinned: boolean('is_pinned').default(false), // 时间戳 createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(), lastMessageAt: timestamp('last_message_at', { withTimezone: true }).defaultNow(), }); // ============================================ // 消息表 // ============================================ export const messages = pgTable('messages', { id: serial('id').primaryKey(), // 消息唯一标识 messageId: varchar('message_id', { length: 64 }).notNull().unique(), // 关联对话 conversationId: varchar('conversation_id', { length: 64 }).notNull(), // 消息内容 role: varchar('role', { length: 20 }).notNull(), // user, assistant, system content: text('content').notNull(), // 思考内容 thinkingContent: text('thinking_content'), thinkingCollapsed: boolean('thinking_collapsed').default(true), // 工具调用记录 toolCalls: jsonb('tool_calls').$type(), toolResults: jsonb('tool_results').$type(), // 代码执行产生的图片(Base64 编码数组) images: jsonb('images').$type(), // 用户上传的图片(Base64 编码数组) uploadedImages: jsonb('uploaded_images').$type(), // 用户上传的文档 uploadedDocuments: jsonb('uploaded_documents').$type(), // Token 统计 inputTokens: integer('input_tokens').default(0), outputTokens: integer('output_tokens').default(0), // 状态 status: varchar('status', { length: 20 }).default('completed'), // pending, streaming, completed, error errorMessage: text('error_message'), // 用户反馈 feedback: varchar('feedback', { length: 10 }), // thumbs_up, thumbs_down // 时间戳 createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(), }); // ============================================ // 工具表 // ============================================ export const tools = pgTable('tools', { id: serial('id').primaryKey(), // 工具唯一标识 toolId: varchar('tool_id', { length: 64 }).notNull().unique(), // 工具信息 name: varchar('name', { length: 64 }).notNull(), displayName: varchar('display_name', { length: 128 }).notNull(), description: text('description'), icon: varchar('icon', { length: 64 }), // Claude Tool Schema inputSchema: jsonb('input_schema').notNull(), // 配置 isEnabled: boolean('is_enabled').default(true), isDefault: boolean('is_default').default(false), sortOrder: integer('sort_order').default(0), // 时间戳 createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(), }); // ============================================ // 模型表 // ============================================ export const models = pgTable('models', { id: serial('id').primaryKey(), // 模型唯一标识 modelId: varchar('model_id', { length: 128 }).notNull().unique(), // 模型信息 name: varchar('name', { length: 64 }).notNull(), displayName: varchar('display_name', { length: 128 }).notNull(), description: text('description'), // 模型类型:claude | codex modelType: varchar('model_type', { length: 20 }).notNull().default('claude'), // 模型特性 supportsTools: boolean('supports_tools').default(true), supportsThinking: boolean('supports_thinking').default(true), supportsVision: boolean('supports_vision').default(false), maxTokens: integer('max_tokens').default(8192), contextWindow: integer('context_window').default(200000), // 配置 isEnabled: boolean('is_enabled').default(true), isDefault: boolean('is_default').default(false), sortOrder: integer('sort_order').default(0), // 时间戳 createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(), }); // ============================================ // 关系定义 // ============================================ export const usersRelations = relations(users, ({ many, one }) => ({ conversations: many(conversations), settings: one(userSettings, { fields: [users.userId], references: [userSettings.userId], }), })); export const userSettingsRelations = relations(userSettings, ({ one }) => ({ user: one(users, { fields: [userSettings.userId], references: [users.userId], }), })); export const conversationsRelations = relations(conversations, ({ many, one }) => ({ messages: many(messages), user: one(users, { fields: [conversations.userId], references: [users.userId], }), })); export const messagesRelations = relations(messages, ({ one }) => ({ conversation: one(conversations, { fields: [messages.conversationId], references: [conversations.conversationId], }), })); // ============================================ // 类型定义 // ============================================ export interface ToolCall { id: string; name: string; input: Record; } export interface ToolResult { toolUseId: string; content: string; isError?: boolean; } // 上传的文档数据(用于持久化存储) export interface UploadedDocumentData { name: string; size: number; type: string; content: string; } // 导出类型 export type User = typeof users.$inferSelect; export type NewUser = typeof users.$inferInsert; export type VerificationCode = typeof verificationCodes.$inferSelect; export type NewVerificationCode = typeof verificationCodes.$inferInsert; export type UserSettings = typeof userSettings.$inferSelect; export type NewUserSettings = typeof userSettings.$inferInsert; export type Conversation = typeof conversations.$inferSelect; export type NewConversation = typeof conversations.$inferInsert; export type Message = typeof messages.$inferSelect; export type NewMessage = typeof messages.$inferInsert; export type Tool = typeof tools.$inferSelect; export type NewTool = typeof tools.$inferInsert; export type Model = typeof models.$inferSelect; export type NewModel = typeof models.$inferInsert;