117 lines
4.5 KiB
Markdown
117 lines
4.5 KiB
Markdown
# Docs Gatekeeper 开发说明
|
||
|
||
Docs Gatekeeper 把 `/docs` 从“前端构建时打包所有 Markdown”改成“后端按权限返回目录和正文”。它的目标是让公开使用手册、用户文档、开发文档和管理/运维文档在同一个 Docs 页面内可检索,但正文读取必须经过服务端白名单和用户权限检查。
|
||
|
||
用户侧说明见 [Planet 使用手册](/home/ray/dev/linkong/planet/docs/technical/zh/manual.md) 的 Docs 章节。
|
||
|
||
## 鉴权模型
|
||
|
||
Docs 使用两层权限:
|
||
|
||
- `users.role`:保留给控制台系统权限。
|
||
- `users.gatekeeper_groups`:Docs 内容权限组。
|
||
|
||
权限组:
|
||
|
||
| 组 | 用途 |
|
||
| --- | --- |
|
||
| `docs_user` | 用户操作类文档 |
|
||
| `docs_developer` | Earth、前端、后端、采集器和 AI Provider 开发文档 |
|
||
| `docs_admin` | 服务控制、运维、环境变量和敏感操作文档 |
|
||
|
||
继承规则:
|
||
|
||
- 未登录用户只能读 `public`。
|
||
- `docs_developer` 隐含 `docs_user`。
|
||
- `docs_admin` 隐含 `docs_developer` 和 `docs_user`。
|
||
- `admin` 和 `super_admin` 默认拥有全部 Docs 权限。
|
||
|
||
## 后端入口
|
||
|
||
文件:
|
||
|
||
- [docs.py](/home/ray/dev/linkong/planet/backend/app/api/v1/docs.py)
|
||
- [docs_gatekeeper.py](/home/ray/dev/linkong/planet/backend/app/services/docs_gatekeeper.py)
|
||
- [user.py](/home/ray/dev/linkong/planet/backend/app/models/user.py)
|
||
- [users.py](/home/ray/dev/linkong/planet/backend/app/api/v1/users.py)
|
||
|
||
API:
|
||
|
||
```http
|
||
GET /api/v1/docs/catalog
|
||
GET /api/v1/docs/{lang}/{slug}
|
||
```
|
||
|
||
`catalog` 只返回当前用户可见文档。正文接口会先校验语言、slug 和文件是否在 metadata 白名单里,再判断权限:
|
||
|
||
- 未登录访问受保护文档:`401`。
|
||
- 已登录但权限不足:`403`。
|
||
- 未知语言、未知 slug 或文件不存在:`404`。
|
||
|
||
正文文件只能来自 `docs/technical/{zh,en}/` 下的白名单文件,不能通过路径拼接读取任意文件。
|
||
|
||
## Metadata 来源
|
||
|
||
当前服务端 metadata 维护在 [docs_gatekeeper.py](/home/ray/dev/linkong/planet/backend/app/services/docs_gatekeeper.py):
|
||
|
||
```python
|
||
DocsMetadata(
|
||
"manual.md",
|
||
"manual",
|
||
"public",
|
||
"Manual",
|
||
2,
|
||
"Planet 使用手册",
|
||
"Planet Manual",
|
||
)
|
||
```
|
||
|
||
新增可在 Docs 页面展示的技术文档时,需要同步:
|
||
|
||
- 新增中英文 Markdown 文件。
|
||
- 在服务端 `DOCS_METADATA` 添加 filename、slug、access、group、order、标题。后端目录接口以这里为准,只改前端 metadata 不会让文档出现在 `/docs` 导航中。
|
||
- 在前端 [docs-content.ts](/home/ray/dev/linkong/planet/frontend/src/pages/Docs/docs-content.ts) 添加同名 metadata,保持导航标题和排序一致。
|
||
- 如果需要从 README 发现,更新 `docs/technical/zh/README.md` 和 `docs/technical/en/README.md`。
|
||
|
||
## 用户管理
|
||
|
||
`users` 表新增 `gatekeeper_groups JSONB DEFAULT '[]'`。启动时 [session.py](/home/ray/dev/linkong/planet/backend/app/db/session.py) 会用 `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` 补列,适配已有本地数据库。
|
||
|
||
用户 API 负责:
|
||
|
||
- 创建用户时写入 `gatekeeper_groups`。
|
||
- 更新用户时校验组名只能是 `docs_user`、`docs_developer`、`docs_admin`。
|
||
- 只有 `super_admin` 能修改 Gatekeeper 权限组。
|
||
|
||
前端 [Users.tsx](/home/ray/dev/linkong/planet/frontend/src/admin/pages/Users.tsx) 展示权限组标签,并在编辑表单中提供多选框。非 `super_admin` 打开的表单会禁用该字段,并在提交前移除 `gatekeeper_groups`。
|
||
|
||
## 前端 Docs 加载
|
||
|
||
文件:
|
||
|
||
- [Docs.tsx](/home/ray/dev/linkong/planet/frontend/src/pages/Docs/Docs.tsx)
|
||
- [docs-content.ts](/home/ray/dev/linkong/planet/frontend/src/pages/Docs/docs-content.ts)
|
||
- [docs-search.ts](/home/ray/dev/linkong/planet/frontend/src/pages/Docs/docs-search.ts)
|
||
|
||
关键变化:
|
||
|
||
- 移除 `import.meta.glob(...?raw)` 作为正文来源。
|
||
- 页面加载时请求 `/api/v1/docs/catalog` 构建当前可见目录。
|
||
- 打开正文时请求 `/api/v1/docs/{lang}/{slug}`。
|
||
- 搜索只索引当前用户可见文档,并按需从后端读取 Markdown。
|
||
- `401` 显示登录提示,`403` 显示权限提示,`404` 显示文档不可用。
|
||
|
||
## 测试覆盖
|
||
|
||
相关测试:
|
||
|
||
- [test_docs_gatekeeper.py](/home/ray/dev/linkong/planet/backend/tests/test_docs_gatekeeper.py)
|
||
|
||
测试应覆盖:
|
||
|
||
- 匿名用户只能看到 public 文档。
|
||
- 受保护正文的 `401` / `403`。
|
||
- `docs_developer` 可读开发文档但不能读管理文档。
|
||
- `admin` 和 `super_admin` 可读管理文档。
|
||
- 未知 slug、未知语言和路径穿越字符串不能读取文件。
|