// Package models 定义所有 GORM 数据模型(对应 SQLite 数据表)。 // // 本文件包含两个存在于 settings.db 中的模型: // - AppSetting: 简单的键值配置表,用于存 AI 参数和用户偏好。 // - Library: 知识库注册表,每行指向一个独立的 .db 文件。 package models import "time" // AppSetting 是存储于 settings.db 的全局键值对配置表。 // // 选择键值对(而非定义强类型结构体)的原因: // 1. 配置项未来可能扩展(新增 AI 提供商、新增偏好项),KV 表无需迁移。 // 2. 加密后的 API Key(二进制)和普通字符串值可以统一存储。 // 3. UPSERT(INSERT ... ON CONFLICT DO UPDATE)操作极为简单。 // // 典型键名: // - "ai_provider" / "base_url" / "model" // - "api_key_encrypted"(AES-256-GCM 密文 base64) // - "system_prompt" / "max_tokens" / "use_public_key" // - "active_library" (上次使用的知识库名,用于启动时恢复) type AppSetting struct { // Key 使用 primaryKey,保证同名键全局唯一,UPSERT 可直接依赖此约束。 Key string `gorm:"primaryKey;size:100" json:"key"` // Value 使用 text 而非 varchar,支持存储较长内容(如系统提示词)。 Value string `gorm:"type:text" json:"value"` } // TableName 显式声明表名,避免 GORM 的复数化规则(AppSettings → app_settings) // 在不同 GORM 版本间产生歧义。 func (AppSetting) TableName() string { return "app_settings" } // Library 是知识库注册表,存储于 settings.db。 // // 每条 Library 记录描述一个独立的知识库 .db 文件。 // // # 物理隔离设计 // // 传统多租户方案在同一张表里用 user_id 或 namespace 做逻辑隔离, // 一旦查询遗漏 WHERE 条件就会产生跨库数据泄露。 // 本项目改用"一个知识库 = 一个独立 .db 文件"的物理隔离方案: // - 数据泄露风险从根本上消除; // - 用户可以在 Finder 中直接拷贝/分享单个 .db 文件; // - 切换知识库等同于更换数据库连接,极为清晰。 type Library struct { ID uint `gorm:"primaryKey;autoIncrement" json:"id"` // Name 添加 uniqueIndex 防止重复注册同名知识库。 Name string `gorm:"uniqueIndex;size:100;not null" json:"name"` Description string `gorm:"size:255" json:"description"` // FilePath 存储 .db 文件的绝对路径,程序通过此路径打开对应 SQLite 连接。 FilePath string `gorm:"size:1024;not null" json:"file_path"` // EntryCount 使用 gorm:"-" 标签,表示此字段不映射到数据库列, // 而是在 service 层查询后动态填充,供前端展示。 EntryCount int `gorm:"-" json:"entry_count"` CreatedAt time.Time `json:"created_at"` } func (Library) TableName() string { return "libraries" }