增加部署说明

This commit is contained in:
silk 2026-06-01 14:15:01 +08:00
parent 4cd86d97bd
commit 0d341f0513
5 changed files with 656 additions and 759 deletions

555
ddl-init.sql Normal file
View File

@ -0,0 +1,555 @@
-- public.chat_messages definition
-- Drop table
-- DROP TABLE public.chat_messages;
CREATE TABLE public.chat_messages (
id serial4 NOT NULL,
thread_id varchar(255) NOT NULL,
checkpoint_id varchar(255) NOT NULL,
message_index int4 NOT NULL,
"role" varchar(20) NOT NULL,
"content" text NOT NULL,
injected_content text NULL,
has_files bool DEFAULT false NULL,
metadata jsonb NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
"name" varchar(255) NULL,
CONSTRAINT chat_messages_pkey PRIMARY KEY (id),
CONSTRAINT uk_checkpoint_message UNIQUE (checkpoint_id, message_index)
);
CREATE INDEX idx_chat_messages_checkpoint_id ON public.chat_messages USING btree (checkpoint_id);
CREATE INDEX idx_chat_messages_content_search ON public.chat_messages USING gin (to_tsvector('simple'::regconfig, content));
CREATE INDEX idx_chat_messages_has_files ON public.chat_messages USING btree (has_files);
CREATE INDEX idx_chat_messages_metadata ON public.chat_messages USING gin (metadata);
CREATE INDEX idx_chat_messages_role ON public.chat_messages USING btree (role);
CREATE INDEX idx_chat_messages_thread_created ON public.chat_messages USING btree (thread_id, created_at DESC);
CREATE INDEX idx_chat_messages_thread_id ON public.chat_messages USING btree (thread_id);
-- public.checkpoint_blobs definition
-- Drop table
-- DROP TABLE public.checkpoint_blobs;
CREATE TABLE public.checkpoint_blobs (
thread_id text NOT NULL,
checkpoint_ns text DEFAULT ''::text NOT NULL,
channel text NOT NULL,
"version" text NOT NULL,
"type" text NOT NULL,
"blob" bytea NULL,
CONSTRAINT checkpoint_blobs_pkey PRIMARY KEY (thread_id, checkpoint_ns, channel, version)
);
CREATE INDEX checkpoint_blobs_thread_id_idx ON public.checkpoint_blobs USING btree (thread_id);
-- public.checkpoint_migrations definition
-- Drop table
-- DROP TABLE public.checkpoint_migrations;
CREATE TABLE public.checkpoint_migrations (
v int4 NOT NULL,
CONSTRAINT checkpoint_migrations_pkey PRIMARY KEY (v)
);
-- public.checkpoint_writes definition
-- Drop table
-- DROP TABLE public.checkpoint_writes;
CREATE TABLE public.checkpoint_writes (
thread_id text NOT NULL,
checkpoint_ns text DEFAULT ''::text NOT NULL,
checkpoint_id text NOT NULL,
task_id text NOT NULL,
idx int4 NOT NULL,
channel text NOT NULL,
"type" text NULL,
"blob" bytea NOT NULL,
task_path text DEFAULT ''::text NOT NULL,
CONSTRAINT checkpoint_writes_pkey PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id, task_id, idx)
);
CREATE INDEX checkpoint_writes_thread_id_idx ON public.checkpoint_writes USING btree (thread_id);
-- public.checkpoints definition
-- Drop table
-- DROP TABLE public.checkpoints;
CREATE TABLE public.checkpoints (
thread_id text NOT NULL,
checkpoint_ns text DEFAULT ''::text NOT NULL,
checkpoint_id text NOT NULL,
parent_checkpoint_id text NULL,
"type" text NULL,
"checkpoint" jsonb NOT NULL,
metadata jsonb DEFAULT '{}'::jsonb NOT NULL,
CONSTRAINT checkpoints_pkey PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id)
);
CREATE INDEX checkpoints_thread_id_idx ON public.checkpoints USING btree (thread_id);
-- public.enterprise definition
-- Drop table
-- DROP TABLE public.enterprise;
CREATE TABLE public.enterprise (
id serial4 NOT NULL,
"name" varchar(255) NOT NULL,
code varchar(64) NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL,
ai_display_name varchar(128) DEFAULT '智能助手 AI'::character varying NOT NULL,
CONSTRAINT enterprise_code_key UNIQUE (code),
CONSTRAINT enterprise_pkey PRIMARY KEY (id)
);
-- public.chat_message_file definition
-- Drop table
-- DROP TABLE public.chat_message_file;
CREATE TABLE public.chat_message_file (
id serial4 NOT NULL,
thread_id varchar(255) NOT NULL,
checkpoint_id varchar(255) NOT NULL,
message_index int4 NOT NULL,
file_id int4 NOT NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
CONSTRAINT chat_message_file_pkey PRIMARY KEY (id),
CONSTRAINT uk_message_file UNIQUE (checkpoint_id, message_index, file_id)
);
CREATE INDEX idx_chat_message_file_checkpoint ON public.chat_message_file USING btree (checkpoint_id, message_index);
CREATE INDEX idx_chat_message_file_file_id ON public.chat_message_file USING btree (file_id);
CREATE INDEX idx_chat_message_file_thread_checkpoint ON public.chat_message_file USING btree (thread_id, checkpoint_id);
CREATE INDEX idx_chat_message_file_thread_id ON public.chat_message_file USING btree (thread_id);
-- public.chat_thread_chunk definition
-- Drop table
-- DROP TABLE public.chat_thread_chunk;
CREATE TABLE public.chat_thread_chunk (
id serial4 NOT NULL,
file_id int4 NOT NULL,
thread_id varchar(255) NOT NULL,
chunk_index int4 NOT NULL,
"content" text NOT NULL,
metadata jsonb NULL,
vector_id varchar(255) NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
summary text NULL,
CONSTRAINT chat_thread_chunk_pkey PRIMARY KEY (id)
);
CREATE INDEX idx_chat_thread_chunk_created_at ON public.chat_thread_chunk USING btree (created_at);
CREATE INDEX idx_chat_thread_chunk_file_id ON public.chat_thread_chunk USING btree (file_id);
CREATE INDEX idx_chat_thread_chunk_file_thread ON public.chat_thread_chunk USING btree (file_id, thread_id);
CREATE INDEX idx_chat_thread_chunk_thread_id ON public.chat_thread_chunk USING btree (thread_id);
CREATE INDEX idx_chat_thread_chunk_vector_id ON public.chat_thread_chunk USING btree (vector_id);
-- public.chat_thread_file definition
-- Drop table
-- DROP TABLE public.chat_thread_file;
CREATE TABLE public.chat_thread_file (
id serial4 NOT NULL,
thread_id varchar(255) NOT NULL,
user_id int4 NOT NULL,
file_name varchar(255) NOT NULL,
file_path varchar(500) NOT NULL,
file_size int4 DEFAULT 0 NULL,
file_type varchar(50) DEFAULT 'pdf'::character varying NULL,
status varchar(20) DEFAULT 'processing'::character varying NULL,
chunk_count int4 DEFAULT 0 NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
updated_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
is_deleted bool DEFAULT false NULL,
deleted_at timestamptz NULL,
CONSTRAINT chat_thread_file_pkey PRIMARY KEY (id)
);
CREATE INDEX idx_chat_thread_file_created_at ON public.chat_thread_file USING btree (created_at);
CREATE INDEX idx_chat_thread_file_is_deleted ON public.chat_thread_file USING btree (is_deleted);
CREATE INDEX idx_chat_thread_file_status ON public.chat_thread_file USING btree (status);
CREATE INDEX idx_chat_thread_file_thread_deleted ON public.chat_thread_file USING btree (thread_id, is_deleted);
CREATE INDEX idx_chat_thread_file_thread_id ON public.chat_thread_file USING btree (thread_id);
CREATE INDEX idx_chat_thread_file_thread_user ON public.chat_thread_file USING btree (thread_id, user_id);
CREATE INDEX idx_chat_thread_file_user_id ON public.chat_thread_file USING btree (user_id);
CREATE UNIQUE INDEX uk_chat_thread_file_thread_name_active ON public.chat_thread_file USING btree (thread_id, file_name) WHERE (is_deleted = false);
-- public.chat_threads definition
-- Drop table
-- DROP TABLE public.chat_threads;
CREATE TABLE public.chat_threads (
id serial4 NOT NULL,
thread_id varchar(255) NOT NULL,
user_id int4 NOT NULL,
title varchar(50) NOT NULL,
first_query text NOT NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
updated_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
message_count int4 DEFAULT 1 NULL,
is_deleted bool DEFAULT false NULL,
knowledge_base_id int4 NULL,
novel_graph_id int4 NULL,
knowledge_graph_id int4 NULL,
ip varchar(128) NULL,
CONSTRAINT chat_threads_pkey PRIMARY KEY (id),
CONSTRAINT uk_thread_id UNIQUE (thread_id)
);
CREATE INDEX idx_chat_threads_created_at ON public.chat_threads USING btree (created_at DESC);
CREATE INDEX idx_chat_threads_knowledge_graph_id ON public.chat_threads USING btree (knowledge_graph_id);
CREATE INDEX idx_chat_threads_novel_graph_id ON public.chat_threads USING btree (novel_graph_id);
CREATE INDEX idx_chat_threads_user_created ON public.chat_threads USING btree (user_id, created_at DESC);
CREATE INDEX idx_chat_threads_user_id ON public.chat_threads USING btree (user_id);
-- public.department definition
-- Drop table
-- DROP TABLE public.department;
CREATE TABLE public.department (
id serial4 NOT NULL,
enterprise_id int4 NOT NULL,
"name" varchar(255) NOT NULL,
parent_id int4 NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL,
leader_user_id int4 NULL,
CONSTRAINT department_pkey PRIMARY KEY (id),
CONSTRAINT uq_department_enterprise_name UNIQUE (enterprise_id, name)
);
CREATE INDEX idx_department_enterprise_id ON public.department USING btree (enterprise_id);
CREATE INDEX idx_department_leader_user_id ON public.department USING btree (leader_user_id);
-- public.graphs definition
-- Drop table
-- DROP TABLE public.graphs;
CREATE TABLE public.graphs (
id serial4 NOT NULL,
user_id int4 NOT NULL,
"name" varchar(255) NOT NULL,
description text NULL,
csv_file_name varchar(255) NULL,
node_count int4 DEFAULT 0 NULL,
edge_count int4 DEFAULT 0 NULL,
neo4j_graph_id varchar(100) NOT NULL,
graph_type varchar(20) DEFAULT 'knowledge'::character varying NOT NULL,
build_status varchar(20) NULL,
build_error text NULL,
rag_chunk_count int4 DEFAULT 0 NOT NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
updated_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
enterprise_id int4 NOT NULL,
department_id int4 NULL,
creator_id int4 NOT NULL,
visibility varchar(32) DEFAULT 'private'::character varying NOT NULL,
CONSTRAINT ck_graphs_visibility CHECK (((visibility)::text = ANY ((ARRAY['private'::character varying, 'department'::character varying, 'enterprise'::character varying])::text[]))),
CONSTRAINT graphs_neo4j_graph_id_key UNIQUE (neo4j_graph_id),
CONSTRAINT graphs_pkey PRIMARY KEY (id)
);
CREATE INDEX idx_graphs_created_at ON public.graphs USING btree (created_at DESC);
CREATE INDEX idx_graphs_creator ON public.graphs USING btree (creator_id);
CREATE INDEX idx_graphs_ent_vis ON public.graphs USING btree (enterprise_id, visibility);
CREATE INDEX idx_graphs_enterprise ON public.graphs USING btree (enterprise_id);
CREATE INDEX idx_graphs_graph_type ON public.graphs USING btree (user_id, graph_type);
CREATE INDEX idx_graphs_neo4j_id ON public.graphs USING btree (neo4j_graph_id);
CREATE INDEX idx_graphs_user_id ON public.graphs USING btree (user_id);
-- public.kb_audit_log definition
-- Drop table
-- DROP TABLE public.kb_audit_log;
CREATE TABLE public.kb_audit_log (
id serial4 NOT NULL,
enterprise_id int4 NOT NULL,
actor_id int4 NOT NULL,
target_user_id int4 NULL,
department_id int4 NULL,
kb_id int4 NULL,
file_id int4 NULL,
"action" varchar(50) NOT NULL,
ip varchar(128) NULL,
user_agent text NULL,
metadata jsonb NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT kb_audit_log_pkey PRIMARY KEY (id)
);
CREATE INDEX idx_kb_audit_log_action ON public.kb_audit_log USING btree (action);
CREATE INDEX idx_kb_audit_log_actor_id ON public.kb_audit_log USING btree (actor_id);
CREATE INDEX idx_kb_audit_log_created_at ON public.kb_audit_log USING btree (created_at DESC);
CREATE INDEX idx_kb_audit_log_department_id ON public.kb_audit_log USING btree (department_id);
CREATE INDEX idx_kb_audit_log_ent_dept_created ON public.kb_audit_log USING btree (enterprise_id, department_id, created_at DESC);
CREATE INDEX idx_kb_audit_log_enterprise_id ON public.kb_audit_log USING btree (enterprise_id);
CREATE INDEX idx_kb_audit_log_kb_id ON public.kb_audit_log USING btree (kb_id);
CREATE INDEX idx_kb_audit_log_target_user_id ON public.kb_audit_log USING btree (target_user_id);
-- public.knowledge_base definition
-- Drop table
-- DROP TABLE public.knowledge_base;
CREATE TABLE public.knowledge_base (
id serial4 NOT NULL,
user_id int4 NOT NULL,
"name" varchar(255) NOT NULL,
description text NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
updated_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
is_deleted bool DEFAULT false NULL,
deleted_at timestamptz NULL,
enterprise_id int4 DEFAULT 1 NOT NULL,
department_id int4 NULL,
creator_id int4 NULL,
visibility varchar(32) DEFAULT 'private'::character varying NOT NULL,
CONSTRAINT ck_knowledge_base_visibility CHECK (((visibility)::text = ANY ((ARRAY['private'::character varying, 'department'::character varying, 'enterprise'::character varying])::text[]))),
CONSTRAINT knowledge_base_pkey PRIMARY KEY (id)
);
CREATE INDEX idx_knowledge_base_created_at ON public.knowledge_base USING btree (created_at);
CREATE INDEX idx_knowledge_base_creator ON public.knowledge_base USING btree (creator_id);
CREATE INDEX idx_knowledge_base_ent_vis ON public.knowledge_base USING btree (enterprise_id, visibility) WHERE (is_deleted = false);
CREATE INDEX idx_knowledge_base_enterprise ON public.knowledge_base USING btree (enterprise_id);
CREATE INDEX idx_knowledge_base_is_deleted ON public.knowledge_base USING btree (is_deleted);
CREATE INDEX idx_knowledge_base_user_deleted ON public.knowledge_base USING btree (user_id, is_deleted);
CREATE INDEX idx_knowledge_base_user_id ON public.knowledge_base USING btree (user_id);
CREATE INDEX idx_knowledge_base_user_name ON public.knowledge_base USING btree (user_id, name);
CREATE UNIQUE INDEX uk_user_knowledge_base_name_active ON public.knowledge_base USING btree (user_id, name) WHERE (is_deleted = false);
-- public.knowledge_base_chunk definition
-- Drop table
-- DROP TABLE public.knowledge_base_chunk;
CREATE TABLE public.knowledge_base_chunk (
id serial4 NOT NULL,
file_id int4 NOT NULL,
knowledge_base_id int4 NOT NULL,
chunk_index int4 NOT NULL,
"content" text NOT NULL,
metadata jsonb NULL,
vector_id varchar(255) NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
summary text NULL,
CONSTRAINT knowledge_base_chunk_pkey PRIMARY KEY (id)
);
CREATE INDEX idx_kb_chunk_file_id ON public.knowledge_base_chunk USING btree (file_id);
CREATE INDEX idx_kb_chunk_kb_id ON public.knowledge_base_chunk USING btree (knowledge_base_id);
CREATE INDEX idx_kb_chunk_metadata ON public.knowledge_base_chunk USING gin (metadata);
CREATE INDEX idx_kb_chunk_vector_id ON public.knowledge_base_chunk USING btree (vector_id);
-- public.knowledge_base_file definition
-- Drop table
-- DROP TABLE public.knowledge_base_file;
CREATE TABLE public.knowledge_base_file (
id serial4 NOT NULL,
knowledge_base_id int4 NOT NULL,
user_id int4 NOT NULL,
file_name varchar(255) NOT NULL,
file_path varchar(500) NOT NULL,
file_size int8 NOT NULL,
file_type varchar(50) DEFAULT 'pdf'::character varying NOT NULL,
status varchar(20) DEFAULT 'processing'::character varying NOT NULL,
chunk_count int4 DEFAULT 0 NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
updated_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
is_deleted bool DEFAULT false NULL,
deleted_at timestamptz NULL,
CONSTRAINT knowledge_base_file_pkey PRIMARY KEY (id)
);
CREATE INDEX idx_kb_file_created_at ON public.knowledge_base_file USING btree (created_at);
CREATE INDEX idx_kb_file_kb_id ON public.knowledge_base_file USING btree (knowledge_base_id);
CREATE INDEX idx_kb_file_status ON public.knowledge_base_file USING btree (status);
CREATE UNIQUE INDEX idx_kb_file_unique_active ON public.knowledge_base_file USING btree (knowledge_base_id, file_name) WHERE (is_deleted = false);
CREATE INDEX idx_kb_file_user_id ON public.knowledge_base_file USING btree (user_id);
-- public.knowledge_processing_task definition
-- Drop table
-- DROP TABLE public.knowledge_processing_task;
CREATE TABLE public.knowledge_processing_task (
id serial4 NOT NULL,
user_id int4 NOT NULL,
knowledge_base_id int4 NOT NULL,
task_name varchar(255) NOT NULL,
instruction text NOT NULL,
file_ids _int4 NOT NULL,
task_type varchar(50) NOT NULL,
status varchar(20) DEFAULT 'pending'::character varying NULL,
"result" text NULL,
result_file_url text NULL,
error_message text NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
updated_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
started_at timestamptz NULL,
completed_at timestamptz NULL,
CONSTRAINT knowledge_processing_task_pkey PRIMARY KEY (id)
);
CREATE INDEX idx_kb_processing_created_at ON public.knowledge_processing_task USING btree (created_at DESC);
CREATE INDEX idx_kb_processing_kb_id ON public.knowledge_processing_task USING btree (knowledge_base_id);
CREATE INDEX idx_kb_processing_status ON public.knowledge_processing_task USING btree (status);
CREATE INDEX idx_kb_processing_user_id ON public.knowledge_processing_task USING btree (user_id);
CREATE INDEX idx_kb_processing_user_status ON public.knowledge_processing_task USING btree (user_id, status);
-- public.user_list definition
-- Drop table
-- DROP TABLE public.user_list;
CREATE TABLE public.user_list (
id serial4 NOT NULL,
username varchar(50) NOT NULL,
email varchar(255) NOT NULL,
phone varchar(255) NOT NULL,
github_id varchar(100) NULL,
github_username varchar(100) NULL,
github_avatar_url text NULL,
github_access_token text NULL,
github_token_expires_at timestamptz NULL,
display_name varchar(100) NULL,
avatar_url text NULL,
bio text NULL,
is_active bool DEFAULT true NULL,
email_verified bool DEFAULT false NULL,
created_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
updated_at timestamptz DEFAULT CURRENT_TIMESTAMP NULL,
last_login_at timestamptz NULL,
hashed_password varchar(255) NULL,
is_search bool DEFAULT false NULL,
is_reasoner bool DEFAULT false NULL,
enterprise_id int4 DEFAULT 1 NOT NULL,
department_id int4 NULL,
"role" varchar(32) DEFAULT 'employee'::character varying NOT NULL,
is_first_login bool DEFAULT true NOT NULL,
allow_kb_upload bool DEFAULT true NOT NULL,
CONSTRAINT unique_email UNIQUE (email),
CONSTRAINT unique_github_id UNIQUE (github_id),
CONSTRAINT user_list_phone_key UNIQUE (phone),
CONSTRAINT user_list_pkey PRIMARY KEY (id),
CONSTRAINT user_list_username_key UNIQUE (username)
);
CREATE INDEX idx_user_list_created_at ON public.user_list USING btree (created_at);
CREATE INDEX idx_user_list_department_id ON public.user_list USING btree (department_id);
CREATE INDEX idx_user_list_email ON public.user_list USING btree (email);
CREATE INDEX idx_user_list_enterprise_id ON public.user_list USING btree (enterprise_id);
CREATE INDEX idx_user_list_github_id ON public.user_list USING btree (github_id);
CREATE INDEX idx_user_list_role ON public.user_list USING btree (role);
CREATE INDEX idx_user_list_username ON public.user_list USING btree (username);
-- public.chat_message_file foreign keys
ALTER TABLE public.chat_message_file ADD CONSTRAINT fk_chat_message_file_file FOREIGN KEY (file_id) REFERENCES public.chat_thread_file(id) ON DELETE CASCADE;
-- public.chat_thread_chunk foreign keys
ALTER TABLE public.chat_thread_chunk ADD CONSTRAINT fk_chat_thread_chunk_file FOREIGN KEY (file_id) REFERENCES public.chat_thread_file(id) ON DELETE CASCADE;
-- public.chat_thread_file foreign keys
ALTER TABLE public.chat_thread_file ADD CONSTRAINT fk_chat_thread_file_user FOREIGN KEY (user_id) REFERENCES public.user_list(id) ON DELETE CASCADE;
-- public.chat_threads foreign keys
ALTER TABLE public.chat_threads ADD CONSTRAINT fk_chat_threads_knowledge_graph FOREIGN KEY (knowledge_graph_id) REFERENCES public.graphs(id) ON DELETE SET NULL;
ALTER TABLE public.chat_threads ADD CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES public.user_list(id) ON DELETE CASCADE;
-- public.department foreign keys
ALTER TABLE public.department ADD CONSTRAINT department_enterprise_id_fkey FOREIGN KEY (enterprise_id) REFERENCES public.enterprise(id) ON DELETE CASCADE;
ALTER TABLE public.department ADD CONSTRAINT department_leader_user_id_fkey FOREIGN KEY (leader_user_id) REFERENCES public.user_list(id) ON DELETE SET NULL;
ALTER TABLE public.department ADD CONSTRAINT department_parent_id_fkey FOREIGN KEY (parent_id) REFERENCES public.department(id) ON DELETE SET NULL;
-- public.graphs foreign keys
ALTER TABLE public.graphs ADD CONSTRAINT fk_graphs_user FOREIGN KEY (user_id) REFERENCES public.user_list(id) ON DELETE CASCADE;
ALTER TABLE public.graphs ADD CONSTRAINT graphs_creator_id_fkey FOREIGN KEY (creator_id) REFERENCES public.user_list(id) ON DELETE SET NULL;
ALTER TABLE public.graphs ADD CONSTRAINT graphs_department_id_fkey FOREIGN KEY (department_id) REFERENCES public.department(id) ON DELETE SET NULL;
ALTER TABLE public.graphs ADD CONSTRAINT graphs_enterprise_id_fkey FOREIGN KEY (enterprise_id) REFERENCES public.enterprise(id);
-- public.kb_audit_log foreign keys
ALTER TABLE public.kb_audit_log ADD CONSTRAINT kb_audit_log_actor_id_fkey FOREIGN KEY (actor_id) REFERENCES public.user_list(id) ON DELETE CASCADE;
ALTER TABLE public.kb_audit_log ADD CONSTRAINT kb_audit_log_department_id_fkey FOREIGN KEY (department_id) REFERENCES public.department(id) ON DELETE SET NULL;
ALTER TABLE public.kb_audit_log ADD CONSTRAINT kb_audit_log_enterprise_id_fkey FOREIGN KEY (enterprise_id) REFERENCES public.enterprise(id) ON DELETE CASCADE;
ALTER TABLE public.kb_audit_log ADD CONSTRAINT kb_audit_log_file_id_fkey FOREIGN KEY (file_id) REFERENCES public.knowledge_base_file(id) ON DELETE SET NULL;
ALTER TABLE public.kb_audit_log ADD CONSTRAINT kb_audit_log_kb_id_fkey FOREIGN KEY (kb_id) REFERENCES public.knowledge_base(id) ON DELETE SET NULL;
ALTER TABLE public.kb_audit_log ADD CONSTRAINT kb_audit_log_target_user_id_fkey FOREIGN KEY (target_user_id) REFERENCES public.user_list(id) ON DELETE SET NULL;
-- public.knowledge_base foreign keys
ALTER TABLE public.knowledge_base ADD CONSTRAINT knowledge_base_creator_id_fkey FOREIGN KEY (creator_id) REFERENCES public.user_list(id) ON DELETE CASCADE;
ALTER TABLE public.knowledge_base ADD CONSTRAINT knowledge_base_department_id_fkey FOREIGN KEY (department_id) REFERENCES public.department(id) ON DELETE SET NULL;
ALTER TABLE public.knowledge_base ADD CONSTRAINT knowledge_base_enterprise_id_fkey FOREIGN KEY (enterprise_id) REFERENCES public.enterprise(id);
-- public.knowledge_base_chunk foreign keys
ALTER TABLE public.knowledge_base_chunk ADD CONSTRAINT fk_kb FOREIGN KEY (knowledge_base_id) REFERENCES public.knowledge_base(id) ON DELETE CASCADE;
ALTER TABLE public.knowledge_base_chunk ADD CONSTRAINT fk_kb_file FOREIGN KEY (file_id) REFERENCES public.knowledge_base_file(id) ON DELETE CASCADE;
-- public.knowledge_base_file foreign keys
ALTER TABLE public.knowledge_base_file ADD CONSTRAINT fk_knowledge_base FOREIGN KEY (knowledge_base_id) REFERENCES public.knowledge_base(id) ON DELETE CASCADE;
-- public.knowledge_processing_task foreign keys
ALTER TABLE public.knowledge_processing_task ADD CONSTRAINT fk_kb_processing_kb FOREIGN KEY (knowledge_base_id) REFERENCES public.knowledge_base(id) ON DELETE CASCADE;
ALTER TABLE public.knowledge_processing_task ADD CONSTRAINT fk_kb_processing_user FOREIGN KEY (user_id) REFERENCES public.user_list(id) ON DELETE CASCADE;
-- public.user_list foreign keys
ALTER TABLE public.user_list ADD CONSTRAINT user_list_department_id_fkey FOREIGN KEY (department_id) REFERENCES public.department(id) ON DELETE SET NULL;
ALTER TABLE public.user_list ADD CONSTRAINT user_list_enterprise_id_fkey FOREIGN KEY (enterprise_id) REFERENCES public.enterprise(id);

101
readme.md Normal file
View File

@ -0,0 +1,101 @@
# 如何部署 Backend
本仓库的 HTTP API 由 `backend/` 目录下的 **FastAPI** 服务提供,`frontend` 与 `admin-frontend` 均请求同一套后端接口。
---
## 一、环境准备
### 1.1 运行环境
| 组件 | 版本 / 说明 |
|------|-------------|
| Python | **3.11**(与 `backend/pyproject.toml``requires-python` 一致) |
| 包管理 | 推荐 [uv](https://docs.astral.sh/uv/)(项目含 `uv.lock` |
| PostgreSQL | **14+**(主库,必选) |
| Redis | **6+**(短信验证码、图形验证码等,可选) |
| ChromaDB | 向量检索(知识库 RAG按业务需要部署必选 |
| Neo4j | 知识图谱(按业务需要部署,必选) |
---
## 二、数据库初始化
后端依赖 PostgreSQL。首次部署请在**空库**上执行项目根目录的初始化脚本:
`ddl-init.sql` 会创建完整表结构
初始化完成后,在 `backend/.env` 中配置与上述库一致的数据库连接(见下文)。
---
## 三、配置环境变量
`backend/` 目录复制示例配置并修改:
```bash
cd backend
cp .env.example .env
```
至少修改以下项(生产环境务必使用强密码与随机 `JWT_SECRET_KEY`
| 变量 | 说明 |
|------|------|
| `API.HOST` / `API.PORT` | 监听地址与端口(默认 `0.0.0.0:7862` |
| `DB_HOST`、`DB_PORT`、`DB_NAME`、`DB_USER`、`DB_PASSWORD` | PostgreSQL需与 `ddl-init.sql` 执行的库一致 |
| `JWT_SECRET_KEY` | JWT 签名密钥 |
| `REDIS_HOST`、`REDIS_PORT` | Redis未在 `.env.example` 列出时,默认 `127.0.0.1:6379`,可在 `.env` 中显式配置) |
| `CHROMA_HOST`、`CHROMA_PORT` | ChromaDB 地址(启用知识库向量检索时) |
| `NEO4J_URI`、`NEO4J_USER`、`NEO4J_PASSWORD` | Neo4j启用知识图谱时 |
| `DASHSCOPE_API_KEY` / `DEEPSEEK_API_KEY` 等 | 大模型与 Embedding聊天、RAG 必需) |
| `OSS_*` | 阿里云 OSS文件上传按需 |
| `MODERATION_ENABLED` | 内容审核;关闭时可不配置阿里云审核密钥 |
完整字段说明见 `backend/.env.example``backend/core/config.py`
---
## 四、本地部署(推荐开发 / 单机生产)
### 4.1 安装依赖
```bash
cd backend
uv sync --frozen
```
仅安装生产依赖(与 Docker 构建一致):
```bash
uv sync --frozen --no-dev
```
### 4.2 启动服务
**`backend` 目录**下执行(会读取 `backend/.env` 中的 `API.HOST` / `API.PORT`
```bash
uv run python -m main
```
开发热重载(同样需在 `backend` 目录):
```bash
uv run python -m main
# 或显式指定端口(须与 .env 中 API.PORT 一致)
uv run uvicorn main:app --reload --host 0.0.0.0 --port 7862
```
> **注意**:若直接运行 `uvicorn main:app` 且未传 `--port`,默认端口为 **8000**,不会自动读取 `.env` 中的 `API.PORT`。生产环境请使用 `python -m main` 或显式传入 `--port`
### 4.3 验证
- 健康:查看启动日志中是否有「数据库健康检查通过」
- API 文档:浏览器打开 `http://<主机>:<端口>/docs`(根路径 `/` 会重定向到 Swagger
- 管理端接口:前缀为 `/api/admin/...`,需 `role=admin` 用户登录后携带 JWT
---

675
sql.txt
View File

@ -1,675 +0,0 @@
create table public.chat_messages
(
id serial
primary key,
thread_id varchar(255) not null,
checkpoint_id varchar(255) not null,
message_index integer not null,
role varchar(20) not null,
content text not null,
injected_content text,
has_files boolean default false,
metadata jsonb,
created_at timestamp with time zone default CURRENT_TIMESTAMP,
name varchar(255),
constraint uk_checkpoint_message
unique (checkpoint_id, message_index)
);
comment on table public.chat_messages is '聊天消息表存储用户原始消息和AI响应的关键信息';
comment on column public.chat_messages.thread_id is '会话线程ID';
comment on column public.chat_messages.checkpoint_id is '关联的checkpoint ID';
comment on column public.chat_messages.message_index is '消息在checkpoint中的索引从0开始';
comment on column public.chat_messages.role is '消息角色user、assistant、system、tool';
comment on column public.chat_messages.content is '用户的原始问题或AI的响应';
comment on column public.chat_messages.injected_content is '注入给AI的完整内容包含文件内容';
comment on column public.chat_messages.has_files is '是否关联了文件';
comment on column public.chat_messages.metadata is '额外信息token、模型、推理内容等';
comment on column public.chat_messages.name is '工具消息时的工具名称(如 internet_search、text_to_image';
alter table public.chat_messages
owner to zuoleiroot;
create index idx_chat_messages_thread_id
on public.chat_messages (thread_id);
create index idx_chat_messages_checkpoint_id
on public.chat_messages (checkpoint_id);
create index idx_chat_messages_thread_created
on public.chat_messages (thread_id asc, created_at desc);
create index idx_chat_messages_role
on public.chat_messages (role);
create index idx_chat_messages_has_files
on public.chat_messages (has_files);
create index idx_chat_messages_metadata
on public.chat_messages using gin (metadata);
create index idx_chat_messages_content_search
on public.chat_messages using gin (to_tsvector('simple'::regconfig, content));
create table public.checkpoint_migrations
(
v integer not null
primary key
);
alter table public.checkpoint_migrations
owner to zuoleiroot;
create table public.checkpoints
(
thread_id text not null,
checkpoint_ns text default ''::text not null,
checkpoint_id text not null,
parent_checkpoint_id text,
type text,
checkpoint jsonb not null,
metadata jsonb default '{}'::jsonb not null,
primary key (thread_id, checkpoint_ns, checkpoint_id)
);
alter table public.checkpoints
owner to zuoleiroot;
create index checkpoints_thread_id_idx
on public.checkpoints (thread_id);
create table public.checkpoint_blobs
(
thread_id text not null,
checkpoint_ns text default ''::text not null,
channel text not null,
version text not null,
type text not null,
blob bytea,
primary key (thread_id, checkpoint_ns, channel, version)
);
alter table public.checkpoint_blobs
owner to zuoleiroot;
create index checkpoint_blobs_thread_id_idx
on public.checkpoint_blobs (thread_id);
create table public.checkpoint_writes
(
thread_id text not null,
checkpoint_ns text default ''::text not null,
checkpoint_id text not null,
task_id text not null,
idx integer not null,
channel text not null,
type text,
blob bytea not null,
task_path text default ''::text not null,
primary key (thread_id, checkpoint_ns, checkpoint_id, task_id, idx)
);
alter table public.checkpoint_writes
owner to zuoleiroot;
create index checkpoint_writes_thread_id_idx
on public.checkpoint_writes (thread_id);
create table public.enterprise
(
id serial
primary key,
name varchar(255) not null,
code varchar(64)
unique,
created_at timestamp with time zone default CURRENT_TIMESTAMP not null,
updated_at timestamp with time zone default CURRENT_TIMESTAMP not null
);
comment on table public.enterprise is '企业(单租户部署通常仅一条记录)';
alter table public.enterprise
owner to zuoleiroot;
create table public.department
(
id serial
primary key,
enterprise_id integer not null
references public.enterprise
on delete cascade,
name varchar(255) not null,
parent_id integer
references public.department
on delete set null,
created_at timestamp with time zone default CURRENT_TIMESTAMP not null,
updated_at timestamp with time zone default CURRENT_TIMESTAMP not null,
constraint uq_department_enterprise_name
unique (enterprise_id, name)
);
comment on table public.department is '部门';
alter table public.department
owner to zuoleiroot;
create table public.user_list
(
id serial
primary key,
username varchar(50) not null
unique,
email varchar(255) not null
constraint unique_email
unique,
phone varchar(255) not null
unique,
github_id varchar(100)
constraint unique_github_id
unique,
github_username varchar(100),
github_avatar_url text,
github_access_token text,
github_token_expires_at timestamp with time zone,
display_name varchar(100),
avatar_url text,
bio text,
is_active boolean default true,
email_verified boolean default false,
created_at timestamp with time zone default CURRENT_TIMESTAMP,
updated_at timestamp with time zone default CURRENT_TIMESTAMP,
last_login_at timestamp with time zone,
hashed_password varchar(255),
is_search boolean default false,
is_reasoner boolean default false,
enterprise_id integer default 1 not null
references public.enterprise,
department_id integer
references public.department
on delete set null,
role varchar(32) default 'employee'::character varying not null,
is_first_login boolean default true not null
);
comment on column public.user_list.role is 'admin | leader | employee';
comment on column public.user_list.is_first_login is '首次登录可强制改密(可选业务)';
alter table public.user_list
owner to zuoleiroot;
create index idx_user_list_github_id
on public.user_list (github_id);
create index idx_user_list_email
on public.user_list (email);
create index idx_user_list_username
on public.user_list (username);
create index idx_user_list_created_at
on public.user_list (created_at);
create index idx_user_list_enterprise_id
on public.user_list (enterprise_id);
create index idx_user_list_department_id
on public.user_list (department_id);
create index idx_user_list_role
on public.user_list (role);
create table public.knowledge_base
(
id serial
primary key,
user_id integer not null,
name varchar(255) not null,
description text,
created_at timestamp with time zone default CURRENT_TIMESTAMP,
updated_at timestamp with time zone default CURRENT_TIMESTAMP,
is_deleted boolean default false,
deleted_at timestamp with time zone,
enterprise_id integer default 1 not null
references public.enterprise,
department_id integer
references public.department
on delete set null,
creator_id integer not null
references public.user_list
on delete set null,
visibility varchar(32) default 'private'::character varying not null
constraint ck_knowledge_base_visibility
check ((visibility)::text = ANY
((ARRAY ['private'::character varying, 'department'::character varying, 'enterprise'::character varying])::text[]))
);
comment on column public.knowledge_base.creator_id is '创建者(与 user_id 通常一致,用于权限判断)';
comment on column public.knowledge_base.visibility is 'private | department | enterprise';
alter table public.knowledge_base
owner to zuoleiroot;
create index idx_knowledge_base_user_id
on public.knowledge_base (user_id);
create index idx_knowledge_base_user_name
on public.knowledge_base (user_id, name);
create index idx_knowledge_base_created_at
on public.knowledge_base (created_at);
create index idx_knowledge_base_is_deleted
on public.knowledge_base (is_deleted);
create index idx_knowledge_base_user_deleted
on public.knowledge_base (user_id, is_deleted);
create unique index uk_user_knowledge_base_name_active
on public.knowledge_base (user_id, name)
where (is_deleted = false);
create index idx_knowledge_base_enterprise
on public.knowledge_base (enterprise_id);
create index idx_knowledge_base_creator
on public.knowledge_base (creator_id);
create index idx_knowledge_base_ent_vis
on public.knowledge_base (enterprise_id, visibility)
where (is_deleted = false);
create table public.knowledge_base_file
(
id serial
primary key,
knowledge_base_id integer not null
constraint fk_knowledge_base
references public.knowledge_base
on delete cascade,
user_id integer not null,
file_name varchar(255) not null,
file_path varchar(500) not null,
file_size bigint not null,
file_type varchar(50) default 'pdf'::character varying not null,
status varchar(20) default 'processing'::character varying not null,
chunk_count integer default 0,
created_at timestamp with time zone default CURRENT_TIMESTAMP,
updated_at timestamp with time zone default CURRENT_TIMESTAMP,
is_deleted boolean default false,
deleted_at timestamp with time zone
);
alter table public.knowledge_base_file
owner to zuoleiroot;
create index idx_kb_file_kb_id
on public.knowledge_base_file (knowledge_base_id);
create index idx_kb_file_user_id
on public.knowledge_base_file (user_id);
create index idx_kb_file_status
on public.knowledge_base_file (status);
create index idx_kb_file_created_at
on public.knowledge_base_file (created_at);
create unique index idx_kb_file_unique_active
on public.knowledge_base_file (knowledge_base_id, file_name)
where (is_deleted = false);
create table public.knowledge_base_chunk
(
id serial
primary key,
file_id integer not null
constraint fk_kb_file
references public.knowledge_base_file
on delete cascade,
knowledge_base_id integer not null
constraint fk_kb
references public.knowledge_base
on delete cascade,
chunk_index integer not null,
content text not null,
metadata jsonb,
vector_id varchar(255),
created_at timestamp with time zone default CURRENT_TIMESTAMP,
summary text
);
alter table public.knowledge_base_chunk
owner to zuoleiroot;
create index idx_kb_chunk_file_id
on public.knowledge_base_chunk (file_id);
create index idx_kb_chunk_kb_id
on public.knowledge_base_chunk (knowledge_base_id);
create index idx_kb_chunk_vector_id
on public.knowledge_base_chunk (vector_id);
create index idx_kb_chunk_metadata
on public.knowledge_base_chunk using gin (metadata);
create table public.chat_thread_file
(
id serial
primary key,
thread_id varchar(255) not null,
user_id integer not null
constraint fk_chat_thread_file_user
references public.user_list
on delete cascade,
file_name varchar(255) not null,
file_path varchar(500) not null,
file_size integer default 0,
file_type varchar(50) default 'pdf'::character varying,
status varchar(20) default 'processing'::character varying,
chunk_count integer default 0,
created_at timestamp with time zone default CURRENT_TIMESTAMP,
updated_at timestamp with time zone default CURRENT_TIMESTAMP,
is_deleted boolean default false,
deleted_at timestamp with time zone
);
alter table public.chat_thread_file
owner to zuoleiroot;
create index idx_chat_thread_file_thread_id
on public.chat_thread_file (thread_id);
create index idx_chat_thread_file_user_id
on public.chat_thread_file (user_id);
create index idx_chat_thread_file_thread_user
on public.chat_thread_file (thread_id, user_id);
create index idx_chat_thread_file_status
on public.chat_thread_file (status);
create index idx_chat_thread_file_is_deleted
on public.chat_thread_file (is_deleted);
create index idx_chat_thread_file_created_at
on public.chat_thread_file (created_at);
create index idx_chat_thread_file_thread_deleted
on public.chat_thread_file (thread_id, is_deleted);
create unique index uk_chat_thread_file_thread_name_active
on public.chat_thread_file (thread_id, file_name)
where (is_deleted = false);
create table public.chat_thread_chunk
(
id serial
primary key,
file_id integer not null
constraint fk_chat_thread_chunk_file
references public.chat_thread_file
on delete cascade,
thread_id varchar(255) not null,
chunk_index integer not null,
content text not null,
metadata jsonb,
vector_id varchar(255),
created_at timestamp with time zone default CURRENT_TIMESTAMP,
summary text
);
alter table public.chat_thread_chunk
owner to zuoleiroot;
create index idx_chat_thread_chunk_file_id
on public.chat_thread_chunk (file_id);
create index idx_chat_thread_chunk_thread_id
on public.chat_thread_chunk (thread_id);
create index idx_chat_thread_chunk_file_thread
on public.chat_thread_chunk (file_id, thread_id);
create index idx_chat_thread_chunk_vector_id
on public.chat_thread_chunk (vector_id);
create index idx_chat_thread_chunk_created_at
on public.chat_thread_chunk (created_at);
create table public.chat_message_file
(
id serial
primary key,
thread_id varchar(255) not null,
checkpoint_id varchar(255) not null,
message_index integer not null,
file_id integer not null
constraint fk_chat_message_file_file
references public.chat_thread_file
on delete cascade,
created_at timestamp with time zone default CURRENT_TIMESTAMP,
constraint uk_message_file
unique (checkpoint_id, message_index, file_id)
);
alter table public.chat_message_file
owner to zuoleiroot;
create index idx_chat_message_file_thread_id
on public.chat_message_file (thread_id);
create index idx_chat_message_file_checkpoint
on public.chat_message_file (checkpoint_id, message_index);
create index idx_chat_message_file_file_id
on public.chat_message_file (file_id);
create index idx_chat_message_file_thread_checkpoint
on public.chat_message_file (thread_id, checkpoint_id);
create table public.graphs
(
id serial
primary key,
user_id integer not null
constraint fk_graphs_user
references public.user_list
on delete cascade,
name varchar(255) not null,
description text,
csv_file_name varchar(255),
node_count integer default 0,
edge_count integer default 0,
neo4j_graph_id varchar(100) not null
unique,
graph_type varchar(20) default 'knowledge'::character varying not null,
build_status varchar(20),
build_error text,
rag_chunk_count integer default 0 not null,
created_at timestamp with time zone default CURRENT_TIMESTAMP,
updated_at timestamp with time zone default CURRENT_TIMESTAMP,
enterprise_id integer not null
references public.enterprise,
department_id integer
references public.department
on delete set null,
creator_id integer not null
references public.user_list
on delete set null,
visibility varchar(32) default 'private'::character varying not null
constraint ck_graphs_visibility
check ((visibility)::text = ANY
((ARRAY ['private'::character varying, 'department'::character varying, 'enterprise'::character varying])::text[]))
);
comment on table public.graphs is '知识图谱元数据表,图数据在 Neo4j向量块数量见 rag_chunk_count';
comment on column public.graphs.neo4j_graph_id is 'Neo4j 中图谱唯一标识';
comment on column public.graphs.graph_type is '兼容字段,默认 knowledge';
comment on column public.graphs.build_status is '构建状态pending/processing/completed/failed';
comment on column public.graphs.build_error is '构建失败时的错误信息';
comment on column public.graphs.rag_chunk_count is 'Chroma 中知识图谱 RAG 分块数量';
comment on column public.graphs.creator_id is '创建者(与 user_id 通常一致,用于权限判断)';
comment on column public.graphs.visibility is 'private | department | enterprise';
alter table public.graphs
owner to zuoleiroot;
create index idx_graphs_user_id
on public.graphs (user_id);
create index idx_graphs_created_at
on public.graphs (created_at desc);
create index idx_graphs_neo4j_id
on public.graphs (neo4j_graph_id);
create index idx_graphs_graph_type
on public.graphs (user_id, graph_type);
create index idx_graphs_enterprise
on public.graphs (enterprise_id);
create index idx_graphs_creator
on public.graphs (creator_id);
create index idx_graphs_ent_vis
on public.graphs (enterprise_id, visibility);
create table public.chat_threads
(
id serial
primary key,
thread_id varchar(255) not null
constraint uk_thread_id
unique,
user_id integer not null
constraint fk_user_id
references public.user_list
on delete cascade,
title varchar(50) not null,
first_query text not null,
created_at timestamp with time zone default CURRENT_TIMESTAMP,
updated_at timestamp with time zone default CURRENT_TIMESTAMP,
message_count integer default 1,
is_deleted boolean default false,
knowledge_base_id integer,
novel_graph_id integer,
knowledge_graph_id integer
constraint fk_chat_threads_knowledge_graph
references public.graphs
on delete set null,
ip varchar(128)
);
comment on table public.chat_threads is '聊天会话记录表,记录每个用户的会话基本信息';
comment on column public.chat_threads.id is '主键 ID';
comment on column public.chat_threads.thread_id is '会话线程 IDUUID 格式)';
comment on column public.chat_threads.user_id is '用户 ID关联 user_list 表';
comment on column public.chat_threads.title is '会话标题首次请求内容的前10个字';
comment on column public.chat_threads.first_query is '首次请求的完整内容';
comment on column public.chat_threads.created_at is '会话创建时间';
comment on column public.chat_threads.updated_at is '最后更新时间';
comment on column public.chat_threads.message_count is '该会话的消息总数';
comment on column public.chat_threads.is_deleted is '是否已删除(软删除标记)';
comment on column public.chat_threads.knowledge_graph_id is '绑定的知识图谱 graphs.id与 knowledge_base_id 二选一';
comment on column public.chat_threads.ip is '最近一次发起聊天时的客户端 IP可选';
alter table public.chat_threads
owner to zuoleiroot;
create index idx_chat_threads_user_id
on public.chat_threads (user_id);
create index idx_chat_threads_created_at
on public.chat_threads (created_at desc);
create index idx_chat_threads_user_created
on public.chat_threads (user_id asc, created_at desc);
create index idx_chat_threads_novel_graph_id
on public.chat_threads (novel_graph_id);
create index idx_chat_threads_knowledge_graph_id
on public.chat_threads (knowledge_graph_id);
create table public.knowledge_processing_task
(
id serial
primary key,
user_id integer not null
constraint fk_kb_processing_user
references public.user_list
on delete cascade,
knowledge_base_id integer not null
constraint fk_kb_processing_kb
references public.knowledge_base
on delete cascade,
task_name varchar(255) not null,
instruction text not null,
file_ids integer[] not null,
task_type varchar(50) not null,
status varchar(20) default 'pending'::character varying,
result text,
result_file_url text,
error_message text,
created_at timestamp with time zone default CURRENT_TIMESTAMP,
updated_at timestamp with time zone default CURRENT_TIMESTAMP,
started_at timestamp with time zone,
completed_at timestamp with time zone
);
comment on table public.knowledge_processing_task is '知识加工任务表:合并、对比、总结等异步任务';
comment on column public.knowledge_processing_task.result_file_url is '加工结果文件的 OSS 下载链接';
alter table public.knowledge_processing_task
owner to zuoleiroot;
create index idx_kb_processing_user_id
on public.knowledge_processing_task (user_id);
create index idx_kb_processing_kb_id
on public.knowledge_processing_task (knowledge_base_id);
create index idx_kb_processing_status
on public.knowledge_processing_task (status);
create index idx_kb_processing_created_at
on public.knowledge_processing_task (created_at desc);
create index idx_kb_processing_user_status
on public.knowledge_processing_task (user_id, status);
create index idx_department_enterprise_id
on public.department (enterprise_id);

View File

@ -1,11 +0,0 @@
# Test your FastAPI endpoints
GET http://127.0.0.1:8000/
Accept: application/json
###
GET http://127.0.0.1:8000/hello/User
Accept: application/json
###

View File

@ -1,73 +0,0 @@
-- ================================================================
-- 权限方案 A 升级 DDL在已有表结构基础上执行
-- 执行顺序:按文件从上到下顺序执行
-- ================================================================
-- ------------------------------------------------------------
-- 1. department新增部门负责人字段
-- ------------------------------------------------------------
ALTER TABLE public.department
ADD COLUMN IF NOT EXISTS leader_user_id INTEGER
REFERENCES public.user_list(id) ON DELETE SET NULL;
COMMENT ON COLUMN public.department.leader_user_id IS '部门负责人 user_id对应 role=leader 的用户';
CREATE INDEX IF NOT EXISTS idx_department_leader_user_id
ON public.department (leader_user_id);
-- ------------------------------------------------------------
-- 2. user_list新增「是否允许上传文件到知识库」开关
-- ------------------------------------------------------------
ALTER TABLE public.user_list
ADD COLUMN IF NOT EXISTS allow_kb_upload BOOLEAN NOT NULL DEFAULT TRUE;
COMMENT ON COLUMN public.user_list.allow_kb_upload IS '是否允许上传文件到知识库(上级领导或 admin 可关闭)';
-- ------------------------------------------------------------
-- 3. kb_audit_log知识库操作审计日志表新建
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS public.kb_audit_log
(
id SERIAL PRIMARY KEY,
enterprise_id INTEGER NOT NULL
REFERENCES public.enterprise ON DELETE CASCADE,
actor_id INTEGER NOT NULL
REFERENCES public.user_list (id) ON DELETE CASCADE,
target_user_id INTEGER
REFERENCES public.user_list (id) ON DELETE SET NULL,
department_id INTEGER
REFERENCES public.department (id) ON DELETE SET NULL,
kb_id INTEGER
REFERENCES public.knowledge_base (id) ON DELETE SET NULL,
file_id INTEGER
REFERENCES public.knowledge_base_file (id) ON DELETE SET NULL,
action VARCHAR(50) NOT NULL,
-- upload | download | delete | archive | create_kb | delete_kb | permission_change
ip VARCHAR(128),
user_agent TEXT,
metadata JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL
);
COMMENT ON TABLE public.kb_audit_log IS '知识库操作审计日志';
COMMENT ON COLUMN public.kb_audit_log.action IS
'upload | download | delete | archive | create_kb | delete_kb | permission_change';
CREATE INDEX IF NOT EXISTS idx_kb_audit_log_enterprise_id
ON public.kb_audit_log (enterprise_id);
CREATE INDEX IF NOT EXISTS idx_kb_audit_log_actor_id
ON public.kb_audit_log (actor_id);
CREATE INDEX IF NOT EXISTS idx_kb_audit_log_target_user_id
ON public.kb_audit_log (target_user_id);
CREATE INDEX IF NOT EXISTS idx_kb_audit_log_department_id
ON public.kb_audit_log (department_id);
CREATE INDEX IF NOT EXISTS idx_kb_audit_log_kb_id
ON public.kb_audit_log (kb_id);
CREATE INDEX IF NOT EXISTS idx_kb_audit_log_action
ON public.kb_audit_log (action);
CREATE INDEX IF NOT EXISTS idx_kb_audit_log_created_at
ON public.kb_audit_log (created_at DESC);
CREATE INDEX IF NOT EXISTS idx_kb_audit_log_ent_dept_created
ON public.kb_audit_log (enterprise_id, department_id, created_at DESC);
ALTER TABLE public.kb_audit_log OWNER TO zuoleiroot;