21 KiB
数据库设计
权威来源是
backend/app/models/:本文是它的可读镜像,两者冲突时以模型为准并回改本文。 结构变更流程见 quickstart.md §9。
- 引擎:MySQL 8.0 / InnoDB /
utf8mb4/utf8mb4_unicode_ci - 表数量:18
- 时间列:
created_at/updated_at由各模型的default=now/onupdate=now维护(DATETIME,无时区,容器时区固定Asia/Shanghai) - 主键:除
llm_model_config.config_id外,其余表主键均为自增id - ⚠️ 文档正文不在数据库里:Markdown 正文存在文件系统(
STORAGE_ROOT/projects/<storage_key>/…),数据库只存权限、元数据与索引(见 sdd ADR-0001、ADR-0002)
表清单
| 分组 | 表 | 用途 | 主要写入方 |
|---|---|---|---|
| 身份权限 | users |
账号、状态、超管标记、登录痕迹 | 注册、用户管理、登录 |
| 身份权限 | roles |
角色(super_admin / admin / user + 自定义) | 角色管理、init_db.py 种子 |
| 身份权限 | user_roles |
用户 ↔ 角色 | 用户管理 |
| 身份权限 | system_menus |
菜单 与 按钮级权限点(menu_type 区分) |
init_db.py 种子、权限管理 |
| 身份权限 | role_menus |
角色 ↔ 菜单/权限点 | 权限管理 |
| 项目文档 | projects |
项目主表,storage_key 是磁盘目录名 |
项目管理 |
| 项目文档 | project_members |
项目成员与项目内角色 | 成员管理 |
| 项目文档 | document_meta |
文档标题/标签/字数/浏览与编辑痕迹(可选表,正文仍在文件) | 保存文件、浏览统计 |
| 项目文档 | project_git_repos |
项目绑定的 Git 仓库(含令牌) | Git 同步设置 |
| 项目文档 | share_links |
项目/文件分享码与访问密码 | 分享管理 |
| AI 知识库 | llm_model_config |
Chat / Embedding 模型配置 | 模型配置 |
| AI 知识库 | chat_session |
对话会话(按项目 + 用户 + 模型) | 对话 |
| AI 知识库 | chat_message |
消息、状态、耗时、思考过程、引用文件 | 对话 |
| AI 知识库 | document_vector |
文档分块 → 向量库映射(ZVec) | 向量化 |
| AI 知识库 | project_vectorization_task |
全量/增量向量化任务与进度 | 向量化 |
| 通知审计 | notifications |
站内通知 | 通知服务 |
| 通知审计 | operation_logs |
操作审计(谁、何时、对什么、结果) | log_service(各 API 埋点) |
| 通知审计 | mcp_bots |
MCP Bot 的 bot_id/secret 凭证 |
MCP 凭证管理 |
关系(逻辑外键)
数据库只在 notifications.user_id 与 project_git_repos.project_id 上声明了真正的 FOREIGN KEY,其余是逻辑外键(不建约束,便于分库与批量清理):
users 1─N user_roles N─1 roles 1─N role_menus N─1 system_menus
users 1─N projects(owner_id) 1─N project_members N─1 users
projects 1─N document_meta / share_links / project_git_repos
/ document_vector / project_vectorization_task / chat_session
chat_session 1─N chat_message
projects 1─N chat_session(同时 chat_session.user_id → users)
删除项目时由服务层负责级联清理文件目录与相关索引行;不要指望数据库级联。
初始化与迁移
| 阶段 | 代码 | 行为 |
|---|---|---|
| 建表 | backend/scripts/init_db.py → Base.metadata.create_all |
只创建缺失表;表结构来自 app/models/。模型必须在 app/models/__init__.py 中注册,否则该表不会出现在新库里 |
| 种子 | 同上 | 角色(super_admin/admin/user)、系统菜单与权限点、管理员账号;按 id 与 (parent_id, menu_name) 去重,幂等增量 |
| 补列 | app/core/migrations.py::migrate_schema() |
幂等 ALTER TABLE ADD COLUMN(先查 information_schema)。当前覆盖:chat_message.status/duration_ms/thinking_log、project_git_repos.sync_path |
| 未使用 | Alembic | 依赖里有 alembic,但项目未启用版本化迁移脚本 |
Docker 部署时后端容器启动命令是 python scripts/init_db.py && uvicorn main:app …,因此新环境无需手工执行 SQL。
已知数据差异与运维建议
-
project_members.role大小写混杂:历史数据(早期init_database.sql建的库)多为ADMIN/EDITOR/VIEWER,新写入是admin/editor/viewer。读取路径统一经过app/services/project_service.normalize_project_role()归一化,因此行为正确;如需彻底清洗,可执行:UPDATE project_members SET role = LOWER(role) WHERE BINARY role <> LOWER(role); -
share_links.access_pass/project_git_repos.token为明文存储:属已知技术债(见发布报告 P2)。上线前应限制库账号的远程访问并纳入备份加密范围。 -
document_vector无数据库唯一约束:靠idx_project_file_chunk(project_id, file_path, chunk_index)普通索引查询,重复向量化由服务层用content_hash判定,不在库里去重。 -
llm_model_config.api_key明文:同上,接口返回时会脱敏,但库里是原文。 -
备份:文件系统(
STORAGE_PATH)与数据库必须一起备份,缺一个都无法还原,命令见 deploy/README.md。
-- 常用排查
SELECT id, name, storage_key, owner_id, is_public FROM projects WHERE id = ?; -- storage_key 即磁盘目录名
SELECT status, COUNT(*) FROM document_vector WHERE project_id = ? GROUP BY status;
SELECT task_id, task_type, status, total, processed, failed FROM project_vectorization_task
WHERE project_id = ? ORDER BY created_at DESC LIMIT 5;
SELECT role, COUNT(*) FROM project_members WHERE project_id = ? GROUP BY role;
身份与权限
users — 用户
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 用户ID |
username |
VARCHAR(50) | UNIQUE · NOT NULL | 用户名 |
password_hash |
VARCHAR(255) | NOT NULL | 密码哈希 |
nickname |
VARCHAR(50) | — | 昵称 |
email |
VARCHAR(100) | — | 邮箱 |
phone |
VARCHAR(20) | — | 手机号 |
avatar |
VARCHAR(255) | — | 头像URL |
status |
SMALLINT | 默认 1 |
状态:0-禁用 1-启用 |
is_superuser |
SMALLINT | 默认 0 |
是否超级管理员:0-否 1-是 |
last_login_at |
DATETIME | — | 最后登录时间 |
last_login_ip |
VARCHAR(50) | — | 最后登录IP |
created_at |
DATETIME | — | 创建时间 |
updated_at |
DATETIME | — | 更新时间 |
索引:ix_users_email(email);ix_users_status(status);ix_users_username(username) UNIQUE
roles — 角色
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 角色ID |
role_name |
VARCHAR(50) | UNIQUE · NOT NULL | 角色名称 |
role_code |
VARCHAR(50) | UNIQUE · NOT NULL | 角色编码 |
description |
VARCHAR(255) | — | 角色描述 |
status |
SMALLINT | 默认 1 |
状态:0-禁用 1-启用 |
is_system |
SMALLINT | 默认 0 |
是否系统角色:0-否 1-是 |
created_at |
DATETIME | — | 创建时间 |
updated_at |
DATETIME | — | 更新时间 |
索引:ix_roles_role_code(role_code) UNIQUE;ix_roles_status(status)
user_roles — 用户-角色关联
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 关联ID |
user_id |
BIGINT | NOT NULL | 用户ID |
role_id |
BIGINT | NOT NULL | 角色ID |
created_at |
DATETIME | — | 创建时间 |
索引:ix_user_roles_role_id(role_id);ix_user_roles_user_id(user_id)
system_menus — 系统菜单/权限点
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 菜单ID |
parent_id |
BIGINT | 默认 0 |
父菜单ID(0表示根菜单) |
menu_name |
VARCHAR(50) | NOT NULL | 菜单名称 |
menu_code |
VARCHAR(50) | UNIQUE · NOT NULL | 菜单编码 |
menu_type |
SMALLINT | NOT NULL | 菜单类型:1-目录 2-菜单 3-按钮/权限点 |
path |
VARCHAR(255) | — | 路由路径 |
component |
VARCHAR(255) | — | 组件路径 |
icon |
VARCHAR(100) | — | 图标 |
sort_order |
INTEGER | 默认 0 |
排序号 |
visible |
SMALLINT | 默认 1 |
是否可见:0-隐藏 1-显示 |
status |
SMALLINT | 默认 1 |
状态:0-禁用 1-启用 |
permission |
VARCHAR(100) | — | 权限字符串 |
created_at |
DATETIME | — | 创建时间 |
updated_at |
DATETIME | — | 更新时间 |
索引:ix_system_menus_menu_code(menu_code) UNIQUE;ix_system_menus_status(status)
role_menus — 角色-菜单授权
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 关联ID |
role_id |
BIGINT | NOT NULL | 角色ID |
menu_id |
BIGINT | NOT NULL | 菜单ID |
created_at |
DATETIME | — | 创建时间 |
索引:ix_role_menus_menu_id(menu_id);ix_role_menus_role_id(role_id)
项目与文档
projects — 项目
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 项目ID |
name |
VARCHAR(100) | NOT NULL | 项目名称 |
description |
VARCHAR(500) | — | 项目描述 |
storage_key |
VARCHAR(36) | UNIQUE · NOT NULL | 磁盘存储UUID |
owner_id |
BIGINT | NOT NULL | 项目所有者ID |
is_public |
SMALLINT | 默认 0 |
是否公开:0-私有 1-公开 |
is_template |
SMALLINT | 默认 0 |
是否模板项目:0-否 1-是 |
status |
SMALLINT | 默认 1 |
状态:0-归档 1-活跃 |
cover_image |
VARCHAR(255) | — | 封面图 |
sort_order |
INTEGER | 默认 0 |
排序号 |
visit_count |
INTEGER | 默认 0 |
访问次数 |
access_pass |
VARCHAR(100) | — | 访问密码(用于分享链接) |
created_at |
DATETIME | — | 创建时间 |
updated_at |
DATETIME | — | 更新时间 |
索引:ix_projects_created_at(created_at);ix_projects_name(name);ix_projects_owner_id(owner_id);ix_projects_status(status)
project_members — 项目成员
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 成员ID |
project_id |
BIGINT | NOT NULL | 项目ID |
user_id |
BIGINT | NOT NULL | 用户ID |
role |
VARCHAR(20) | 默认 viewer |
项目角色: admin/editor/viewer |
invited_by |
BIGINT | — | 邀请人ID |
joined_at |
DATETIME | — | 加入时间 |
索引:ix_project_members_project_id(project_id);ix_project_members_role(role);ix_project_members_user_id(user_id)
document_meta — 文档元数据
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 元数据ID |
project_id |
BIGINT | NOT NULL | 项目ID |
file_path |
VARCHAR(500) | NOT NULL | 文件相对路径 |
title |
VARCHAR(200) | — | 文档标题 |
tags |
VARCHAR(500) | — | 标签(JSON数组) |
author_id |
BIGINT | — | 作者ID |
word_count |
INTEGER | 默认 0 |
字数统计 |
view_count |
INTEGER | 默认 0 |
浏览次数 |
last_editor_id |
BIGINT | — | 最后编辑者ID |
last_edited_at |
DATETIME | — | 最后编辑时间 |
created_at |
DATETIME | — | 创建时间 |
updated_at |
DATETIME | — | 更新时间 |
索引:ix_document_meta_author_id(author_id);ix_document_meta_project_id(project_id)
project_git_repos — 项目绑定的 Git 仓库
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | ID |
project_id |
BIGINT | FK → projects.id · NOT NULL | 项目ID |
name |
VARCHAR(50) | NOT NULL | 仓库别名 |
repo_url |
VARCHAR(255) | NOT NULL | Git仓库地址 |
branch |
VARCHAR(50) | 默认 main |
Git分支 |
username |
VARCHAR(100) | — | Git用户名 |
token |
VARCHAR(255) | — | Git访问令牌/密码 |
is_default |
SMALLINT | 默认 0 |
是否默认仓库 |
sync_path |
VARCHAR(255) | — | 同步目录(空=整个仓库) |
created_at |
DATETIME | — | 创建时间 |
updated_at |
DATETIME | — | 更新时间 |
索引:ix_project_git_repos_project_id(project_id)
share_links — 分享链接
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 分享ID |
project_id |
BIGINT | NOT NULL | 项目ID |
share_type |
VARCHAR(20) | NOT NULL | 分享类型: project/file |
share_code |
VARCHAR(64) | UNIQUE · NOT NULL | 公开分享码 |
file_path |
VARCHAR(500) | — | 文件路径,仅文件分享使用 |
access_pass |
VARCHAR(100) | — | 访问密码 |
created_by |
BIGINT | — | 创建人ID |
status |
SMALLINT | 默认 1 |
状态:0-禁用 1-启用 |
created_at |
DATETIME | — | 创建时间 |
updated_at |
DATETIME | — | 更新时间 |
索引:ix_share_links_created_by(created_by);ix_share_links_project_id(project_id);ix_share_links_share_code(share_code) UNIQUE;ix_share_links_share_type(share_type);ix_share_links_status(status)
AI 知识库
llm_model_config — LLM 模型配置
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
config_id |
BIGINT | PK | 配置ID |
model_code |
VARCHAR(128) | UNIQUE · NOT NULL | 模型编码 |
model_name |
VARCHAR(255) | NOT NULL | 模型名称 |
model_type |
VARCHAR(32) | NOT NULL · 默认 chat |
模型类型: chat/embedding |
provider |
VARCHAR(64) | — | 模型提供方 |
endpoint_url |
VARCHAR(512) | — | 接口地址 |
api_key |
VARCHAR(512) | — | API Key |
llm_model_name |
VARCHAR(128) | NOT NULL | 模型名称/部署名 |
llm_timeout |
INTEGER | NOT NULL · 默认 120 |
超时时间(秒) |
type_config |
JSON | NOT NULL · 默认 服务端函数 |
模型类型差异参数 |
description |
VARCHAR(500) | — | 描述 |
is_active |
BOOLEAN | NOT NULL · 默认 True |
是否启用 |
is_default |
BOOLEAN | NOT NULL · 默认 False |
是否默认 |
created_at |
DATETIME | — | 创建时间 |
updated_at |
DATETIME | — | 更新时间 |
索引:ix_llm_model_config_is_active(is_active);ix_llm_model_config_model_code(model_code) UNIQUE;ix_llm_model_config_model_type(model_type)
chat_session — 对话会话
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 会话ID |
project_id |
BIGINT | NOT NULL | 项目ID |
user_id |
BIGINT | NOT NULL | 用户ID |
llm_config_id |
BIGINT | NOT NULL | LLM配置ID |
title |
VARCHAR(255) | NOT NULL | 会话标题 |
description |
TEXT | — | 会话描述 |
is_active |
BOOLEAN | NOT NULL · 默认 True |
是否激活 |
message_count |
INTEGER | NOT NULL · 默认 0 |
消息数 |
created_at |
DATETIME | — | 创建时间 |
updated_at |
DATETIME | — | 更新时间 |
索引:ix_chat_session_project_id(project_id);ix_chat_session_user_id(user_id)
chat_message — 对话消息
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 消息ID |
session_id |
BIGINT | NOT NULL | 会话ID |
role |
VARCHAR(32) | NOT NULL | 角色(user/assistant) |
content |
TEXT | NOT NULL | 消息内容 |
status |
VARCHAR(32) | NOT NULL · 默认 pending |
消息状态: pending/completed/interrupted/error |
duration_ms |
INTEGER | — | 生成耗时(毫秒) |
thinking_log |
TEXT | — | 思考过程(JSON数组) |
referenced_files |
TEXT | — | 参考文件(JSON数组) |
tokens_used |
INTEGER | — | 消耗的token数 |
is_deleted |
BOOLEAN | NOT NULL · 默认 False |
是否已删除 |
created_at |
DATETIME | — | 创建时间 |
索引:ix_chat_message_session_id(session_id)
document_vector — 文档向量分块
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 向量ID |
project_id |
BIGINT | NOT NULL | 项目ID |
file_path |
VARCHAR(500) | NOT NULL | 文件相对路径 |
chunk_index |
INTEGER | NOT NULL · 默认 0 |
分块序号(0起),同一文件可有多个分块 |
chunk_text |
TEXT | — | 分块首段文本,作为点击引用时的定位锚点 |
content_hash |
VARCHAR(64) | — | 整个文件内容哈希值,用于判断文件是否变更 |
zvec_id |
VARCHAR(256) | — | ZVec返回的向量ID(每个分块独立) |
zvec_response |
TEXT | — | ZVec完整响应JSON |
status |
VARCHAR(32) | NOT NULL · 默认 success |
向量化状态:success/failed/pending |
error_message |
VARCHAR(500) | — | 错误信息 |
created_at |
DATETIME | — | 创建时间 |
updated_at |
DATETIME | — | 更新时间 |
索引:idx_project_file_chunk(project_id, file_path, chunk_index);idx_project_file(project_id, file_path);ix_document_vector_project_id(project_id)
project_vectorization_task — 项目向量化任务
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 任务ID |
task_id |
VARCHAR(64) | UNIQUE · NOT NULL | 任务唯一标识 |
project_id |
BIGINT | NOT NULL | 项目ID |
user_id |
BIGINT | NOT NULL | 触发用户ID |
task_type |
VARCHAR(32) | NOT NULL | 任务类型:incremental/full |
status |
VARCHAR(32) | NOT NULL · 默认 pending |
任务状态:pending/running/success/failed |
total |
INTEGER | NOT NULL · 默认 0 |
文件总数 |
processed |
INTEGER | NOT NULL · 默认 0 |
处理成功数 |
skipped |
INTEGER | NOT NULL · 默认 0 |
跳过数 |
failed |
INTEGER | NOT NULL · 默认 0 |
失败数 |
error_message |
TEXT | — | 错误信息 |
started_at |
DATETIME | — | 开始时间 |
finished_at |
DATETIME | — | 完成时间 |
created_at |
DATETIME | — | 创建时间 |
updated_at |
DATETIME | — | 更新时间 |
索引:idx_vector_task_created_at(created_at);idx_vector_task_project_status(project_id, status);ix_project_vectorization_task_project_id(project_id);ix_project_vectorization_task_status(status);ix_project_vectorization_task_task_id(task_id) UNIQUE;ix_project_vectorization_task_user_id(user_id)
通知与审计
notifications — 站内通知
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 通知ID |
user_id |
BIGINT | FK → users.id · NOT NULL | 接收用户ID |
type |
VARCHAR(20) | 默认 info |
类型:info, success, warning, error |
category |
VARCHAR(50) | 默认 system |
分类:system, project, collaboration |
title |
VARCHAR(200) | NOT NULL | 标题 |
content |
TEXT | — | 内容 |
link |
VARCHAR(255) | — | 跳转链接 |
is_read |
SMALLINT | 默认 0 |
是否已读:0-未读 1-已读 |
created_at |
DATETIME | — | 创建时间 |
read_at |
DATETIME | — | 阅读时间 |
索引:ix_notifications_user_id(user_id)
operation_logs — 操作日志
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | 日志ID |
user_id |
BIGINT | — | 操作用户ID |
username |
VARCHAR(50) | — | 用户名 |
operation_type |
VARCHAR(50) | NOT NULL | 操作类型 |
resource_type |
VARCHAR(50) | NOT NULL | 资源类型 |
resource_id |
BIGINT | — | 资源ID |
detail |
TEXT | — | 操作详情(JSON) |
ip_address |
VARCHAR(50) | — | IP地址 |
user_agent |
VARCHAR(500) | — | 用户代理 |
status |
SMALLINT | 默认 1 |
状态:0-失败 1-成功 |
error_message |
TEXT | — | 错误信息 |
created_at |
DATETIME | — | 操作时间 |
索引:ix_operation_logs_created_at(created_at);ix_operation_logs_resource_id(resource_id);ix_operation_logs_resource_type(resource_type);ix_operation_logs_user_id(user_id)
mcp_bots — MCP Bot 凭证
| 字段 | 类型 | 约束/默认 | 说明 |
|---|---|---|---|
id |
BIGINT | PK | Bot credential ID |
user_id |
BIGINT | UNIQUE · NOT NULL | Owner user ID |
bot_id |
VARCHAR(64) | UNIQUE · NOT NULL | External MCP bot id |
bot_secret |
VARCHAR(255) | NOT NULL | External MCP bot secret |
status |
SMALLINT | 默认 1 |
Status: 0-disabled 1-enabled |
last_used_at |
DATETIME | — | Last successful MCP access time |
created_at |
DATETIME | — | Created at |
updated_at |
DATETIME | — | Updated at |
索引:ix_mcp_bots_bot_id(bot_id) UNIQUE;ix_mcp_bots_status(status);ix_mcp_bots_user_id(user_id) UNIQUE
变更记录
| 日期 | 变更 |
|---|---|
| 2026-09-30 | 按 v1.0.0 代码重写:补齐 notifications、mcp_bots、project_git_repos、chat_*、document_vector、project_vectorization_task 等 10 张此前未记录的表;删除已废弃的 init_database.sql 相关描述 |