feat: 添加注释
This commit is contained in:
@@ -1,16 +1,48 @@
|
||||
// Package models 定义知识库 .db 文件中的核心业务表。
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// Entry is a single Q&A row in a knowledge library .db file.
|
||||
// Entry 是知识库中的一条问答记录,存储于各知识库 .db 文件的 entries 表。
|
||||
//
|
||||
// # 设计说明
|
||||
//
|
||||
// Entry 不包含 user_id 字段——这是本架构与传统多用户方案的核心区别。
|
||||
// 数据隔离通过"切换不同 .db 文件"实现(物理隔离),而非逻辑隔离。
|
||||
// 这意味着:
|
||||
// - 每个知识库文件就是一个完全独立的数据源;
|
||||
// - 任何针对 Entry 的查询都自动限定在当前活跃的知识库内;
|
||||
// - 不存在因遗漏 WHERE user_id = ? 而导致跨库数据泄露的风险。
|
||||
//
|
||||
// # 字段说明
|
||||
//
|
||||
// Keyword 是搜索的主要匹配目标(经过 INDEX 加速),
|
||||
// Question 存放完整的问题文本(兼做二级匹配),
|
||||
// Answer 存放答案全文(供 AI 润色时作为原始素材)。
|
||||
type Entry struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
Keyword string `gorm:"index;size:255;not null" json:"keyword"`
|
||||
Question string `gorm:"type:text;not null" json:"question"`
|
||||
Answer string `gorm:"type:text;not null" json:"answer"`
|
||||
Category string `gorm:"size:100;default:'通用'" json:"category"`
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
|
||||
// Keyword 是精简的检索关键词,例如 "退款政策"、"浇水频率"。
|
||||
// 添加了 GORM 索引(B-Tree),使 LIKE '%keyword%' 查询更快。
|
||||
// size:255 对应 TEXT NOT NULL,防止存入过长字符串或空值。
|
||||
Keyword string `gorm:"index;size:255;not null" json:"keyword"`
|
||||
|
||||
// Question 是完整的问题描述,作为搜索的二级匹配字段。
|
||||
// type:text 映射到 SQLite TEXT 类型,无长度限制。
|
||||
Question string `gorm:"type:text;not null" json:"question"`
|
||||
|
||||
// Answer 是对应答案全文,也是传给 AI 做"润色"的原始素材。
|
||||
Answer string `gorm:"type:text;not null" json:"answer"`
|
||||
|
||||
// Category 用于前端分类展示和颜色区分(例如 "浇水"、"病虫害")。
|
||||
// default:'通用' 保证没填分类时有默认值,避免前端渲染空标签。
|
||||
Category string `gorm:"size:100;default:'通用'" json:"category"`
|
||||
|
||||
// GORM 约定字段:自动维护创建时间和最后更新时间。
|
||||
// UpdatedAt 用于在搜索无结果时排序返回"最近更新"的热门问答。
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// TableName 显式指定表名为 "entries"(避免 GORM 默认复数化为 "entries" / "entris")。
|
||||
func (Entry) TableName() string { return "entries" }
|
||||
|
||||
+44
-11
@@ -1,25 +1,58 @@
|
||||
// Package models 定义所有 GORM 数据模型(对应 SQLite 数据表)。
|
||||
//
|
||||
// 本文件包含两个存在于 settings.db 中的模型:
|
||||
// - AppSetting: 简单的键值配置表,用于存 AI 参数和用户偏好。
|
||||
// - Library: 知识库注册表,每行指向一个独立的 .db 文件。
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// AppSetting is a key-value store for global application settings
|
||||
// (AI provider, endpoint, API key, etc.) in settings.db.
|
||||
// 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 string `gorm:"primaryKey;size:100" json:"key"`
|
||||
// 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 represents a registered knowledge library in settings.db.
|
||||
// Each library is a separate SQLite file.
|
||||
// Library 是知识库注册表,存储于 settings.db。
|
||||
//
|
||||
// 每条 Library 记录描述一个独立的知识库 .db 文件。
|
||||
//
|
||||
// # 物理隔离设计
|
||||
//
|
||||
// 传统多租户方案在同一张表里用 user_id 或 namespace 做逻辑隔离,
|
||||
// 一旦查询遗漏 WHERE 条件就会产生跨库数据泄露。
|
||||
// 本项目改用"一个知识库 = 一个独立 .db 文件"的物理隔离方案:
|
||||
// - 数据泄露风险从根本上消除;
|
||||
// - 用户可以在 Finder 中直接拷贝/分享单个 .db 文件;
|
||||
// - 切换知识库等同于更换数据库连接,极为清晰。
|
||||
type Library struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
Name string `gorm:"uniqueIndex;size:100;not null" json:"name"`
|
||||
Description string `gorm:"size:255" json:"description"`
|
||||
FilePath string `gorm:"size:1024;not null" json:"file_path"`
|
||||
EntryCount int `gorm:"-" json:"entry_count"` // populated on read
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
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" }
|
||||
|
||||
Reference in New Issue
Block a user