Skip to content

Latest commit

 

History

History
3419 lines (2560 loc) · 90.9 KB

File metadata and controls

3419 lines (2560 loc) · 90.9 KB

OPENKB MASTER SPEC v0.3.3

This file is generated from the repository documents. Source files remain authoritative; if any conflict exists, follow AGENTS.md, docs/18-decision-overrides-v0.3.zh-CN.md, docs/21-v0.3.2-clarifications.zh-CN.md, and docs/22-v0.3.3-clarifications.zh-CN.md.


Source: AGENTS.md

AGENTS.md — OpenKB Codex Instructions

This file is the highest-priority project instruction for Codex or any coding agent working in this repository.

Project identity

OpenKB is a Markdown-first, Yuque-like, self-hostable knowledge base system. It supports document editing, Yuque-style permissions, file import to Markdown, Milvus-based retrieval, Dify External Knowledge compatibility, and a user-bound MCP server.

Non-negotiable rules

  1. Markdown follows Milkdown exactly.

    • Do not invent a custom OpenKB Markdown dialect.
    • The supported Markdown set is the round-trippable Markdown supported by the locked Milkdown version and the enabled Milkdown plugins.
    • If a feature cannot be parsed, rendered, and serialized through Milkdown, it is not supported as editable body Markdown.
  2. The editor must feel close to Yuque.

    • Left document tree, center document editor, right outline.
    • Markdown-rich-text editing through Milkdown.
    • Reading mode, edit mode, source mode.
    • Collaboration, sharing, invitations, and visibility controls should be exposed in Yuque-like places.
  3. Permissions must align with Yuque-style product logic.

    • Workspace/space, knowledge base, document, collaborators, invitation links, share links, approval, password, member-only access, and close-share behaviors.
    • Do not introduce LDAP, SCIM, OpenFGA, Casbin, OPA, or custom ABAC in v0.x.
    • External identity systems may be added later only as login/user import sources, not as replacements for the Yuque-style object permissions.
  4. Admin configuration is not content permission.

    • system_admin / tenant_admin can access admin configuration pages.
    • Admin status does not automatically grant read access to all private documents.
    • Any emergency content access must be an explicit audited action, not default behavior.
  5. Knowledge base owners cannot configure models.

    • Workspace owners, knowledge base owners, knowledge base managers, and document owners cannot configure embedding/rerank/LLM models.
    • Model and Milvus index configuration is admin-only.
  6. Embedding and rerank belong to Milvus-native capabilities whenever supported.

    • Use Milvus 2.6+ Functions such as TEXTEMBEDDING, BM25, and RERANK/Model Ranker when compatible with the deployment.
    • OpenKB should not store embedding/rerank API keys in its database.
    • Provider credentials and endpoints should be configured in Milvus deployment configuration, environment variables, or the provider service deployment.
  7. Embedding model replacement uses Milvus-native blue/green indexing.

    • Do not mix vectors generated by different embedding models/dimensions in one active collection.
    • Create a new collection with the new schema/functions, rebuild from PostgreSQL chunks, load and health-check it, then switch the Milvus alias.
    • Keep old collections temporarily for rollback.
  8. PostgreSQL is the content and permission truth.

    • Markdown content, document versions, directories, users, collaborators, share links, invitations, audit logs, and permission decisions live in PostgreSQL.
    • Milvus never becomes the final authorization source.
  9. Milvus is a retrieval index.

    • Milvus stores chunk text, metadata, access principals, vector/sparse search indexes, and collection aliases.
    • If Milvus and PostgreSQL disagree about access, PostgreSQL wins.
  10. MCP is user-bound; Dify is app-key-bound.

    • MCP tokens must resolve to a real user and use that user's document permissions.
    • Dify External Knowledge API keys are scoped to specific knowledge bases and cannot impersonate arbitrary users.
  11. Every retrieval result must pass final permission check.

    • Web search, MCP, Dify, export, and attachment reads must call the same permission service before returning sensitive content.

Tech baseline

  • Monorepo: pnpm workspaces + Turborepo.
  • Frontend: Next.js, React, TypeScript, Milkdown, Tailwind CSS, shadcn/ui.
  • API: NestJS with Fastify adapter, REST + OpenAPI.
  • Database: PostgreSQL.
  • ORM/migrations: Prisma plus SQL migrations where Prisma is insufficient.
  • Queue/cache: Redis + BullMQ.
  • Object storage: S3-compatible storage, MinIO for self-hosted.
  • Vector/search index: Milvus Server 2.6+ by default.
  • Import worker: Python worker for MinerU and conversion adapters.
  • Index worker: TypeScript worker that reads chunks from PostgreSQL and writes raw text/metadata to Milvus collections.
  • MCP: Streamable HTTP primary; do not implement arbitrary stdio command execution.
  • Dify: External Knowledge compatible /retrieval endpoint.

Suggested package layout

apps/
  web/
  api/
  mcp-server/
  dify-adapter/
workers/
  import-worker/
  index-worker/
packages/
  auth/
  db/
  editor/
  markdown/
  milvus/
  permissions/
  retrieval/
  shared/
deploy/
  docker-compose/
  helm/
docs/
prompts/

Implementation discipline

  • Read docs/00-index.zh-CN.md, docs/18-decision-overrides-v0.3.zh-CN.md, docs/21-v0.3.2-clarifications.zh-CN.md, and docs/22-v0.3.3-clarifications.zh-CN.md before coding.
  • Implement in phases. Do not attempt the whole product in one patch.
  • Prefer domain services over controller-heavy logic.
  • Put authorization checks in service layer, not only in route handlers.
  • Write permission tests before convenience features.
  • Keep async jobs idempotent.
  • Keep editor behavior deterministic: Markdown in, Milkdown-normalized Markdown out.
  • Do not bypass the feature registry when adding editor features.
  • Do not add per-knowledge-base model configuration.
  • Treat share links as read-only only in v0.x; do not add link-edit capabilities.
  • Treat folders as documents.type = folder; do not create a separate folders table unless the spec is explicitly changed.

v0.3.3 clarifications

  • Workspace membership roles are owner/admin/member/guest and live in workspace_members.
  • Content collaborator roles are owner/manager/editor/viewer and live in collaborators for knowledge_base and document only.
  • Workspace invitations grant admin/member/guest; content invitations grant manager/editor/viewer; ordinary invitations do not grant owner.
  • Milvus collection primary key is id; chunk_id is a regular field. In v0.x both values equal the PostgreSQL document_chunks.id string.
  • Implement auth_settings, MCP OAuth/PAT tables, and Dify scoped API key tables from docs/07-data-model.zh-CN.md.
  • Do not implement embedding/rerank fallback provider secrets in OpenKB DB.

Source: README.md

OpenKB Codex Bootstrap v0.3.3

这是给 Codex 使用的 OpenKB 项目启动包。它不是最终应用代码,而是一个带有完整产品/架构/权限/编辑器/Milvus/MCP/Dify 规格的仓库骨架。

项目定位

OpenKB 是一个:

Markdown-first 的开源私有化知识库
+ 语雀式文档编辑和权限
+ Milvus 原生 Function 检索索引
+ Dify 第三方知识库接口
+ 用户权限绑定的 MCP Server

最重要的三条

  1. 编辑器白嫖 Milkdown: Markdown 方言完全跟随 Milkdown 当前锁定版本和启用插件。
  2. 权限白嫖语雀: 只做语雀式空间/知识库/文档/协作者/邀请/分享权限,不引入其它权限方案。
  3. 向量检索白嫖 Milvus: embedding、BM25、rerank 优先放到 Milvus 2.6+ 原生 Functions;模型更换走新 collection + rebuild + alias switch。

给 Codex 的使用方式

第一轮只让 Codex 读文档,不写代码:

Read AGENTS.md and docs/00-index.zh-CN.md first. Do not modify files yet.
Summarize the non-negotiable rules, proposed architecture, first milestones, and any contradictions.

确认总结没跑偏后,再让 Codex 从 prompts/01-read-and-plan.md 开始,按 prompts/ 目录逐步执行。v0.3.3 已修正 Codex 前两轮发现的不一致:优先级统一到 docs/18;prompt 补读 docs/18/21/22;分享链接固定只读;folder 明确为 documents.type=folder;workspace 角色和内容协作者角色分离;Milvus 使用 id 作为主键;auth_settings、MCP OAuth/PAT、Dify scoped API key 表已补齐;OpenKB DB 不保存 embedding/rerank fallback key。

推荐实现顺序

0. 读文档和确认约束
1. Monorepo 脚手架
2. PostgreSQL 数据模型和迁移
3. 邮箱注册、登录、管理员激活
4. 语雀式权限服务
5. Milkdown 文档编辑器
6. 文件导入转 Markdown
7. Milvus collection / Function / rebuild / alias
8. Web Search + Retrieval Service
9. MCP Server
10. Dify Adapter
11. Docker Compose / Helm

当前目录

AGENTS.md                         # Codex 最高优先级规则
README.md                         # 本说明
docs/                             # 完整中文规格文档
prompts/                          # 分阶段给 Codex 的提示词
apps/ workers/ packages/ deploy/  # 未来代码目录占位

Source: package-notes.md

Package Notes

Generated as OpenKB Codex Bootstrap v0.3.3.

This package integrates:

  • Milkdown-native Markdown dialect rule.
  • Yuque-style permissions only.
  • Admin-only Milvus/model/index configuration.
  • Milvus-native TEXTEMBEDDING/BM25/RERANK Function direction.
  • New collection + rebuild + alias switch for embedding replacement.
  • Codex staged prompts.
  • v0.3.2 reconciled Codex first-pass findings: priority docs, prompt priority list, read-only share links, and folder-as-document modeling.
  • v0.3.3 reconciles Codex second-pass findings: workspace role mapping, Milvus primary key, auth_settings schema, MCP/Dify persistence tables, and no embedding/rerank fallback secrets in OpenKB DB.

Old v0.1/v0.2/v0.3.2 files in /mnt/data were not modified. This is a new integrated package.


Source: manifest.json

{ "name": "openkb-codex-bootstrap", "version": "0.3.3", "purpose": "Codex bootstrap specification for OpenKB", "highest_priority_documents": [ "AGENTS.md", "docs/18-decision-overrides-v0.3.zh-CN.md", "docs/21-v0.3.2-clarifications.zh-CN.md", "docs/22-v0.3.3-clarifications.zh-CN.md", "docs/04-editor-spec.zh-CN.md", "docs/05-permission-spec.zh-CN.md", "docs/09-search-rag-milvus-native.zh-CN.md" ], "resolved_findings": [ "docs/00-index and prompts/01 prioritize docs/18 over docs/16", "prompts/01 explicitly includes docs/18, docs/21, and docs/22", "share_links.permission is constrained to view only in v0.x", "folders are represented by documents.type = folder, not a separate folders table", "workspace membership roles and content collaborator roles are separated", "Milvus primary key is id; chunk_id is a regular field", "auth_settings table is fully specified", "MCP OAuth/PAT tables and Dify scoped API key tables are specified", "embedding/rerank fallback provider secrets are forbidden in OpenKB DB for v0.x" ], "non_negotiable_rules": [ "Markdown follows Milkdown enabled features exactly", "Permissions follow Yuque-style product logic only in v0.x", "Only system_admin/tenant_admin can access Milvus/model/index configuration", "Knowledge base owners cannot configure models", "Embedding/rerank use Milvus-native Functions whenever compatible", "Embedding replacement uses new collection + rebuild + alias switch", "PostgreSQL remains content and permission truth", "MCP is user-bound; Dify is app-key-bound" ] }


Source: docs/00-index.zh-CN.md

00 — OpenKB 文档索引

Codex 开始任何代码工作前,必须按下面顺序阅读。

最高优先级

  1. AGENTS.md
  2. docs/18-decision-overrides-v0.3.zh-CN.md
  3. docs/21-v0.3.2-clarifications.zh-CN.md
  4. docs/22-v0.3.3-clarifications.zh-CN.md
  5. docs/04-editor-spec.zh-CN.md
  6. docs/05-permission-spec.zh-CN.md
  7. docs/09-search-rag-milvus-native.zh-CN.md
  8. docs/16-decisions-and-non-goals.zh-CN.md

如果以上文档存在细节差异,以 AGENTS.mddocs/18-decision-overrides-v0.3.zh-CN.md 为准;docs/16-decisions-and-non-goals.zh-CN.md 只作为基础决策摘要。

产品和架构

  • docs/01-product-vision.zh-CN.md:产品目标和范围。
  • docs/02-yuque-reference-model.zh-CN.md:语雀式产品模型抽象。
  • docs/03-system-architecture.zh-CN.md:整体系统架构。

核心模块

  • docs/04-editor-spec.zh-CN.md:Milkdown 文档编辑器。
  • docs/05-permission-spec.zh-CN.md:语雀式权限。
  • docs/06-auth-registration.zh-CN.md:邮箱注册、激活、登录。
  • docs/07-data-model.zh-CN.md:数据库模型。
  • docs/08-api-contract.zh-CN.md:API 合同。
  • docs/09-search-rag-milvus-native.zh-CN.md:Milvus 原生检索、Function、alias、重建索引。
  • docs/10-mcp-server.zh-CN.md:MCP Server。
  • docs/11-dify-adapter.zh-CN.md:Dify External Knowledge Adapter。
  • docs/12-import-conversion.zh-CN.md:文件导入和 Markdown 转换。
  • docs/13-deployment.zh-CN.md:Docker Compose 和 K8s。
  • docs/14-ui-routes.zh-CN.md:UI 路由和页面。
  • docs/15-roadmap-and-codex-tasks.zh-CN.md:开发路线。
  • docs/18-decision-overrides-v0.3.zh-CN.md:v0.3 最高优先级决策覆盖清单。
  • docs/21-v0.3.2-clarifications.zh-CN.md:Codex 首轮发现点的澄清和修正。
  • docs/22-v0.3.3-clarifications.zh-CN.md:Codex 第二轮发现点的澄清和修正。

辅助文档

  • docs/17-glossary.zh-CN.md:术语表。
  • docs/99-references.md:参考资料。
  • prompts/:给 Codex 的分阶段提示词。

Source: docs/01-product-vision.zh-CN.md

01 — 产品愿景

一句话定位

OpenKB 是一个 Markdown-first、语雀式权限和编辑体验、支持私有化部署的开源知识库系统,同时可以作为 Dify 第三方知识库和用户权限绑定的 MCP Server。

目标用户

  • 想自托管知识库的团队。
  • 想把内部知识库接入 AI/RAG 的团队。
  • 想把文档系统通过 MCP 暴露给 IDE、Agent、企业系统的团队。
  • 想把所有文件统一转换为 Markdown 管理的用户。

核心能力

文档编辑:Milkdown 富文本式 Markdown 编辑器。
知识管理:空间、知识库、目录、文档、版本。
权限:语雀式协作者、邀请、分享、审批、密码访问、成员可见。
导入:PDF/DOCX/PPTX/XLSX/图片 -> Markdown + assets。
检索:Milvus 原生 Function + dense/sparse/hybrid/rerank。
集成:MCP Server、Dify External Knowledge API。
部署:Docker Compose、K8s/Helm。

非目标

  • 不做 Notion 式数据库。
  • 不做语雀的表格文档和画板/思维图文档,v0.x 只做富文本文档。
  • 不做 LDAP/SCIM/OpenFGA/Casbin/OPA 权限系统。
  • 不做知识库级模型配置。
  • 不允许 MCP 或 Dify 绕过文档权限。

内容真相

OpenKB 的长期内容真相是 Markdown。Milkdown/ProseMirror state 只是编辑器运行时状态,除非作为草稿快照单独保存。

Markdown + metadata + assets + versions = content truth

Source: docs/02-yuque-reference-model.zh-CN.md

02 — 语雀式产品模型抽象

本项目不复制语雀内部实现,只抽象语雀公开产品体验中对 OpenKB 有价值的结构。

核心结构

OpenKB 使用以下结构贴近语雀:

Tenant / 实例或租户
  └── Workspace / 空间
        └── Knowledge Base / 知识库
              └── Folder / 目录
                    └── Document / 文档

UI 中可以把 Workspace 显示为“空间”。Folder / 目录 是产品和 UI 概念;数据库实现中不单独建立 folders 表,而是使用 documents.type = folder | page 统一表达目录节点和文档页。

编辑体验

语雀式文档编辑体验应包括:

  • 左侧知识库目录树。
  • 中间标题和正文编辑。
  • 右侧大纲。
  • 顶部面包屑、搜索、分享、更多菜单。
  • 阅读和编辑在同一个文档上下文内切换。
  • 文档协作者、分享链接、邀请入口靠近文档顶部。

OpenKB 的实现方式是 Milkdown,而不是自研编辑器。

权限体验

语雀式权限由这些产品对象组成:

空间成员
知识库公开性
知识库协作者
文档协作者
邀请链接
分享链接
审批
密码访问
仅空间成员可访问
关闭分享

OpenKB 不引入抽象 IAM 权限系统。所有功能优先按用户可理解的协作者和分享逻辑实现。

公开性

知识库和文档的公开性建议显示为:

UI 文案 内部值 含义
仅协作者可访问 private 只有协作者或明确授权用户可访问。
空间成员可访问 workspace 空间成员可阅读。
互联网可访问 public 匿名可阅读已发布内容。

公开性主要控制阅读;编辑仍然依赖协作者权限。

协作者权限

UI 文案 内部 role 含义
所有者 owner 拥有对象,可转让、删除、管理协作者。
可管理 manager 可管理设置、目录、协作者和内容。
可编辑 editor 可阅读和编辑内容。
可阅读 viewer 只读访问。

注意:manager 是内容对象角色,不等于系统 admin。


Source: docs/03-system-architecture.zh-CN.md

03 — 系统架构

架构原则

PostgreSQL:内容、版本、目录、用户、权限、审计的真相。
Milvus:chunk 检索索引,不是业务数据库,不是最终权限系统。
Milkdown:Markdown 编辑器能力边界。
MCP:用户级权限出口。
Dify:应用级 scoped API key 出口。

总体架构

Browser / Web App
  -> API Server
       -> PostgreSQL
       -> Redis
       -> MinIO/S3
       -> Permission Service
       -> Retrieval Service
            -> Milvus active alias

Workers
  -> Import Worker: 文件转 Markdown
  -> Index Worker: chunk + metadata + access principals 写入 Milvus

Integrations
  -> MCP Server: user-bound tools/resources
  -> Dify Adapter: app-key-bound /retrieval

推荐服务

apps/web           Next.js + Milkdown
apps/api           NestJS/Fastify API
apps/mcp-server    MCP Streamable HTTP server
apps/dify-adapter  Dify External Knowledge endpoint
workers/import-worker
workers/index-worker
packages/permissions
packages/editor
packages/milvus
packages/retrieval
packages/db

关键链路

文档保存

Milkdown editor
  -> Markdown serialize
  -> API version conflict check
  -> document_versions insert
  -> documents.current_version_id update
  -> enqueue indexing job

检索

caller identity
  -> permission principals
  -> Milvus search with metadata/access_principals pre-filter
  -> PostgreSQL final permission check
  -> return authorized chunks/documents

Embedding 模型更换

admin updates Milvus/provider deployment
  -> create new Milvus collection with new functions/schema
  -> rebuild chunks into new collection
  -> health check
  -> switch alias
  -> retain old collection for rollback

部署模式

  • 单机开发:Docker Compose。
  • 私有化生产:Docker Compose 或 K8s standalone Milvus。
  • 企业规模:K8s + Milvus cluster + external PostgreSQL/S3/Redis。

Source: docs/04-editor-spec.zh-CN.md

04 — 文档编辑器规格说明

1. 最高原则

Milkdown 是编辑器能力边界。
Markdown 是持久化内容真相。
OpenKB 不发明独立 Markdown 方言。

OpenKB 支持的 Markdown 等于当前锁定 Milkdown 版本和启用插件能完整 round-trip 的 Markdown。

Markdown source
  -> Milkdown parse
  -> editor state
  -> Milkdown serialize
  -> normalized Markdown

这个过程不能丢失语义。允许规范化空格、换行、代码块围栏等格式细节,但不能丢失标题、表格、链接、图片、列表、任务状态、代码、公式等语义。

2. Milkdown-native 方言定义

OpenKB Markdown Dialect = locked Milkdown version + enabled Milkdown plugins/features

因此:

  • CommonMark/GFM 只有在 Milkdown 配置实际启用时才算支持。
  • Mermaid、LaTeX、callout、附件卡片、内部链接卡片必须通过 Milkdown plugin 或兼容扩展实现。
  • 服务端 sanitizer、导入器、导出器、检索文本抽取都必须读取同一个 feature registry。
  • 源码模式不能保存 Milkdown 无法 parse/serialize 的正文内容。

3. Feature Registry

必须维护统一的编辑器能力注册表。

建议文件:

packages/editor/src/feature-registry.ts

示例类型:

export type EditorFeature = {
  key: string;
  label: string;
  milkdownPlugin: string;
  enabled: boolean;
  markdownSyntax: string[];
  supportsParse: boolean;
  supportsRender: boolean;
  supportsSerialize: boolean;
  supportsSearchExtraction: boolean;
};

所有模块都从 registry 获取能力:

编辑器工具栏
slash menu
源码模式校验
导入器 Markdown 校验
服务端 sanitizer
搜索索引文本抽取
导出器
测试用例

4. 编辑页面布局

页面必须贴近语雀式文档体验:

┌─────────────────────────────────────────────────────────────┐
│ 顶部栏:空间 / 知识库 / 文档面包屑、搜索、协作、分享、更多 │
├───────────────┬───────────────────────────────┬─────────────┤
│ 左侧目录树    │ 标题 + Milkdown 正文编辑器     │ 右侧大纲    │
│ 文件夹/文档   │ 阅读/编辑/源码模式             │ H1/H2/H3    │
└───────────────┴───────────────────────────────┴─────────────┘

左侧目录树

必须支持:

  • 知识库目录。
  • 文件夹。
  • 文档。
  • 新建文档。
  • 新建文件夹。
  • 重命名。
  • 删除。
  • 移动。
  • 拖拽排序。
  • 折叠/展开。
  • 当前文档高亮。
  • 按权限隐藏不可见文档。

主编辑区

必须支持:

  • 标题输入。
  • Milkdown 富文本式 Markdown 编辑。
  • 阅读模式。
  • 编辑模式。
  • 源码模式。
  • 自动保存状态。
  • 保存中/已保存/保存失败提示。
  • 版本冲突提示。
  • 顶部协作与分享按钮。

右侧大纲

必须支持:

  • 从当前 Markdown 标题生成。
  • 点击跳转。
  • 滚动高亮。
  • 窄屏隐藏。

5. 编辑模式

模式 用途 要求
阅读模式 阅读文档 使用 Milkdown-compatible renderer。
可视化编辑模式 主编辑模式 Milkdown WYSIWYG Markdown editor。
源码模式 兜底/开发者模式 Monaco 或 textarea,但保存前必须通过 Milkdown parse。

6. 保存和版本

文档内容保存在 document_versions.markdown

保存请求必须包含:

document_id
base_version_id 或 base_version_no
markdown
markdown_hash

服务端检查:

如果 base_version 不是当前版本 -> 返回 VERSION_CONFLICT。
如果用户无编辑权限 -> 返回 403。
如果 Markdown 无法通过 Milkdown 方言校验 -> 返回 MARKDOWN_DIALECT_ERROR。

7. 自动保存

  • 编辑状态每隔固定时间或内容变化后 debounce 自动保存。
  • 页面离开前提示未保存变更。
  • 自动保存失败必须可见。
  • 不做实时多人协作,v0.x 只做乐观锁。

8. 内部链接

可以实现本项目文档链接:

[文档标题](openkb://document/{document_id})

渲染时转换为 Web URL。源码模式仍然必须是 Milkdown 可处理的普通链接或兼容插件节点。

9. 资源引用

图片和附件存对象存储,Markdown 中使用稳定引用:

![图片](asset://asset_id)

读取时由 API 转成带权限校验的临时 URL。附件下载必须检查文档读权限。

10. 导入文档校验

文件转换出的 Markdown 不能直接入库。必须:

转换器输出 Markdown
  -> Milkdown parse/serialize 测试
  -> sanitizer
  -> normalized Markdown
  -> 保存版本

不能被 Milkdown 表示的内容:

  • 转为 asset。
  • 转为只读 HTML block 前必须明确标记。
  • 或等待插件支持。

11. 测试要求

必须有:

  • 每个 enabled feature 的 parse/render/serialize round-trip 测试。
  • 源码模式非法 Markdown 保存失败测试。
  • 自动保存冲突测试。
  • 目录树权限隐藏测试。
  • 内部链接和 asset 链接渲染测试。

Source: docs/05-permission-spec.zh-CN.md

05 — 权限规格说明

1. 最高原则

权限完整向语雀产品逻辑对齐。
v0.x 不引入其它权限方案作为设计目标。
PostgreSQL 中的语雀式对象权限是最终权限真相。

不做:

LDAP / SCIM / 复杂组织架构同步
OpenFGA / Casbin / OPA
自定义 ABAC 策略语言
管理员默认可读全库内容
知识库级模型配置权限
链接编辑权限

2. 对象层级

Tenant / 实例或租户
  └── Workspace / 空间
        └── Knowledge Base / 知识库
              └── Folder / 目录
                    └── Document / 文档

权限主要发生在 workspace、knowledge_base、document。folder 默认参与继承、目录结构和排序,不做单独权限体系。实现时 folder 不单独建表,而是 documents.type = folder 的目录节点;page 是 documents.type = page 的正文文档。

3. 角色命名和映射

3.1 Workspace / 空间成员角色

空间成员关系只存在 workspace_members 表,不进入 collaborators 表。

UI 文案 内部 role 含义
空间所有者 owner 拥有空间,可转让、删除、管理空间成员和设置。通常由创建、转让或系统初始化产生,不通过普通邀请链接授予。
空间管理员 admin 可管理空间成员、空间设置和空间内知识库管理入口,但不等于内容对象 owner。
空间成员 member 普通成员。可以阅读 visibility = workspace 的知识库/文档。
空间访客 guest 受限成员。默认只看到明确邀请或分享给自己的内容。

Workspace 邀请只能授予:

admin / member / guest

不允许通过普通邀请链接直接授予 workspace owner。workspace owner 只能通过创建空间、转让所有权或系统级初始化产生。

3.2 内容对象协作者角色

内容对象包括 knowledge_base 和 document。documents.type = folder 的目录节点也按 document 对象处理。

内容对象协作者关系存在 collaborators 表。

UI 文案 内部 role 含义
所有者 owner 拥有对象,可转让、删除、管理协作者。通常由创建或转让产生。
可管理 manager 可管理设置、目录、协作者和内容。
可编辑 editor 可阅读和编辑内容。
可阅读 viewer 只读访问。

Knowledge base / document / folder 邀请只能授予:

manager / editor / viewer

不允许通过普通邀请链接直接授予内容对象 owner。内容对象 owner 只能通过创建或转让产生。

3.3 系统管理角色

角色 来源 含义
system_admin tenant_memberships.role 或系统级成员关系 系统级后台管理员。
tenant_admin tenant_memberships.role 租户级后台管理员。
member tenant_memberships.role 租户普通用户。

内容对象 manager 不等于后台 admin。workspace admin 也不等于 tenant_admin

4. Admin 边界

system_admin / tenant_admin 可以:

  • 进入后台。
  • 管理用户、激活用户、禁用用户。
  • 配置 SMTP。
  • 配置 Milvus 连接、索引任务、collection alias。
  • 查看模型/embedding/rerank Function 状态。
  • 触发全局重建索引。
  • 查看审计日志。

但 admin 不因此自动拥有所有私有文档的阅读权限。搜索、MCP、Dify、附件、导出都不能因为 admin 身份绕过内容权限。

5. Workspace / 空间权限

空间是成员协作和安全策略边界。

默认规则:

空间 member 可以阅读 visibility = workspace 的知识库/文档。
空间 member 不能阅读 private 知识库,除非是协作者。
空间 member 不能编辑知识库,除非有 editor/manager/owner 内容对象协作者权限。
空间 guest 只看到明确邀请或分享给自己的内容。
空间 admin 可以管理空间设置和成员,但不自动获得 private 知识库内容阅读权。

6. Knowledge Base / 知识库权限

知识库有两组关键设置:

visibility
collaborators

6.1 公开性

UI 文案 内部值 含义
仅协作者可访问 private 只有知识库协作者和被授权文档协作者可访问。
空间成员可访问 workspace 当前空间 member/admin/owner 可阅读。guest 默认不可读,除非被明确授权。
互联网可访问 public 匿名用户可阅读已发布内容。

公开性只决定阅读。编辑/管理仍然依赖协作者角色。

6.2 协作者

知识库协作者可以是:

  • 用户。
  • 用户组。
  • 邮箱邀请接受后的用户。

角色:owner、manager、editor、viewer。

知识库 owner 不能配置知识库自己的模型。

7. Document / 文档权限

文档默认继承知识库权限。

document.permission_mode = inherit | custom

inherit

文档继承知识库 visibility 和 collaborators。

custom

文档可以设置独立协作者和分享状态。custom 可以让某篇文档比知识库更严格或更开放,但必须通过明确 UI 展示。

文档协作者角色:owner、manager、editor、viewer。

8. 内容对象能力矩阵

能力 owner manager editor viewer
阅读
编辑正文
新建子文档
移动/重命名
删除 可配置,默认 ❌
管理协作者
创建分享链接 可配置,默认 ❌
转让 owner

9. 邀请机制

9.1 Workspace 邀请

Workspace 邀请的结果是写入 workspace_members,不是写入 collaborators

邀请对象:

  • 已注册用户。
  • 邮箱。

邀请角色:

admin / member / guest

普通 workspace 邀请不支持 owner。owner 转让走单独接口和审计。

9.2 内容对象直接邀请

邀请对象:

  • 已注册用户。
  • 邮箱。
  • 用户组。

邀请范围:knowledge_base、document。folder 使用 document 对象语义。

邀请角色:

manager / editor / viewer

普通内容对象邀请不支持 owner。owner 转让走单独接口和审计。

9.3 邀请链接

邀请链接设置:

  • 角色:根据 object_type 使用不同角色集合:
    • workspace:admin/member/guest。
    • knowledge_base/document:manager/editor/viewer。
  • 是否需要审批。
  • 是否限制邮箱域名。
  • 过期时间。
  • 使用次数。
  • 可重置链接。
  • 可关闭链接。

10. 分享链接

分享链接和协作者邀请分开。

分享链接默认只读,支持:

  • 密码访问。
  • 过期时间。
  • 仅空间成员可访问。
  • 关闭分享。
  • 访问审计。

v0.x 不支持链接编辑权限。share_links.permission 必须固定为 view

11. 权限服务函数

必须实现统一 Permission Service:

canReadDocument(user, documentId): Promise<boolean>
canEditDocument(user, documentId): Promise<boolean>
canManageDocument(user, documentId): Promise<boolean>
canManageKnowledgeBase(user, kbId): Promise<boolean>
canInviteCollaborator(user, object): Promise<boolean>
canCreateShareLink(user, object): Promise<boolean>
resolveEffectiveRole(user, object): Promise<Role | null>
resolveWorkspaceRole(user, workspaceId): Promise<'owner' | 'admin' | 'member' | 'guest' | null>
resolveReadablePrincipalsForMilvus(user): Promise<string[]>

所有 API、MCP、Dify、附件和导出必须调用 Permission Service 或同等底层逻辑。

12. Milvus access principals

写入 Milvus 的每个 chunk 带 access_principals 作为预过滤字段:

[
  "tenant:t1:member",
  "workspace:w1:member",
  "kb:kb1:viewer",
  "group:g1",
  "user:u123"
]

用户检索时先计算用户 principals,再做 Milvus 预过滤,最后回 PostgreSQL 做最终 canReadDocument。

13. 审计

需要记录:

  • 权限变更。
  • 邀请创建/接受/拒绝/撤销。
  • 分享链接创建/关闭。
  • 管理员激活/禁用用户。
  • MCP 查询返回的 document IDs。
  • Dify scoped key 调用。
  • 管理员触发重建索引和 alias 切换。
  • owner 转让。

14. 测试要求

必须覆盖:

  • private 知识库只有协作者可读。
  • workspace-visible 知识库对 workspace member 可读,对 guest 默认不可读。
  • workspace admin 不自动获得 private 知识库阅读权限。
  • workspace 邀请写入 workspace_members,角色只能是 admin/member/guest。
  • knowledge_base/document 邀请写入 collaborators,角色只能是 manager/editor/viewer。
  • 分享链接固定只读。
  • removed collaborator 失去访问。
  • MCP principals 只包含当前用户允许范围。

Source: docs/06-auth-registration.zh-CN.md

06 — 用户注册、登录和激活

1. 注册方式

v0.x 支持邮箱注册和邮箱密码登录。

不做:

  • LDAP。
  • SCIM。
  • 企业组织架构同步。
  • 第三方 OAuth 登录,后续可加。

2. 用户状态

pending_email_verification
pending_activation
active
suspended
deleted

3. 管理员设置

后台注册设置:

允许邮箱注册:开/关
必须验证邮箱:开/关
注册后默认状态:active / pending_activation
被邀请用户验证邮箱后是否自动激活:开/关
允许邮箱域名白名单:可选
仅允许邀请注册:开/关
第一位用户自动成为 system_admin:开/关,默认开

3.1 auth_settings 表结构

auth_settings 必须在 docs/07-data-model.zh-CN.md 中实现。核心字段包括:

registration_enabled
email_verification_required
default_signup_status = active | pending_activation
invited_user_auto_active
allowed_email_domains
invite_required
first_user_becomes_admin

实现时优先读取租户级设置;如果不存在租户级设置,则读取 tenant_id = null 的实例默认设置。

4. 注册流程

用户提交邮箱和密码
  -> 创建 user
  -> 如果需要邮箱验证:pending_email_verification
  -> 用户点击验证链接
  -> 如果默认需要管理员激活:pending_activation
  -> 否则 active

5. 激活流程

管理员后台可查看 pending_activation 用户,并执行:

  • 激活。
  • 拒绝/删除。
  • 禁用 active 用户。
  • 重发验证邮件。

所有操作写入 audit_logs。

6. 邀请注册

用户通过邀请链接注册时:

打开邀请链接
  -> 注册/登录
  -> 邮箱验证
  -> 如果链接需要审批:进入待审批
  -> 否则根据 object_type 授权:
      workspace -> 写入 workspace_members
      knowledge_base/document -> 写入 collaborators

被邀请用户是否自动 active 由后台设置决定。

7. 第一位用户

如果系统中不存在任何 system_admin,且 first_user_becomes_admin = true,第一位完成注册/验证流程的用户必须被授予:

tenant_memberships.role = system_admin

如果系统采用多租户初始化流程,该用户也应成为默认 tenant 的 tenant_admin。


Source: docs/07-data-model.zh-CN.md

07 — 数据模型

本文件描述核心 PostgreSQL 表。字段名可在实现时微调,但语义不能偏离。

1. 用户、租户、注册设置

users (
  id uuid primary key,
  email text unique not null,
  password_hash text null,
  display_name text not null,
  status text not null check (status in (
    'pending_email_verification',
    'pending_activation',
    'active',
    'suspended',
    'deleted'
  )),
  email_verified_at timestamptz null,
  created_at timestamptz not null,
  updated_at timestamptz not null
)

tenants (
  id uuid primary key,
  name text not null,
  slug text unique not null,
  created_at timestamptz not null
)

tenant_memberships (
  id uuid primary key,
  tenant_id uuid not null,
  user_id uuid not null,
  role text not null check (role in ('system_admin', 'tenant_admin', 'member')),
  created_at timestamptz not null,
  unique (tenant_id, user_id)
)

auth_settings (
  id uuid primary key,
  tenant_id uuid null unique,
  -- tenant_id null 表示实例默认设置;tenant_id 非 null 表示租户覆盖。
  registration_enabled boolean not null default true,
  email_verification_required boolean not null default true,
  default_signup_status text not null default 'active' check (default_signup_status in ('active', 'pending_activation')),
  invited_user_auto_active boolean not null default true,
  allowed_email_domains text[] null,
  invite_required boolean not null default false,
  first_user_becomes_admin boolean not null default true,
  created_at timestamptz not null,
  updated_at timestamptz not null
)

1.1 用户组

用户组用于手动授权,不来自 LDAP/SCIM。

groups (
  id uuid primary key,
  tenant_id uuid not null,
  name text not null,
  created_by uuid not null,
  created_at timestamptz not null,
  updated_at timestamptz not null,
  unique (tenant_id, name)
)

group_members (
  id uuid primary key,
  tenant_id uuid not null,
  group_id uuid not null,
  user_id uuid not null,
  created_at timestamptz not null,
  unique (group_id, user_id)
)

2. 空间和知识库

Workspace 成员角色只存在 workspace_members 表。不要把 workspace 成员关系写入 collaborators

workspaces (
  id uuid primary key,
  tenant_id uuid not null,
  name text not null,
  slug text not null,
  created_by uuid not null,
  created_at timestamptz not null,
  updated_at timestamptz not null,
  unique (tenant_id, slug)
)

workspace_members (
  id uuid primary key,
  tenant_id uuid not null,
  workspace_id uuid not null,
  user_id uuid not null,
  role text not null check (role in ('owner', 'admin', 'member', 'guest')),
  created_at timestamptz not null,
  unique (workspace_id, user_id)
)

knowledge_bases (
  id uuid primary key,
  tenant_id uuid not null,
  workspace_id uuid not null,
  title text not null,
  slug text not null,
  visibility text not null check (visibility in ('private', 'workspace', 'public')),
  status text not null check (status in ('active', 'archived')),
  created_by uuid not null,
  created_at timestamptz not null,
  updated_at timestamptz not null,
  unique (workspace_id, slug)
)

3. 文档和版本

OpenKB 不单独建立 folders 表。目录树中的目录和文档页统一存在 documents 表中,通过 documents.type = folder | page 区分。folder 行用于目录结构、排序、继承和协作者范围,不保存可编辑正文;page 行才保存 Markdown 正文版本。

documents (
  id uuid primary key,
  tenant_id uuid not null,
  workspace_id uuid not null,
  knowledge_base_id uuid not null,
  parent_id uuid null,
  type text not null check (type in ('folder', 'page')),
  title text not null,
  slug text not null,
  status text not null check (status in ('draft', 'published', 'archived', 'deleted')),
  permission_mode text not null default 'inherit' check (permission_mode in ('inherit', 'custom')),
  visibility text null check (visibility is null or visibility in ('private', 'workspace', 'public')),
  current_version_id uuid null,
  sort_order int not null default 0,
  created_by uuid not null,
  updated_by uuid not null,
  created_at timestamptz not null,
  updated_at timestamptz not null
)

document_versions (
  id uuid primary key,
  tenant_id uuid not null,
  document_id uuid not null,
  version_no int not null,
  markdown text not null,
  markdown_hash text not null,
  source_type text not null check (source_type in ('manual', 'upload', 'import', 'api')),
  source_file_id uuid null,
  created_by uuid not null,
  created_at timestamptz not null,
  unique (document_id, version_no)
)

4. 协作者和权限

collaborators 是语雀式内容对象权限的核心表。它只用于 knowledge_base 和 document。folder 因为也是 documents.type = folder,所以按 document 对象处理。

collaborators (
  id uuid primary key,
  tenant_id uuid not null,
  object_type text not null check (object_type in ('knowledge_base', 'document')),
  object_id uuid not null,
  subject_type text not null check (subject_type in ('user', 'group')),
  subject_id uuid not null,
  role text not null check (role in ('owner', 'manager', 'editor', 'viewer')),
  source text not null check (source in ('direct', 'invitation', 'system', 'transfer')),
  created_by uuid null,
  created_at timestamptz not null,
  unique (object_type, object_id, subject_type, subject_id)
)

不使用 OpenFGA/Casbin。workspace 成员关系由 workspace_members 表表达,不进入 collaborators

5. 邀请和分享

invitations.role 根据 object_type 使用不同的合法集合:

object_type = workspace: role in admin/member/guest
object_type = knowledge_base/document: role in manager/editor/viewer

普通邀请不授予 owner。owner 转让走单独接口和审计。

invitations (
  id uuid primary key,
  tenant_id uuid not null,
  object_type text not null check (object_type in ('workspace', 'knowledge_base', 'document')),
  object_id uuid not null,
  email text null,
  invited_user_id uuid null,
  role text not null,
  token_hash text not null,
  status text not null check (status in ('pending', 'accepted', 'rejected', 'expired', 'revoked', 'awaiting_approval')),
  require_approval boolean not null default false,
  approved_by uuid null,
  invited_by uuid not null,
  expires_at timestamptz null,
  max_uses int null,
  used_count int not null default 0,
  created_at timestamptz not null,
  constraint invitations_role_by_object check (
    (object_type = 'workspace' and role in ('admin', 'member', 'guest'))
    or (object_type in ('knowledge_base', 'document') and role in ('manager', 'editor', 'viewer'))
  )
)

share_links (
  id uuid primary key,
  tenant_id uuid not null,
  object_type text not null check (object_type in ('knowledge_base', 'document')),
  object_id uuid not null,
  token_hash text not null,
  permission text not null default 'view' check (permission = 'view'),
  password_hash text null,
  require_login boolean not null default false,
  restrict_to_workspace_members boolean not null default false,
  expires_at timestamptz null,
  revoked_at timestamptz null,
  created_by uuid not null,
  created_at timestamptz not null
)

share_links.permission 字段在 v0.x 固定为 view,只是为了和产品语义保持清晰以及未来保留扩展点。当前实现必须通过数据库约束和服务层校验禁止任何链接编辑权限。

6. 资源和导入

document_assets (
  id uuid primary key,
  tenant_id uuid not null,
  document_id uuid null,
  object_key text not null,
  mime_type text not null,
  size_bytes bigint not null,
  created_by uuid not null,
  created_at timestamptz not null
)

import_jobs (
  id uuid primary key,
  tenant_id uuid not null,
  workspace_id uuid not null,
  knowledge_base_id uuid not null,
  source_asset_id uuid not null,
  status text not null check (status in ('pending', 'running', 'succeeded', 'failed')),
  converter text not null,
  error text null,
  created_by uuid not null,
  created_at timestamptz not null,
  updated_at timestamptz not null
)

7. Chunks 和索引状态

PostgreSQL 保存 chunk 真相,Milvus 保存索引副本。

document_chunks (
  id uuid primary key,
  tenant_id uuid not null,
  workspace_id uuid not null,
  knowledge_base_id uuid not null,
  document_id uuid not null,
  version_id uuid not null,
  ordinal int not null,
  heading_path text[] not null default '{}',
  content_text text not null,
  content_markdown text not null,
  token_count int null,
  metadata jsonb not null default '{}',
  created_at timestamptz not null,
  unique (version_id, ordinal)
)

milvus_index_profiles (
  id uuid primary key,
  tenant_id uuid null,
  alias text not null,
  collection_name text not null,
  schema_version text not null,
  vector_dim int not null,
  embedding_function_name text not null,
  bm25_function_name text null,
  rerank_function_name text null,
  status text not null check (status in ('building', 'active', 'deprecated', 'failed')),
  function_metadata jsonb not null default '{}',
  created_by uuid not null,
  created_at timestamptz not null,
  activated_at timestamptz null
)

index_rebuild_jobs (
  id uuid primary key,
  tenant_id uuid null,
  target_collection text not null,
  target_alias text not null,
  status text not null check (status in ('pending', 'running', 'succeeded', 'failed', 'cancelled')),
  started_by uuid not null,
  started_at timestamptz not null,
  finished_at timestamptz null,
  error text null
)

OpenKB 不保存 embedding/rerank API key。密钥放 Milvus 或模型服务部署配置。

8. MCP OAuth / PAT 持久化

MCP 是用户级能力出口。所有 token、grant 和 PAT 必须能解析到真实 user。

mcp_oauth_clients (
  id uuid primary key,
  tenant_id uuid not null,
  client_id text unique not null,
  client_name text not null,
  redirect_uris text[] not null default '{}',
  allowed_scopes text[] not null default '{}',
  status text not null check (status in ('active', 'disabled')),
  created_by uuid not null,
  created_at timestamptz not null,
  updated_at timestamptz not null
)

mcp_oauth_grants (
  id uuid primary key,
  tenant_id uuid not null,
  user_id uuid not null,
  client_id uuid not null,
  scopes text[] not null default '{}',
  status text not null check (status in ('active', 'revoked')),
  expires_at timestamptz null,
  revoked_at timestamptz null,
  created_at timestamptz not null
)

mcp_oauth_authorization_codes (
  id uuid primary key,
  tenant_id uuid not null,
  grant_id uuid not null,
  code_hash text not null,
  redirect_uri text not null,
  scopes text[] not null default '{}',
  expires_at timestamptz not null,
  consumed_at timestamptz null,
  created_at timestamptz not null
)

mcp_oauth_refresh_tokens (
  id uuid primary key,
  tenant_id uuid not null,
  grant_id uuid not null,
  token_hash text not null,
  expires_at timestamptz not null,
  revoked_at timestamptz null,
  created_at timestamptz not null
)

mcp_personal_access_tokens (
  id uuid primary key,
  tenant_id uuid not null,
  user_id uuid not null,
  name text not null,
  token_hash text not null,
  scopes text[] not null default '{}',
  status text not null check (status in ('active', 'revoked', 'expired')),
  expires_at timestamptz null,
  last_used_at timestamptz null,
  revoked_at timestamptz null,
  created_at timestamptz not null
)

MCP access token 可以是短期 JWT,也可以落库;无论采用哪种方式,都不能让 token 脱离 user_id 和 tenant_id。

9. Dify scoped API key 持久化

Dify 是应用级检索出口,不是用户级权限出口。

dify_api_keys (
  id uuid primary key,
  tenant_id uuid not null,
  name text not null,
  key_hash text not null,
  status text not null check (status in ('active', 'disabled', 'revoked')),
  allowed_knowledge_base_ids uuid[] not null default '{}',
  allowed_metadata_filters jsonb not null default '{}',
  retrieval_top_k_limit int not null default 10,
  expires_at timestamptz null,
  last_used_at timestamptz null,
  created_by uuid not null,
  created_at timestamptz not null,
  updated_at timestamptz not null
)

dify_knowledge_mappings (
  id uuid primary key,
  tenant_id uuid not null,
  dify_knowledge_id text not null,
  knowledge_base_id uuid not null,
  status text not null check (status in ('active', 'disabled')),
  created_by uuid not null,
  created_at timestamptz not null,
  updated_at timestamptz not null,
  unique (tenant_id, dify_knowledge_id)
)

Dify 请求中的 knowledge_id 必须先映射到内部 knowledge_base_id,然后再检查当前 API key 是否允许访问该知识库。

10. 审计

audit_logs (
  id uuid primary key,
  tenant_id uuid null,
  actor_user_id uuid null,
  actor_type text not null check (actor_type in ('user', 'api_key', 'system')),
  action text not null,
  object_type text null,
  object_id uuid null,
  metadata jsonb not null default '{}',
  ip text null,
  user_agent text null,
  created_at timestamptz not null
)

Source: docs/08-api-contract.zh-CN.md

08 — API 合同

API 使用 REST + OpenAPI。所有敏感接口必须经过 Permission Service。

1. Auth

POST /api/auth/register
POST /api/auth/login
POST /api/auth/logout
GET  /api/auth/me
POST /api/auth/verify-email
POST /api/auth/password-reset/request
POST /api/auth/password-reset/confirm

2. Admin

GET  /api/admin/users
POST /api/admin/users/:id/activate
POST /api/admin/users/:id/suspend
GET  /api/admin/auth-settings
PUT  /api/admin/auth-settings
GET  /api/admin/audit-logs

Milvus 管理只允许 system_admin / tenant_admin:

GET  /api/admin/milvus/status
GET  /api/admin/milvus/index-profiles
POST /api/admin/milvus/rebuild-jobs
GET  /api/admin/milvus/rebuild-jobs/:id
POST /api/admin/milvus/aliases/switch

这些接口不保存模型 API key,只管理 OpenKB 侧可见的 index profile、job、alias 状态。

3. Workspace / KB / Document

GET    /api/workspaces
POST   /api/workspaces
GET    /api/workspaces/:id
PUT    /api/workspaces/:id

GET    /api/knowledge-bases
POST   /api/knowledge-bases
GET    /api/knowledge-bases/:id
PUT    /api/knowledge-bases/:id

GET    /api/knowledge-bases/:id/tree
POST   /api/documents
GET    /api/documents/:id
PUT    /api/documents/:id
DELETE /api/documents/:id
GET    /api/documents/:id/versions
POST   /api/documents/:id/versions
POST   /api/documents/:id/restore/:versionId

文档保存示例:

{
  "base_version_id": "ver_123",
  "title": "接入说明",
  "markdown": "# 接入说明\n...",
  "markdown_hash": "sha256..."
}

冲突返回:

{
  "error": "VERSION_CONFLICT",
  "current_version_id": "ver_124"
}

4. 协作者、邀请、分享

GET  /api/objects/:objectType/:objectId/collaborators
POST /api/objects/:objectType/:objectId/collaborators
PUT  /api/collaborators/:id
DELETE /api/collaborators/:id

POST /api/objects/:objectType/:objectId/invitations
GET  /api/invitations/:token
POST /api/invitations/:token/accept
POST /api/invitations/:id/approve
POST /api/invitations/:id/revoke

POST /api/objects/:objectType/:objectId/share-links
GET  /api/share/:token
POST /api/share/:token/verify-password
POST /api/share-links/:id/revoke

5. 搜索

POST /api/search

请求:

{
  "query": "MCP 怎么接入",
  "knowledge_base_ids": ["kb_1"],
  "top_k": 10,
  "filters": {
    "tags": ["mcp"]
  }
}

响应只能包含当前用户有权限访问的结果。

6. 导入

POST /api/uploads
POST /api/import-jobs
GET  /api/import-jobs/:id

导入成功后创建 document version 并进入索引队列。


Source: docs/09-search-rag-milvus-native.zh-CN.md

09 — Milvus 原生检索、Function 和索引重建

1. 最高原则

Milvus 是检索索引,不是业务数据库,也不是最终权限系统。
PostgreSQL 是文档、chunk 和权限真相。
Embedding / BM25 / rerank 优先使用 Milvus Server 2.6+ 原生 Function 能力。
OpenKB v0.x 不保存 embedding/rerank provider API key。

如果当前 Milvus/provider 暂时不兼容某个模型,v0.x 不在 OpenKB 内实现“旁路模型配置中心”来保存 embedding/rerank key。应在部署层更换为 Milvus 支持的 provider、TEI endpoint、vLLM ranker endpoint,或等待新的项目决策文档显式改变该规则。

2. OpenKB 管理什么

OpenKB 只管理:

Milvus URI/token/database
active alias
collection/index status
rebuild job
alias switch
health check

OpenKB 不管理:

embedding provider API key
rerank provider API key
知识库级模型配置
知识库级向量维度配置

3. Embedding Function

目标链路:

OpenKB writes raw chunk text + metadata to Milvus
  -> Milvus TEXTEMBEDDING Function calls provider service
  -> Milvus stores dense_vector

查询链路:

OpenKB sends query text
  -> Milvus uses same TEXTEMBEDDING Function to embed query
  -> vector search

适配 Qwen3 Embedding 的推荐部署:

Qwen3-Embedding service via TEI / compatible provider
Milvus TEXTEMBEDDING Function references that provider/endpoint
OpenKB only calls Milvus

4. BM25 / Sparse Search

知识库检索必须支持关键词能力。Milvus collection 中应包含:

content_text: VARCHAR
sparse_vector: SPARSE_FLOAT_VECTOR 或 Milvus BM25 Function 输出字段

检索时优先使用:

dense search + BM25/sparse search + hybrid fusion/ranker

5. Rerank Function

Rerank 优先放在 Milvus search-time Function 中。

推荐方式:

Qwen3-Reranker service via vLLM/TEI-compatible ranker
Milvus RERANK / Model Ranker Function references endpoint
OpenKB receives reranked results from Milvus

限制:

  • rerank 使用的字段必须是文本字段。
  • rerank 失败时可以降级为未 rerank 的 hybrid 结果,但必须记录日志。
  • rerank 不能绕过最终权限检查。
  • OpenKB 不保存 rerank API key。

6. Collection schema

默认 collection 按 embedding 维度和版本创建:

openkb_chunks_qwen3_1024_v1
openkb_chunks_qwen3_1024_v2
openkb_chunks_qwen3_2560_v1
openkb_chunks_custom_768_v1

检索使用 alias:

openkb_chunks_active

6.1 主键定稿

Milvus collection 使用:

id: VARCHAR primary key
chunk_id: VARCHAR regular field

v0.x 中:

id = string(document_chunks.id)
chunk_id = string(document_chunks.id)

也就是说,id 是 Milvus 主键字段,chunk_id 是为了 API 返回、过滤和可读性保留的普通字段。不要在 prompt 或代码里把 chunk_id 声明成 primary key。Dify/MCP/Web 返回里的 chunk_id 使用 document_chunks.id

6.2 推荐字段

id: VARCHAR primary key
chunk_id: VARCHAR
tenant_id: VARCHAR
workspace_id: VARCHAR
knowledge_base_id: VARCHAR
document_id: VARCHAR
version_id: VARCHAR
is_current: BOOL
doc_status: VARCHAR
title: VARCHAR
heading_path: ARRAY<VARCHAR>
content_text: VARCHAR
content_markdown: VARCHAR
metadata: JSON
access_principals: ARRAY<VARCHAR>
dense_vector: FLOAT_VECTOR(dim = current embedding dim)
sparse_vector: SPARSE_FLOAT_VECTOR optional
created_at: INT64 timestamp
updated_at: INT64 timestamp

7. 权限预过滤

Milvus filter 示例:

tenant_id == "t1"
and is_current == true
and doc_status == "published"
and ARRAY_CONTAINS_ANY(access_principals, [
  "user:u123",
  "group:g1",
  "workspace:w1:member",
  "kb:kb1:viewer"
])

这只是预过滤。最终必须回 PostgreSQL 调 Permission Service。

8. Rebuild 和 alias switch

Embedding 模型更换流程:

1. 管理员在 Milvus/模型服务部署层更新 provider、endpoint、credential。
2. 管理员在 OpenKB 后台创建 rebuild job。
3. OpenKB 创建新 Milvus collection。
4. collection schema 定义新的 TEXTEMBEDDING/BM25/RERANK functions。
5. OpenKB 从 PostgreSQL 读取当前有效 chunks。
6. OpenKB 写入 raw text、metadata、access_principals。
7. Milvus 生成 embedding 并建立索引。
8. OpenKB load collection 并执行 sample search。
9. OpenKB 切换 alias openkb_chunks_active -> new collection。
10. 旧 collection 保留 rollback window。
11. 稳定后 admin 可清理旧 collection。

禁止:

  • 在同一 active collection 混合新旧 embedding 模型向量。
  • 让知识库 owner 单独切换模型。
  • 让 OpenKB 保存 embedding/rerank provider API key。
  • 为了兼容某模型在 OpenKB DB 中临时保存 embedding/rerank key。

9. Retrieval Service

输入:

type RetrievalInput = {
  query: string;
  authContext: AuthContext;
  knowledgeBaseIds?: string[];
  topK: number;
  filters?: Record<string, unknown>;
};

输出:

type RetrievalResult = {
  documentId: string;
  chunkId: string;
  title: string;
  path: string;
  content: string;
  score: number;
  metadata: Record<string, unknown>;
};

流程:

resolve caller identity
  -> resolve readable principals
  -> Milvus search active alias with filters
  -> PostgreSQL final permission check
  -> trim/top_k
  -> return

10. Admin UI

后台页面:

系统设置 / Milvus 与索引
  - Milvus 连接状态
  - active alias
  - 当前 collection
  - vector dim
  - embedding function 名称
  - BM25 function 状态
  - rerank function 状态
  - 索引文档数/chunk 数
  - 触发全量重建
  - rebuild job 日志
  - alias 切换记录

不提供知识库级模型配置页面。


Source: docs/10-mcp-server.zh-CN.md

10 — MCP Server

1. 原则

MCP 是用户级能力出口。
MCP 返回的任何文档范围必须和当前用户在 Web 中可访问范围一致。
MCP 不能使用管理员 key 读全库。

2. Transport

主推 Streamable HTTP:

POST /mcp
GET  /.well-known/oauth-protected-resource

v0.x 不实现任意 stdio command spawn。即使提供本地开发 stdio 包装器,也只能连接远程 HTTP MCP,不允许根据用户输入执行 shell 命令。

3. 鉴权

支持两种方式:

OAuth / remote MCP

MCP client -> OAuth authorize -> access token -> /mcp

access token 必须包含或可解析:

user_id
tenant_id
scopes
client_id
grant_id

Personal Access Token

用于简单私有化接入:

Authorization: Bearer kbpat_xxx

PAT 绑定用户,不绑定管理员全库权限。

4. Scopes

默认只开放读:

kb:read
kb:search
doc:read

写工具后续再做,且必须单独授权。

5. Tools

第一版 tools:

kb.search
kb.get_document
kb.get_document_markdown
kb.get_toc
kb.list_workspaces
kb.list_knowledge_bases
kb.list_documents

kb.search

输入:

{
  "query": "string",
  "knowledge_base_ids": ["optional"],
  "top_k": 5,
  "filters": {}
}

输出只包含当前用户可读结果。

kb.get_document_markdown

返回完整 Markdown 前必须调用 canReadDocument

6. Resources

资源 URI:

kb://workspace/{workspace_id}
kb://knowledge-base/{kb_id}
kb://document/{document_id}
kb://document/{document_id}/markdown
kb://document/{document_id}/toc

不要全量列出大型知识库所有资源。分页或按最近访问/搜索结果暴露。

7. 审计

记录:

user_id
client_id
tool_name
query
document_ids_returned
ip
user_agent
created_at

8. 安全规则

  • MCP 不能绕过 Permission Service。
  • MCP 不能返回用户不可见的文档标题、片段、附件 URL。
  • MCP token 被撤销后必须立即失效。
  • MCP 返回 token 数量和 top_k 要有限制。

9. 持久化表

MCP OAuth / PAT 的持久化表在 docs/07-data-model.zh-CN.md 中定义:

mcp_oauth_clients
mcp_oauth_grants
mcp_oauth_authorization_codes
mcp_oauth_refresh_tokens
mcp_personal_access_tokens

实现要求:

  • OAuth grant 必须绑定 user_id 和 tenant_id。
  • PAT 必须绑定 user_id 和 tenant_id。
  • 不允许创建不绑定真实用户的 MCP 管理员全库 token。
  • access token 如果使用短期 JWT,可以不单独落库,但必须能从签名 token 解析到 user_id、tenant_id、scopes、client_id/grant_id。

Source: docs/11-dify-adapter.zh-CN.md

11 — Dify External Knowledge Adapter

1. 原则

Dify 是应用级检索出口。
Dify 使用 scoped API key。
Dify 不等于用户级权限。

MCP 绑定用户权限,Dify 绑定 API key 范围。这两者不能混淆。

2. Endpoint

POST /retrieval
Authorization: Bearer <api_key>
Content-Type: application/json

请求:

{
  "knowledge_id": "kb_xxx",
  "query": "怎么配置 MCP?",
  "retrieval_setting": {
    "top_k": 5,
    "score_threshold": 0.5
  },
  "metadata_condition": {
    "logical_operator": "and",
    "conditions": []
  }
}

响应:

{
  "records": [
    {
      "content": "...",
      "score": 0.87,
      "title": "MCP 接入说明",
      "metadata": {
        "document_id": "doc_1",
        "chunk_id": "chunk_1",
        "path": "/AI/MCP",
        "url": "https://kb.example.com/docs/doc_1"
      }
    }
  ]
}

metadata 必须是 object,不能是 null。

3. API key 范围

Dify API key 绑定:

tenant_id
allowed_knowledge_base_ids
allowed_metadata_filters
retrieval_top_k_limit
status
expires_at

Dify 不通过用户个人权限,而是通过 API key scope 限定知识库范围。

4. 权限

Dify 检索流程:

validate api key
  -> check knowledge_id allowed
  -> build app auth context
  -> Retrieval Service
  -> final scope check
  -> return records

不能因为 API key 存在就访问全租户知识库。

5. 持久化表

Dify scoped API key 和 knowledge_id 映射表在 docs/07-data-model.zh-CN.md 中定义:

dify_api_keys
dify_knowledge_mappings

实现要求:

  • API key 只保存 hash,不保存明文。
  • knowledge_id 必须通过 dify_knowledge_mappings 映射到内部 knowledge_base_id。
  • 映射成功后,还必须检查当前 API key 的 allowed_knowledge_base_ids
  • API key 不能访问全租户知识库,除非其 scope 明确列出对应知识库。

Source: docs/12-import-conversion.zh-CN.md

12 — 文件导入和 Markdown 转换

1. 原则

所有文件导入最终都转换为:

Markdown + assets + metadata + source file reference

Markdown 必须通过 Milkdown 当前启用插件的 parse/serialize 校验。

2. 支持文件

v0.x 支持:

PDF
DOCX
PPTX
XLSX
图片
HTML
CSV

3. 转换器接口

interface DocumentConverter {
  name: string;
  supports(input: ConvertInput): boolean;
  convert(input: ConvertInput): Promise<ConvertResult>;
}

type ConvertResult = {
  markdown: string;
  assets: ConvertedAsset[];
  intermediateJson?: unknown;
  warnings?: string[];
  confidence?: number;
};

4. 推荐转换器

  • MinerU:PDF、扫描 PDF、图片、复杂版面。
  • MarkItDown:Office、HTML、CSV 等轻量转换。
  • Pandoc:通用兜底。

转换器是 adapter,不是主系统依赖边界。

5. 导入流程

upload file
  -> save original to object storage
  -> create import_job
  -> converter worker
  -> markdown + assets
  -> Milkdown parse/serialize validation
  -> create document/version
  -> chunking job
  -> index rebuild/upsert job

6. 复杂内容处理

  • 简单表格:GFM table,前提是 Milkdown 当前 table feature 支持。
  • 复杂表格:只读 HTML block 或 asset。
  • 图表:图片 asset + alt text。
  • 公式:只有 Milkdown 对应插件启用时才可编辑,否则转 asset/只读块。
  • 无法表示的内容:不能静默丢弃,必须记录 warning。

Source: docs/13-deployment.zh-CN.md

13 — 部署

1. Docker Compose

服务:

web
api
mcp-server
dify-adapter
import-worker
index-worker
postgres
redis
minio-assets
milvus-standalone
milvus-etcd
milvus-minio
qwen-embedding-tei optional
qwen-reranker-vllm optional
mineru-worker optional

注意:OpenKB 自己的 MinIO 和 Milvus 内部对象存储可以分开,生产建议分开。

2. Milvus 配置

Milvus/provider 凭证放在:

milvus.yaml
Docker Compose env
K8s Secret + Helm values
provider service env

OpenKB 数据库不保存 embedding/rerank API key。

3. Helm

Helm values 需要支持:

postgres:
  external: false
redis:
  external: false
s3:
  external: false
milvus:
  mode: standalone # standalone | cluster | external
  external:
    uri: ""
    tokenSecret: ""
mcp:
  enabled: true
difyAdapter:
  enabled: true

4. 环境变量

OpenKB:

DATABASE_URL
REDIS_URL
S3_ENDPOINT
S3_BUCKET
S3_ACCESS_KEY
S3_SECRET_KEY
MILVUS_URI
MILVUS_TOKEN
MILVUS_DATABASE
MILVUS_ACTIVE_ALIAS=openkb_chunks_active
SMTP_HOST
SMTP_USER
SMTP_PASSWORD
APP_BASE_URL

Milvus/provider:由 Milvus 部署文档决定,不写入 OpenKB DB。


Source: docs/14-ui-routes.zh-CN.md

14 — UI 路由和页面

1. 公共页面

/login
/register
/verify-email
/share/:token

2. 应用页面

/app
/app/workspaces
/app/workspaces/:workspaceId
/app/kb/:kbId
/app/kb/:kbId/docs/:docId
/app/search

3. 文档页面布局

/app/kb/:kbId/docs/:docId
  - TopBar
  - LeftDocumentTree
  - DocumentTitle
  - MilkdownEditorOrReader
  - RightOutline
  - ShareAndCollaboratorPanel

4. 权限面板

位置:文档/知识库顶部“分享”或“协作”按钮。

包含:

  • 当前公开性。
  • 协作者列表。
  • 添加协作者。
  • 邀请链接。
  • 分享链接。
  • 密码访问。
  • 仅空间成员访问。
  • 关闭分享。

5. Admin 页面

/admin
/admin/users
/admin/auth-settings
/admin/milvus
/admin/milvus/rebuild-jobs
/admin/audit-logs

Admin 页面不显示“给某个知识库单独配置模型”的入口。

6. 知识库设置页

知识库 owner/manager 可以管理:

  • 标题。
  • 描述。
  • 公开性。
  • 协作者。
  • 邀请/分享。
  • 目录。

不能管理:

  • Embedding 模型。
  • Rerank 模型。
  • LLM 模型。
  • Milvus collection。

Source: docs/15-roadmap-and-codex-tasks.zh-CN.md

15 — 开发路线和 Codex 任务

Phase 0 — 读文档和确认约束

目标:Codex 总结规则,不写代码。

输出:

  • 不可违反规则。
  • 架构摘要。
  • 首批里程碑。
  • 发现的矛盾。

Phase 1 — Monorepo 脚手架

输出:

  • pnpm workspaces。
  • Turborepo。
  • apps/web Next.js。
  • apps/api NestJS/Fastify。
  • packages/shared/db/permissions/editor/milvus。
  • 基础 README 和 smoke tests。

Phase 2 — 数据库模型

输出:

  • Prisma schema。
  • SQL migrations。
  • users/tenants/workspaces/kbs/documents/versions/collaborators/invitations/share_links/audit_logs。
  • seed first admin。

Phase 3 — Auth 和注册

输出:

  • 邮箱注册。
  • 邮箱验证。
  • 登录。
  • admin 激活。
  • 注册设置。

Phase 4 — 语雀式权限服务

输出:

  • Permission Service。
  • canRead/canEdit/canManage。
  • 协作者、公开性、分享链接、邀请审批。
  • 单元测试。

Phase 5 — Milkdown 编辑器

输出:

  • 文档树。
  • Milkdown 编辑器。
  • 阅读/编辑/源码模式。
  • 版本保存和冲突。
  • Feature Registry。

Phase 6 — 文件导入

输出:

  • 上传。
  • import_jobs。
  • converter adapters。
  • Milkdown dialect validation。

Phase 7 — Milvus 原生 Function 索引

输出:

  • packages/milvus。
  • 创建 collection schema。
  • TEXTEMBEDDING/BM25/RERANK Function 配置代码。
  • rebuild job。
  • alias switch。
  • health check。

Phase 8 — Retrieval Service

输出:

  • Milvus active alias 检索。
  • access_principals 预过滤。
  • PostgreSQL final permission check。
  • Web search API。

Phase 9 — MCP Server

输出:

  • Streamable HTTP MCP。
  • OAuth/PAT。
  • kb.search / kb.get_document / kb.get_toc。
  • 用户权限绑定。
  • 审计。

Phase 10 — Dify Adapter

输出:

  • /retrieval。
  • scoped API key。
  • knowledge_id mapping。
  • metadata_condition。

Phase 11 — 部署

输出:

  • Docker Compose。
  • Helm chart。
  • Milvus standalone/external。
  • MinIO/Postgres/Redis。

Source: docs/16-decisions-and-non-goals.zh-CN.md

16 — 项目决策和非目标

已定决策

  1. Markdown 方言完全跟随 Milkdown。
  2. 文档持久化内容是 Markdown。
  3. 权限完整按语雀式产品逻辑实现。
  4. v0.x 不引入 OpenFGA/Casbin/OPA/LDAP/SCIM。
  5. 系统/租户 admin 可以访问后台配置,但不默认可读全库私有内容。
  6. 知识库 owner 不能配置模型。
  7. Embedding/Rerank 优先放 Milvus 2.6+ 原生 Functions。
  8. OpenKB 不保存 embedding/rerank API key。
  9. Embedding 模型更换走新 collection + rebuild + alias switch。
  10. Milvus 只做索引,PostgreSQL 是权限真相。
  11. MCP 必须用户权限绑定。
  12. Dify 必须 API key scoped。

非目标

  • 不做语雀表格文档和画板/思维图文档。
  • 不做知识库级模型配置。
  • 不做管理员默认全库检索。
  • 不做复杂 IAM 产品。
  • 不做未授权匿名编辑。
  • 不做任意 stdio MCP command execution。

允许后续扩展但不进入 v0.x

  • 实时协作 Y.js。
  • 评论/批注。
  • OIDC/SAML 登录。
  • 企业组织同步。
  • 复杂图表块。
  • AI 写作助手。
  • Qdrant/pgvector adapter。

Source: docs/17-glossary.zh-CN.md

17 — 术语表

术语 含义
OpenKB 本项目。
Tenant 实例或租户。
Workspace / 空间 团队协作边界。
Knowledge Base / 知识库 文档集合。
Document 文档或文件夹。
Milkdown OpenKB 使用的 Markdown 富文本编辑器。
Feature Registry 当前编辑器支持能力的注册表。
Collaborator 协作者。
Share Link 只读分享链接。
Invitation Link 邀请用户成为协作者的链接。
Milvus Function Milvus 侧 TEXTEMBEDDING、BM25、RERANK 等函数能力。
Active Alias 当前检索使用的 Milvus collection alias。
Access Principals 写入 Milvus 用于权限预过滤的主体 token。
MCP Model Context Protocol,用户权限绑定的知识库服务出口。
Dify Adapter Dify External Knowledge API 接口。

Source: docs/18-decision-overrides-v0.3.zh-CN.md

18 — v0.3 项目决策覆盖清单

本文件是给 Codex / coding agent 的决策摘要。实现冲突时,以本文件和根目录 AGENTS.md 为准;docs/16-decisions-and-non-goals.zh-CN.md 只作为基础摘要,不得覆盖本文件。

1. Markdown 方言跟随 Milkdown

OpenKB Markdown = 当前锁定版本 Milkdown + 当前启用 plugins/features 的可往返 Markdown 集合。

要求:建立 EDITOR_FEATURES registry;slash menu、toolbar、renderer、source mode validator、converter validator 都从 registry 读取能力;自定义语法必须先实现 Milkdown plugin;所有启用能力必须有 round-trip 测试。

2. 权限完整向语雀对齐

v0.x 只做语雀式:空间、知识库、文档、协作者、邀请、分享、审批、密码、仅空间成员访问、关闭/重置链接。

不做 LDAP、SCIM、OpenFGA、Casbin、OPA、自定义 ABAC。外部身份系统未来只能作为登录/用户导入来源,不能替代语雀式对象权限。

3. 知识库 owner 不能配置模型

模型、Milvus、索引、LLM 配置只属于 system_admin / tenant_admin。知识库 owner、workspace owner、document owner 都不能配置 embedding、rerank、LLM。知识库设置页只能展示索引状态,不能出现模型配置入口。

4. Embedding/rerank 尽量放到 Milvus 侧

Embedding: Milvus TEXTEMBEDDING Function。
BM25: Milvus BM25 Function。
Rerank: Milvus RERANK Function / Model Ranker。

OpenKB v0.x 不保存 embedding/rerank API key,也不实现旁路 embedding/rerank 模型配置中心。Qwen embedding 推荐通过 TEI 或 Milvus 支持的 provider;Qwen rerank 推荐通过 vLLM/TEI ranker 或 Milvus 支持的 ranker。如果未来需要 fallback,必须通过新的版本化项目决策文档显式改变本规则,Codex 不得自行添加。

5. Embedding 更换走 Milvus collection/index/alias

流程:

新建 collection -> 新 schema + Function + index -> 插入当前 chunks raw text -> Milvus 生成 embedding -> load + validate -> alias switch -> 旧 collection rollback window

禁止在旧 collection 混写新向量。即使维度一样,也建议新建 collection,避免向量空间混杂。

6. 权限最终判断仍在 PostgreSQL

Milvus candidate chunks -> PostgreSQL can_read(document, subject) -> return

Milvus access_principals 只能做预过滤。Web、MCP、Dify、导出、附件读取都必须调用同一套最终权限判断。

7. MCP 用户级,Dify 应用级

MCP 绑定真实用户,使用用户自己的文档权限;Dify 绑定 integration key,使用管理员授予的知识库范围。两者都不能绕过最终权限检查。

8. v0.3.2 澄清

Codex 首轮阅读发现的 4 个点已按以下方式定稿:

  1. 优先级:AGENTS.md + docs/18-decision-overrides-v0.3.zh-CN.md 是最高优先级;docs/16-decisions-and-non-goals.zh-CN.md 是基础决策摘要。
  2. 提示词:prompts/01-read-and-plan.md 必须包含 docs/18 和本澄清文件,不能只读 docs/16
  3. 分享链接:v0.x 分享链接只读,share_links.permission 固定为 view,实现时必须加数据库约束或等价服务层保护。
  4. 目录:Folder / 目录 是产品概念,数据库中使用 documents.type = folder 表达,不单独建立 folders 表。

9. v0.3.3 澄清

Codex 第二轮阅读发现的 5 个点按以下方式定稿:

  1. Workspace 角色和内容对象角色分开:
    • workspace_members.role = owner | admin | member | guest
    • collaborators.role = owner | manager | editor | viewer,仅用于 knowledge_base/document。
    • Workspace 邀请写入 workspace_members,角色只能是 admin/member/guest;普通邀请不授予 owner。
    • Knowledge base/document 邀请写入 collaborators,角色只能是 manager/editor/viewer;普通邀请不授予 owner。
  2. Milvus 主键固定为 id primary key;chunk_id 是普通字段。v0.x 中两者值都等于 PostgreSQL document_chunks.id 的字符串形式。
  3. auth_settings 必须在数据模型中实现,不能只在 auth 文档和 prompt 中提到。
  4. MCP OAuth/PAT 和 Dify scoped API key 必须有明确持久化表,见 docs/07-data-model.zh-CN.md
  5. OpenKB v0.x 不保存 embedding/rerank provider API key;docs/18 旧表述中的 fallback 不适用于当前硬规则。

Source: docs/19-codex-start-guide.zh-CN.md

19 — 如何和 Codex 启动这个项目

0. 准备仓库

把本包解压到新仓库根目录:

mkdir openkb
cd openkb
# 解压 openkb-codex-bootstrap-v0.3.3.zip 到这里
git init

确认根目录有:

AGENTS.md
README.md
OPENKB_MASTER_SPEC.md
docs/
prompts/
apps/
packages/
workers/
deploy/

1. 第一轮:只读文档,不写代码

先把 prompts/01-read-and-plan.md 的内容发给 Codex。目标是看它有没有吃进去硬约束。

如果 Codex 总结里出现这些内容,要立刻纠正:

  • 知识库 owner 可以配置模型。
  • OpenKB 自己保存 embedding/rerank API key。
  • 使用 OpenFGA/Casbin/LDAP 作为 v0.x 权限基础。
  • 自定义 Markdown 方言。
  • MCP 用管理员 key 搜全库。
  • 搜索结果不做 PostgreSQL 最终权限校验。

2. 第二轮:只搭 scaffold

使用 prompts/02-scaffold.md。这一轮只建立 monorepo、package、基础配置、空目录和 smoke tests,不实现业务。

3. 第三轮:数据库和注册登录

使用 prompts/03-database-auth.md。先把用户、租户、空间、知识库、文档、权限关系、邀请、分享、Milvus job 表建好。

4. 第四轮:语雀式权限服务

使用 prompts/04-permissions.md。权限服务要先写测试,再写实现。MCP、Dify、搜索、附件、导出都复用这套判断。

5. 第五轮:Milkdown 编辑器

使用 prompts/05-editor.md。重点是 Milkdown-native、Markdown-first、feature registry、round-trip tests。

6. 第六轮:Milvus-native indexing

使用 prompts/06-milvus.md。重点是 Milvus 2.6+ Functions、raw text 写入、active alias、rebuild、rollback、权限预过滤 + PostgreSQL 终检。

7. 第七轮:MCP 和 Dify

使用 prompts/07-mcp-dify.md。MCP 先 read-only,Dify 实现 /retrieval

8. 工作方式建议

每一轮让 Codex:

  1. 先说明它准备修改哪些文件。
  2. 再执行修改。
  3. 最后跑测试或 smoke check。
  4. 输出后续待办。

不要让 Codex 一次性实现整个项目。


Source: docs/20-codex-prompts.zh-CN.md

20 — Codex Prompts 索引

本目录已经把可复制的 prompt 放在 prompts/ 下。

推荐顺序

prompts/01-read-and-plan.md
prompts/02-scaffold.md
prompts/03-database-auth.md
prompts/04-permissions.md
prompts/05-editor.md
prompts/06-milvus.md
prompts/07-mcp-dify.md

使用原则

  • 一次只做一个阶段。
  • 不要让 Codex 跳过权限服务直接做 MCP。
  • 不要让 Codex 跳过 Milkdown feature registry 直接写编辑器。
  • 不要让 Codex 把 embedding/rerank API key 存进 OpenKB 数据库。
  • 不要让 Codex 增加知识库级模型配置。
  • 每个阶段结束后提交 git commit,再进入下一阶段。

Source: docs/21-v0.3.2-clarifications.zh-CN.md

21 — v0.3.2 澄清和修正

本文件记录 Codex 首轮读文档后发现的矛盾点,以及本版本的最终处理方式。

1. 优先级文档差异

问题:AGENTS.md 要求优先读 docs/18-decision-overrides-v0.3.zh-CN.md,但旧版 docs/00-index.zh-CN.mdprompts/01-read-and-plan.md 指向 docs/16-decisions-and-non-goals.zh-CN.md

处理:已统一为:

最高优先级:AGENTS.md
第二优先级:docs/18-decision-overrides-v0.3.zh-CN.md
第三优先级:本文件 docs/21-v0.3.2-clarifications.zh-CN.md
基础摘要:docs/16-decisions-and-non-goals.zh-CN.md

如果 docs/18docs/16 有措辞差异,以 docs/18 为准。

2. prompts/01-read-and-plan.md 漏读 docs/18

问题:旧版第一轮提示词没有把 docs/18 放进优先文档列表。

处理:已修正。Codex 第一轮必须阅读:

AGENTS.md
docs/00-index.zh-CN.md
docs/18-decision-overrides-v0.3.zh-CN.md
docs/21-v0.3.2-clarifications.zh-CN.md
docs/04-editor-spec.zh-CN.md
docs/05-permission-spec.zh-CN.md
docs/09-search-rag-milvus-native.zh-CN.md
docs/15-roadmap-and-codex-tasks.zh-CN.md
docs/16-decisions-and-non-goals.zh-CN.md

3. share_links.permission 字段

问题:数据模型里有 share_links.permission default 'view',但权限规格写明 v0.x 不支持链接编辑权限。

处理:v0.x 固定只读分享链接。实现必须使用下面之一防止误用:

permission text not null default 'view' check (permission = 'view')

或等价数据库约束 + 服务层校验。

禁止实现:

link editor
link manager
anonymous edit by share link

4. Folder / 目录的实现方式

问题:对象层级中单列 Folder / 目录,但数据模型中用 documents.type = folder | page 表达。

处理:这不是功能冲突,最终实现方式如下:

Folder 是产品/UI 概念。
数据库不建 folders 表。
目录节点和文档页统一存在 documents 表。
documents.type = folder 表示目录节点。
documents.type = page 表示正文文档。

folder 可以参与目录树、排序、继承和协作者范围,但 v0.x 不保存可编辑 Markdown 正文。


Source: docs/22-v0.3.3-clarifications.zh-CN.md

22 — v0.3.3 澄清和修正

本文件记录 Codex 第二轮读文档后发现的矛盾点,以及本版本的最终处理方式。

1. Workspace 角色映射

问题:文档里 workspace 邀请角色出现过 manager/editor/viewer,但 workspace_members 表使用 owner/admin/member/guest。

判断:这是合理矛盾,必须修。workspace 成员角色和内容对象协作者角色不是一套东西。

最终处理:

workspace_members.role = owner | admin | member | guest
collaborators.role = owner | manager | editor | viewer

Workspace 邀请:

object_type = workspace
role = admin | member | guest
接受后写入 workspace_members

Knowledge base / document 邀请:

object_type = knowledge_base | document
role = manager | editor | viewer
接受后写入 collaborators

普通邀请不授予 owner。owner 只能通过创建、系统初始化或转让产生。

2. Milvus 主键

问题:docs/09 推荐 id primary key + chunk_id 字段,但 prompts/06 写了 chunk_id primary key

判断:这是合理矛盾,必须修。

最终处理:Milvus collection 使用:

id: VARCHAR primary key
chunk_id: VARCHAR regular field

v0.x 中:

id = string(document_chunks.id)
chunk_id = string(document_chunks.id)

chunk_id 不再作为 Milvus primary key。Codex 实现时必须以 id 为 primary key。

3. auth_settings 表

问题:docs/06 和 prompts 要求 auth_settings,但旧版 docs/07 没给具体表结构。

判断:这是合理缺口,必须补。

最终处理:docs/07-data-model.zh-CN.md 已新增 auth_settings 表,包括:

registration_enabled
email_verification_required
default_signup_status
invited_user_auto_active
allowed_email_domains
invite_required
first_user_becomes_admin

4. MCP / Dify 持久化表

问题:MCP OAuth/PAT、Dify scoped API key 在旧版数据模型里没有展开。

判断:这是合理缺口,必须补。否则 Codex 会自己发明表结构。

最终处理:docs/07-data-model.zh-CN.md 已新增:

mcp_oauth_clients
mcp_oauth_grants
mcp_oauth_authorization_codes
mcp_oauth_refresh_tokens
mcp_personal_access_tokens

dify_api_keys
dify_knowledge_mappings

5. embedding/rerank fallback 表述

问题:docs/18 曾写“除非项目 owner 明确要求 fallback”,但当前硬规则应是 OpenKB v0.x 不保存 embedding/rerank key。

判断:这是合理矛盾,必须收紧。

最终处理:当前版本硬规则:

OpenKB v0.x 不保存 embedding/rerank provider API key。
OpenKB v0.x 不实现旁路 embedding/rerank 模型配置中心。
embedding/rerank 走 Milvus Function、Milvus 部署配置、TEI/vLLM/provider 服务配置。

如果未来确实要 fallback,必须新增版本化项目决策文档;Codex 不得自行添加。


Source: docs/99-references.md

99 — References

This project intentionally follows public product/API documentation where useful.

Milkdown

Milvus

MCP

Codex

Dify


Source: prompts/01-read-and-plan.md

Read the repository documents first. Do not modify files yet.

Priority documents:

  • AGENTS.md
  • docs/00-index.zh-CN.md
  • docs/18-decision-overrides-v0.3.zh-CN.md
  • docs/21-v0.3.2-clarifications.zh-CN.md
  • docs/22-v0.3.3-clarifications.zh-CN.md
  • docs/04-editor-spec.zh-CN.md
  • docs/05-permission-spec.zh-CN.md
  • docs/09-search-rag-milvus-native.zh-CN.md
  • docs/15-roadmap-and-codex-tasks.zh-CN.md
  • docs/16-decisions-and-non-goals.zh-CN.md

After reading, produce:

  1. A concise summary of the non-negotiable architecture rules.
  2. The proposed monorepo structure.
  3. The first 5 implementation milestones.
  4. Any contradictions found in the spec.

Important:

  • Do not implement anything in this turn.
  • Do not introduce custom Markdown dialects.
  • Do not introduce non-Yuque permission systems.
  • Do not create per-knowledge-base model configuration.
  • Use Milvus 2.6+ native Function support for embedding/rerank where compatible.
  • Treat docs/18 as higher priority than docs/16 if there is any wording difference.
  • Treat share links as read-only only in v0.x.
  • Treat folders as documents with type=folder, not as a separate table.
  • Treat workspace membership roles and content collaborator roles as separate systems.
  • Use id as the Milvus primary key; chunk_id is a regular field.
  • Do not implement embedding/rerank fallback keys in OpenKB DB.

Source: prompts/02-scaffold.md

Create the initial monorepo scaffold only.

Use:

  • apps/web
  • apps/api
  • apps/mcp-server
  • apps/dify-adapter
  • workers/import-worker
  • workers/index-worker
  • packages/shared
  • packages/db
  • packages/auth
  • packages/permissions
  • packages/editor
  • packages/markdown
  • packages/milvus
  • packages/retrieval
  • deploy/docker-compose
  • deploy/helm

Requirements:

  • TypeScript for web/api/shared packages.
  • Next.js for apps/web.
  • NestJS with Fastify adapter for apps/api unless you find a strong reason otherwise.
  • PostgreSQL migration setup.
  • Redis queue placeholder.
  • Milvus client package placeholder.
  • No business features yet.
  • Add README sections explaining how to run locally.
  • Add tests only for smoke checks.

Do not implement editor, permissions, MCP, Dify, or Milvus indexing yet.


Source: prompts/03-database-auth.md

Implement Phase 1 database schema and auth foundations.

Scope:

  • users
  • tenants
  • tenant_memberships
  • auth_settings
  • workspaces
  • workspace_members
  • groups
  • group_members
  • knowledge_bases
  • documents
  • document_versions
  • collaborators
  • invitations
  • share_links
  • document_assets
  • import_jobs
  • document_chunks
  • audit_logs
  • milvus_index_profiles
  • index_rebuild_jobs
  • mcp_oauth_clients
  • mcp_oauth_grants
  • mcp_oauth_authorization_codes
  • mcp_oauth_refresh_tokens
  • mcp_personal_access_tokens
  • dify_api_keys
  • dify_knowledge_mappings

Rules:

  • Follow docs/05-permission-spec.zh-CN.md.
  • Follow docs/07-data-model.zh-CN.md exactly for role constraints.
  • Do not add LDAP/OpenFGA/Casbin/OPA.
  • Do not add model config per knowledge base.
  • Do not store embedding/rerank API keys in OpenKB DB.
  • Use PostgreSQL as permission truth.
  • Workspace roles are owner/admin/member/guest and live in workspace_members.
  • Content collaborator roles are owner/manager/editor/viewer and live in collaborators.
  • share_links.permission must be constrained to view only.

Deliver:

  • Migration files.
  • Type-safe database models.
  • Basic seed script for first admin user.
  • Minimal tests for constraints.

Source: prompts/04-permissions.md

Implement the Yuque-style permission service.

Scope:

  • canReadDocument
  • canEditDocument
  • canManageDocument
  • canManageKnowledgeBase
  • canInviteCollaborator
  • canCreateShareLink
  • resolveEffectiveRole
  • resolveWorkspaceRole
  • resolveReadablePrincipalsForMilvus

Rules:

  • Match docs/05-permission-spec.zh-CN.md.
  • Workspace roles are owner/admin/member/guest and are stored in workspace_members.
  • Content roles are owner/manager/editor/viewer and are stored in collaborators.
  • Workspace invitations write workspace_members and can grant admin/member/guest only.
  • Knowledge base/document invitations write collaborators and can grant manager/editor/viewer only.
  • Ordinary invitations do not grant owner.
  • Support workspace, knowledge base, folder, document inheritance.
  • Support direct collaborators, invitation acceptance, share links.
  • No explicit deny in v0.1.
  • No LDAP/OpenFGA/Casbin.

Add unit tests covering:

  • workspace member can access workspace-visible knowledge base
  • workspace guest cannot access workspace-visible knowledge base unless directly invited
  • workspace admin does not automatically read private knowledge base
  • private knowledge base only collaborators can access
  • document custom permission overrides inheritance
  • removed collaborator loses access
  • workspace invitation role constraints
  • content invitation role constraints
  • MCP search principals only include current user's allowed scopes

Source: prompts/05-editor.md

Implement the first version of the Markdown editor page.

Scope:

  • Milkdown editor integration.
  • Feature Registry in packages/editor.
  • Markdown-first storage.
  • Document read/edit route.
  • Left document tree.
  • Right outline generated from headings.
  • Save Markdown content through API.
  • Version conflict handling using current document version.

Rules:

  • Markdown dialect follows enabled Milkdown features exactly.
  • Do not define a custom Markdown subset.
  • Source mode must validate through Milkdown parse/serialize.
  • Do not implement real-time collaboration yet.
  • Do not implement table document or mind map document.
  • Only rich-text Markdown document type for now.

Source: prompts/06-milvus.md

Implement Milvus indexing foundation using Milvus Server 2.6+ native Functions.

Scope:

  • packages/milvus
  • create collection schema with:
    • id VARCHAR primary key
    • chunk_id VARCHAR regular field
    • tenant_id
    • workspace_id
    • knowledge_base_id
    • document_id
    • version_id
    • content_text VARCHAR
    • content_markdown VARCHAR
    • metadata JSON
    • access_principals ARRAY
    • dense vector field
    • sparse/BM25 field if supported by Milvus Function
  • In v0.x set both id and chunk_id to string(document_chunks.id).
  • Add TEXTEMBEDDING Function for compatible provider, preferably TEI for Qwen embeddings.
  • Add BM25 Function for sparse retrieval where supported.
  • Add RERANK/Model Ranker configuration where supported.
  • Use active collection alias: openkb_chunks_active.
  • Implement rebuild job:
    • read current document chunks from PostgreSQL
    • insert raw chunk text and metadata into new Milvus collection
    • let Milvus generate embeddings
    • load collection
    • health check
    • switch alias

Rules:

  • Do not use chunk_id as Milvus primary key.
  • Do not call embedding API from OpenKB directly.
  • Do not store embedding/rerank API key in OpenKB database.
  • Do not implement embedding/rerank fallback provider secrets in OpenKB DB.
  • Do not allow knowledge base owner to configure models.
  • Only admin can trigger global reindex.
  • PostgreSQL final permission check remains mandatory after Milvus retrieval.

Source: prompts/07-mcp-dify.md

Implement MCP Server and Dify Adapter after permissions and retrieval are working.

MCP scope:

  • Streamable HTTP endpoint.
  • OAuth/PAT user-bound auth.
  • Persistent tables from docs/07-data-model.zh-CN.md:
    • mcp_oauth_clients
    • mcp_oauth_grants
    • mcp_oauth_authorization_codes
    • mcp_oauth_refresh_tokens
    • mcp_personal_access_tokens
  • Tools: kb.search, kb.get_document, kb.get_document_markdown, kb.get_toc, kb.list_workspaces, kb.list_knowledge_bases.
  • Audit every tool call.
  • Always call Permission Service.

Dify scope:

  • POST /retrieval.
  • Scoped API key.
  • Persistent tables from docs/07-data-model.zh-CN.md:
    • dify_api_keys
    • dify_knowledge_mappings
  • knowledge_id mapping.
  • retrieval_setting.top_k and score_threshold.
  • metadata_condition mapping.
  • Return metadata as object, never null.

Rules:

  • MCP is user-bound.
  • Dify is app-key-bound.
  • Neither can bypass document permissions/scopes.
  • Dify API key is scoped by allowed_knowledge_base_ids.
  • API keys and tokens are stored as hashes only.