# 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", ) ``` 新增公开文档时,需要同步: - 新增中英文 Markdown 文件。 - 在服务端 `DOCS_METADATA` 添加 filename、slug、access、group、order、标题。 - 在前端 [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/pages/Users/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、未知语言和路径穿越字符串不能读取文件。