DocHub/docs/superpowers/specs/2026-08-01-dochub-design.md
2026-08-01 00:22:16 +08:00

154 lines
7.6 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.

# DocHub 设计文档
## 背景与目标
小团队10 人以下)需要一个基于 MinIO 的文档管理系统,支持:
- 浏览 MinIO 中存储的文档(主要是 Markdown / HTML图片为次要内容
- 全文内容检索(不只是文件名搜索)
- 在线编辑文档内容并保存
- 上传新文档
无需用户登录和权限管理(内部工具,信任团队内所有成员)。
## 技术栈
| 层 | 选型 | 理由 |
|----|------|------|
| 前端 | React + Vite + Monaco Editor | Monaco 提供代码级编辑体验(语法高亮、查找替换),适合 Markdown/HTML 源码编辑 |
| 后端 | Python + FastAPI | 团队熟悉度高,异步 IO 足够应对 MinIO/Meilisearch 网络调用瓶颈生态利于后续扩展文档解析、AI 摘要等) |
| 存储 | MinIO独立部署 | S3 兼容对象存储,文档内容和元数据(大小/时间/路径)都存在这里,不引入额外数据库 |
| 检索 | Meilisearch | 轻量、内置中文分词、MIT 协议、Docker 一条命令部署,检索延迟低 |
明确不引入的组件:
- 关系型数据库(内容和元数据用 MinIO 承载,索引用 Meilisearch 承载,当前需求下够用)
- 用户认证/权限系统(团队内部工具,暂不需要)
## 架构
```
┌─────────────┐
HTTPS │ nginx │
───────────▶ │ (反向代理) │
└──────┬──────┘
┌────────────┼────────────┐
▼ ▼ ▼
app.domain api.domain minio.domain(可选)
│ │
┌───────▼───────┐ ┌──▼──────────────┐
│ React 前端 │ │ FastAPI 后端 │
│ Vite + Monaco│ │ (Python) │
└───────────────┘ └───┬──────────┬───┘
│ │
S3 API │ │ REST API
▼ ▼
┌─────────────┐ ┌──────────────┐
│ MinIO │ │ Meilisearch │
│ (独立部署) │ │ (与后端同机) │
└─────────────┘ └──────────────┘
```
**部署形态**:两套独立的 docker-compose各自独立生命周期
- `minio/docker-compose.yml` — 仅 MinIO独立服务器或独立栈长期稳定运行可被其他项目复用
- `app/docker-compose.yml` — frontend + backend + meilisearch可整体重启/升级而不影响已存储的数据
两套 compose 之间通过共享 Docker 网络或宿主机 IP 通信(后端配置 MinIO endpoint 即可,代码不感知部署形态差异,因为走的是标准 S3 API
**域名与端口**:通过 nginx 反向代理 + 子域名区分服务,无需在域名上绑定端口:
```
app.domain → React 前端
api.domain → FastAPI 后端
minio.domain → MinIO 控制台(可选对外)
```
Meilisearch 仅供后端内网访问,不对外暴露子域名。
## 数据流
**上传文档**
```
前端上传文件 → 后端 PUT 到 MinIO
→ 后端解析内容Markdown/HTML 转纯文本)
→ 推送索引到 Meilisearch
→ 返回成功
```
**浏览文件列表**
```
前端请求文件树 → 后端调用 MinIO ListObjects → 返回文件夹/文件结构
```
**查看/编辑文档**
```
点击文件 → 后端从 MinIO GetObject 取内容 → 前端 Monaco Editor 加载展示
保存编辑 → 后端覆盖写入 MinIO → 同步更新 Meilisearch 索引
```
**全局搜索**
```
输入关键词 → 后端转发查询到 Meilisearch
→ 返回匹配文档(含高亮片段)
→ 前端展示结果列表,点击跳转到对应文档
```
**删除文档**
```
后端从 MinIO 删除对象 → 同步从 Meilisearch 删除对应索引
```
**关键决策:索引更新采用后端同步处理**,即写完 MinIO 后立即在同一请求中更新 Meilisearch 索引,不引入 MinIO webhook 异步机制。理由:团队规模小、写入量低,同步更新逻辑更简单、更容易保证一致性,避免维护额外的 webhook 消费者服务。
## 模块设计
### 前端React + Vite + Monaco Editor
| 组件 | 职责 |
|------|------|
| `FileExplorer` | 左侧文件树,展示文件夹/文件,支持点击导航 |
| `DocumentViewer/Editor` | 主区域,用 Monaco 加载文档内容,支持编辑与保存 |
| `SearchBar` | 顶部全局搜索框输入即查debounce |
| `SearchResults` | 搜索结果列表,展示高亮匹配片段,点击跳转对应文档 |
| `UploadButton` | 拖拽或选择文件上传 |
| `apiClient` | 封装对后端的 fetch 调用documents CRUD + search是前端与后端之间的唯一边界 |
### 后端FastAPI
API 层:
| 接口 | 方法 | 职责 |
|------|------|------|
| `/api/documents` | GET | 列出文件树(基于 MinIO ListObjects |
| `/api/documents/{key}` | GET | 读取单个文档内容 |
| `/api/documents/{key}` | PUT | 创建/覆盖文档(写 MinIO + 更新索引) |
| `/api/documents/{key}` | DELETE | 删除文档(删 MinIO + 删索引) |
| `/api/upload` | POST | 处理文件上传multipart |
| `/api/search` | GET | 转发查询到 Meilisearch返回结果 |
内部模块划分(各模块单一职责,可独立测试):
- `minio_client.py` — 封装 MinIO 操作list/get/put/delete只负责与 MinIO 交互,不含业务逻辑
- `search_client.py` — 封装 Meilisearch 操作index/update/delete/search只负责与 Meilisearch 交互
- `document_service.py` — 业务逻辑层,协调 `minio_client``search_client`(保存文档先写 MinIO 再更新索引;删除时顺序相反),并负责 Markdown/HTML 转纯文本供索引使用
- `routes/documents.py`、`routes/search.py` — API 路由层,只做参数校验和调用 service不直接触碰 MinIO/Meilisearch 客户端
依赖方向:`routes` → `document_service``minio_client` / `search_client`。上层不了解下层实现细节,替换 MinIO 为其他 S3 兼容存储或替换 Meilisearch 为其他搜索引擎时,只需改动对应的 client 模块。
## 错误处理
- MinIO 写入成功但索引更新失败:记录日志,不阻塞用户操作(文档已保存成功),后续可手动触发全量重建索引
- 请求的文档不存在:返回 404
- 上传文件类型/大小校验:在后端 `document_service` 层做校验(限制非文档类型或超大文件),拒绝时返回明确错误信息
## 测试策略
- 后端pytest 测试 `document_service` 业务逻辑mock `minio_client``search_client`,覆盖保存/删除时序、索引失败降级等场景
- 前端:暂不强制要求自动化测试覆盖(小型内部工具,手动验证优先级更高)
## 部署资源参考
学习/小团队场景下DocHub 各服务的大致资源占用(供部署规划参考,非强制要求):
- MinIO约 256-512MB 内存
- Meilisearch约 512MB-1GB 内存(随索引文档量增长)
- FastAPI 后端:约 256-512MB 内存
- React/nginx 前端:约 128-256MB 内存
4 核 / 4GB 内存足以运行 DocHub 全部服务;若与其他自建服务(如 Gitea、数据库共享同一台机器建议预留合计 8GB 以上内存。