Files
pj0235-eai_agentplatform/docs/db_schema.md
T
eaiadminandClaude Code 16d63de4e1 chore: 工作台产品化进行中的改动
把工作区里其余在制品一并入库,主要是工作台产品化的推进:

  后端:新增 capability_definition / project / my_app_center / office_skill
        接口与 action_definition / skill_definition / project / user_app_center
        模型,config 加路由健康上报。
  前端:新增 frontend/src/skills(Office 技能与 workbuddy 复刻)、
        项目管理、应用中心、能力目录页,以及配套 api / store / config;
        聊天侧新增 SpecialistChip / SpecialistPanel / SkillStrip / AppChatRail
        等组件。
  清理:移除旧 views/tools 下的单页工具(已并入工作台)、_frozen 冻结组件、
        cmd/inspect_oa_debug 调试入口,以及两份调试笔记。
  其它:文档与启动脚本同步。

(这批改动与上一提交的 SY23 工作并行进行,此前已在同一工作区内交织。)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-17 21:32:35 +08:00

333 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# eai_agentplatform — 数据库 Schema
> **版本:V1.3 | 引擎:SQLite(单文件,GORM AutoMigrate 建表)**
> **最后更新:2026-08-16**
## 约定
- 数据库使用 **SQLite 单文件** `data/eai_agentplatform.db`(GORM AutoMigrate 首次启动自动建表)
- AI 知识检索为 **Go 原生 brute-force 向量检索**(余弦相似度)+ 关键词兜底(不依赖外部向量库)
- 主键 `id` 为 `INTEGER PRIMARY KEY AUTOINCREMENT`
- 时间字段 `created_at` / `updated_at` 为 `DATETIME`,默认 `CURRENT_TIMESTAMP`
- 索引命名规则:`idx_{表}_{字段}`
- `INTEGER` 用于 `BIGINT` 场景(Go `uint`/`uint64`)
- `VARCHAR(n)` 映射为 `TEXT(n)`
- SQLite 外键默认关闭,需 `PRAGMA foreign_keys = ON`
---
## 1. `user` — 用户表
```
CREATE TABLE user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
full_name TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'employee',
status TEXT NOT NULL DEFAULT 'active',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_user_role ON user(role);
CREATE INDEX idx_user_status ON user(status);
```
**说明:**
- `role` 枚举:`employee` / `admin`
- `status` 枚举:`active` / `disabled`
- `disabled` 时 token 校验拒绝访问
- 仅管理员可创建/禁用账号
---
## 2. `product` — 产品表
```
CREATE TABLE product (
id INTEGER PRIMARY KEY AUTOINCREMENT,
code TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
category TEXT NOT NULL,
tags TEXT DEFAULT '',
description TEXT,
pricing TEXT,
commission_recommend TEXT DEFAULT '',
commission_negotiate TEXT DEFAULT '',
public_course_bonus TEXT DEFAULT '',
version_risk TEXT,
report_rules TEXT,
status TEXT DEFAULT 'active',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_product_category ON product(category);
CREATE INDEX idx_product_status ON product(status);
```
**字段说明:**
- `category` 枚举:`capital_consulting` / `qualification_counseling` / `ai_consulting` / `ai_tools_platform`
- `status` 枚举:`active` / `inactive`
---
## 3. `course` — 课程表
```
CREATE TABLE course (
id INTEGER PRIMARY KEY AUTOINCREMENT,
code TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
category TEXT NOT NULL,
target_customers TEXT,
forbidden_customers TEXT,
scripts TEXT,
sales_process TEXT,
objection_handling TEXT,
delivery_pitfalls TEXT,
report_rules TEXT,
related_product_id INTEGER,
status TEXT DEFAULT 'active',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_course_category ON course(category);
CREATE INDEX idx_course_status ON course(status);
CREATE INDEX idx_course_product ON course(related_product_id);
```
**字段说明:**
- `category` 枚举:`capital_script` / `qualification_logic` / `ai_public_course` / `ai_platform_matching`
- `status` 枚举:`active` / `inactive`
- `related_product_id` 可空(外键应用层维护)
---
## 4. `media_file` — 素材文件表
```
CREATE TABLE media_file (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filename TEXT NOT NULL,
file_path TEXT NOT NULL,
file_size INTEGER,
file_type TEXT,
status TEXT DEFAULT 'pending',
source TEXT DEFAULT 'employee',
submitter_id INTEGER,
remark TEXT,
bind_type TEXT DEFAULT 'none',
bind_id INTEGER,
reject_reason TEXT,
audit_by INTEGER,
audit_at DATETIME,
file_category TEXT,
extract_status TEXT DEFAULT 'pending',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_media_status ON media_file(status);
CREATE INDEX idx_media_submitter ON media_file(submitter_id);
CREATE INDEX idx_media_bind ON media_file(bind_type, bind_id);
CREATE INDEX idx_media_extract ON media_file(extract_status);
```
**字段说明:**
- `status`:`pending` / `approved` / `rejected`
- `source`:`employee` / `admin`
- `bind_type`:`company` / `product` / `course` / `none`
- `extract_status`:`pending` / `extracting` / `completed` / `failed`
---
## 5. `knowledge_chunk` — 知识块表
```
CREATE TABLE knowledge_chunk (
id INTEGER PRIMARY KEY AUTOINCREMENT,
media_file_id INTEGER,
knowledge_source_id INTEGER,
source_type TEXT NOT NULL,
source_id TEXT,
knowledge_space_key TEXT,
chunk_index INTEGER NOT NULL,
content TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_kc_media ON knowledge_chunk(media_file_id);
CREATE INDEX idx_kc_source ON knowledge_chunk(knowledge_source_id);
CREATE INDEX idx_kc_space ON knowledge_chunk(knowledge_space_key);
```
**说明:**
- `media_file_id` 与 `knowledge_source_id` 二者必居其一(应用层校验)
- `source_type`:`pdf` / `doc` / `md`
- 文本存储不建全文索引,检索由 Go 层 brute-force 余弦完成
---
## 6. `question` — 题目表
```
CREATE TABLE question (
id INTEGER PRIMARY KEY AUTOINCREMENT,
domain TEXT NOT NULL,
course_id INTEGER,
type TEXT NOT NULL,
stem TEXT NOT NULL,
options TEXT NOT NULL,
answer TEXT NOT NULL,
explanation TEXT DEFAULT '',
status TEXT DEFAULT 'active',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_question_domain ON question(domain);
CREATE INDEX idx_question_course ON question(course_id);
CREATE INDEX idx_question_status ON question(status);
```
**字段说明:**
- `type` 枚举:`single` / `multiple` / `judge` / `essay`(V1.5 新增)
- `options` / `answer` 存储 JSON 文本
---
## 7. `exam_paper` — 考试配置表
```
CREATE TABLE exam_paper (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
type TEXT NOT NULL,
domain TEXT NOT NULL,
question_count INTEGER NOT NULL,
total_score INTEGER NOT NULL,
pass_score INTEGER NOT NULL,
duration_minutes INTEGER NOT NULL,
randomize INTEGER DEFAULT 1,
status TEXT DEFAULT 'active',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_paper_type ON exam_paper(type);
CREATE INDEX idx_paper_status ON exam_paper(status);
```
**字段说明:**
- `type`:`self_test` / `formal`
---
## 8. `exam_record` — 考试记录表
```
CREATE TABLE exam_record (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
paper_id INTEGER NOT NULL,
exam_name TEXT NOT NULL,
score INTEGER NOT NULL,
total_score INTEGER NOT NULL,
pass_score INTEGER NOT NULL,
passed INTEGER NOT NULL,
correct_count INTEGER NOT NULL,
wrong_count INTEGER NOT NULL,
detail_json TEXT NOT NULL,
submitted_at DATETIME NOT NULL
);
CREATE INDEX idx_record_user ON exam_record(user_id);
CREATE INDEX idx_record_paper ON exam_record(paper_id);
CREATE INDEX idx_record_passed ON exam_record(passed);
CREATE INDEX idx_record_submitted ON exam_record(submitted_at);
```
---
## 9. `system_config` — 系统参数配置表
```
CREATE TABLE system_config (
id INTEGER PRIMARY KEY AUTOINCREMENT,
config_key TEXT NOT NULL UNIQUE,
config_value TEXT NOT NULL,
description TEXT DEFAULT '',
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_config_key ON system_config(config_key);
```
### 默认配置项
| config_key | 默认值 | 说明 |
|-----------|--------|------|
| `llm_base_url` | `http://localhost:11434/v1` | LLM 服务地址 |
| `llm_api_key` | `sk-xxx` | LLM API Key |
| `llm_model` | `qwen2.5:7b` | LLM 模型名 |
| `jwt_expire_minutes` | `480` | Token 过期分钟数 |
| `file_max_size_doc` | `209715200` | 文档最大字节(200MB) |
| `file_max_size_video` | `2147483648` | 视频最大字节(2GB) |
| `chunk_threshold` | `104857600` | 分片上传阈值(100MB) |
---
## 10. `knowledge_source` — 结构化知识源表
完整设计见 `04_Backend/BE05_Knowledge_Ingest_Module.md`。
```
CREATE TABLE knowledge_source (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
file_path TEXT NOT NULL UNIQUE,
category TEXT NOT NULL,
domain TEXT DEFAULT 'product',
source_version TEXT NOT NULL,
audit_status TEXT DEFAULT 'pending',
audit_by INTEGER,
audit_at DATETIME,
reject_reason TEXT,
ingested INTEGER DEFAULT 0,
knowledge_space_key TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_ks_status ON knowledge_source(audit_status);
CREATE INDEX idx_ks_category ON knowledge_source(category);
```
**字段说明:**
- `audit_status`:`pending` / `approved` / `rejected`
- `domain`:`company` / `product` / `sales`
---
## 附:ER 关系
```
user ──< media_file (submitter_id / audit_by)
user ──< exam_record (user_id)
user ──< question (course_id → course)
user ──< knowledge_source (audit_by)
product ──< course (related_product_id)
course ──< question (course_id, optional)
media_file ──< knowledge_chunk (media_file_id)
knowledge_source ──< knowledge_chunk (knowledge_source_id)
exam_paper ──< exam_record (paper_id)
```
## 附:V1.4–V1.7 新增表
| 版本 | 表名 | 用途 |
|------|------|------|
| V1.4 | `position` | 岗位字典 |
| V1.4 | `position_knowledge` | 岗位 → 知识映射(域/课程/产品 + 级别 L1-L4 + 权重 + 必学)|
| V1.5 | `position_exam_blueprint` | 岗位考试蓝图(按域+题型+题量抽题)|
| V1.5 | `mistake_record` | 错题本(按 user+question 去重,标记已掌握)|
| V1.6 | `point_event` | 学习积分流水(可审计)|
| V1.6 | `certificate` | 考试合格证书(按 exam_record_id 幂等去重)|
| V1.7 | `department` | 部门字典(部门改名同步 user.department)|
| V1.7 | `notification` | 站内消息通知(事件钩子驱动)|
**列级变更:** `user.learning_points`(V1.6)、`user.position_id`(V1.4)、`user.department`(V1.7)、`exam_paper.position_id`(V1.4)、`question.type` 增加 `essay`(V1.5)。