把工作区里其余在制品一并入库,主要是工作台产品化的推进:
后端:新增 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>
333 lines
11 KiB
Markdown
333 lines
11 KiB
Markdown
# 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)。
|