Skip to content

About

ontology_management

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

255 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

本体管理平台

本体管理平台

Ontology Management

本体建模 · 版本化快照 · 可插拔图存储 · 数据资源 · 智能问答与 MCP
默认使用平台自带的内置图存储;Apache Jena / Fuseki 是可选后端,随时可换

Version Next.js React TypeScript

Graph Store PostgreSQL MCP AI SDK pnpm Vitest License Status


平台管三件事:本体是什么(对象类型、关系类型、接口、概念分组)、本体能做什么(动作与规则)、本体里的数据从哪来(数据资源绑定与对象检索)。本体按版本快照管理:草稿与历史快照都写平台库,发布才重建图数据。

图存储是可替换的:默认用平台自带的内置图存储(PostgreSQL 持久化,不需要外部服务),也可以在「设置 → 图引擎配置」里登记 Apache Jena / Fuseki;上层 API 与界面只调用 GraphStore 抽象。PostgreSQL ontology_platform 保存账号、连接、审计、本体定义/版本、编辑层和压缩历史;ClickHouse 只保存 ODS 源表镜像,查询时按当前版本形成对象。

本体类型与实例数据统一按 版本快照 管理:

草稿编辑 → 校验 → 发布 / 激活 → 重建图数据
   │                                    │
   └──── 版本写进平台库(定义 + 快照)────┘  成功后才更新版本状态

目录

能力概览

按 Palantir 的说法,本体由两部分组成,左侧导航也是按这个分的:

是什么 平台里的位置
本体模型 本体「是什么」:对象类型(Object Type)与它们的属性、关系类型、接口、概念分组 本体建模 · 本体技能
本体实例 本体里"实际有什么":对象与关系,以及它们的实例图谱 实例图谱 · 对象 · 关系
动力模型 本体「能做什么」:动作(唯一的业务写入口),以及挂在动作上的规则 / 动态安全 动作 · 规则
能力验证 把本体交给模型与外部 Agent 用起来:智能问答(工具循环)与 MCP 服务 智能问答 · MCP 调试

「总览」同时展示当前本体的运行状态与本体列表,可在列表中搜索、新建、导入、打开或导出。数据资源(本体的数据来自哪张表)与本体存储(本体落在哪个图库)是平台层;图引擎连接在「设置 → 图引擎配置」管理。

模块 说明
📐 本体建模 对象类型、关系类型、端点契约与属性规则;保存为草稿,校验后发布
🔗 对象与关系 对象绑定单一已发布类型(Label);关系端点须符合契约
🪪 接口(Interfaces) 抽象契约:只描述"实现我的对象类型必须有哪些属性与关系",不绑数据、不能实例化;一个对象类型可实现多个接口、接口可继承接口。本体建模的「接口」标签可查看定义和实现情况
🧩 属性系统 文本 / 整数 / 小数 / 布尔 / 日期 / 日期时间 / 文本数组 / JSON;每个属性可带显示名与说明(外部本体的中文名与口径原文能原样带进来)
👁 建模与实例图谱 本体建模画布查看和搜索对象类型、属性、关系类型;图谱只展示实例。两处节点都可拖拽摆放:有草稿的实例位置写入图快照,建模画布的位置只记在本机浏览器
⌨️ 只读查询 实例图谱页可展开的只读查询(内置与 Jena 共用同一套模板);写入一律拒绝,避免绕过版本
🗄 图引擎配置 内置图存储开箱可用;也可登记 Apache Jena / Fuseki,凭据 AES-256-GCM 加密入库
🔌 存储抽象 GraphStore 契约 + 注册表(内置 / Jena 两个适配器),业务 API 不直接依赖具体引擎
🧱 数据资源 外部关系库的只读连接(PostgreSQL / MySQL / Oracle):列结构、字段与数据预览,再把类绑到表上(一个类可挂多份来源,按主键合并属性)
📦 统一版本 类型 + 对象 + 关系完整快照;草稿与快照都写平台库,发布才写图
📤 本体包 一个 .ontology.json 带走整份结构(类 / 关系类型 / 动作 / 规则 + 数据资源坐标),导入停在草稿。不含实例数据,也不含凭据
🧭 概念分组 画布上的逻辑分组:先建分组,再在对象类型上选归属;智能问答可以按分组找类型
🤖 智能问答 服务端工具循环(AI SDK):模型只调只读工具(本体检索、多跳、表结构、只读 SQL),流式输出、可中断、可带图片、带会话历史
🛰 MCP 两个服务端:本体数据工具(会话或令牌)与建模技能(免令牌),外部 Agent / IDE 直接接
✨ 本体技能 三套建模技能(需求澄清 → 本体设计 → 出包交付),整包下载,或经 MCP 直接给 Agent 用
🔍 对象检索 默认虚拟查询(查询时回源投影对象);大表可先把裁剪列同步成 ClickHouse ODS 源表副本,再在对象服务与 run_query 中实时过滤/聚合;不依赖对象物化副本
🧾 审计记录 发布、导入、删除、改名等关键操作留痕,在「设置 → 审计记录」里按动作筛选

术语对照(中文 ↔ 代码 / 接口)

界面上和文档里用中文,代码目录与 URL 用英文 —— 这张表把两边对上。 其中「本体管理」指的是本体这个实体本身的增删改查(列 / 建 / 改 / 删、导入导出、绑数据来源), 跟「本体模型」(类型定义与版本)不是一回事:

中文叫法 代码目录 接口
本体管理(本体台账:列 / 建 / 改 / 删、导入、导出、绑来源) src/lib/platform/ontologies.ts /api/ontologies/*
本体模型(对象类型 / 关系类型 / 接口 / 指标 / 分组的定义,以及草稿→校验→发布→激活) src/lib/ontology/ · src/lib/versioning/ /api/ontology/*
本体实例(对象 / 关系 / 实例图谱) src/lib/instance/ /api/instances/* · /api/objects/*
数据资源(外部业务库的只读连接与结构) src/lib/datasource/ /api/data-sources/*
图引擎配置(内置图 / Jena 连接) src/lib/platform/targets.ts · src/lib/platform/graph-store.ts · src/lib/infrastructure/graph/ /api/targets/*
能力验证(智能问答 / MCP) src/lib/reasoning/ · src/lib/mcp/ /api/reasoning/* · /api/mcp
本体技能(建模技能与整包下载) src/lib/skills/ · skills/ /api/skills/*
平台(账号 / 角色 / 权限 / 审计) src/lib/platform/ /api/users · /api/roles · /api/audit

同一份对照也用在 /docs:Swagger 里的分组名就是上表第一列(/api/ontologies/* 那组显示为「本体管理」, /api/ontology/* 那组显示为「本体模型」)。URL 段保持英文复数(REST 资源名惯例),不改成中文。

技术栈

层级 选型
前端 / API Next.js 16(App Router)、React 19、TypeScript
本体存储 默认内置图存储(PostgreSQL 持久化 + Graphology 类型图 + N3.js / Comunica 只读 SPARQL);可选 Apache Jena / Fuseki。Neo4j 已移除
平台元数据 PostgreSQL · Schema ontology_platform · TypeORM(业务侧不写裸 SQL)
对象检索 默认查询时虚拟投影;ClickHouse ODS 承载源表镜像,普通读取不使用 object_entries
大表源表层 ClickHouse ODS:一张源表一份裁剪副本,FULL 影子表原子替换 / INCREMENTAL 水位追平
智能问答 AI SDK 7(ai + @ai-sdk/openai-compatible):服务端工具循环、流式输出、可中断
对外协议 MCP:本体数据工具与建模技能两个服务端
图可视化 Sigma + Graphology(实例图谱)、React Flow(本体建模画布)
数据资源驱动 pg · mysql2 · oracledb(Thick 模式,镜像内置 Instant Client)
契约与文档 Zod;OpenAPI 由 next-openapi-gen 生成,Swagger UI 在 /docs
工具链 pnpm · Vitest · ESLint · Playwright

快速开始

1. 环境变量

cp .env.example .env.local
变量 必填 说明
DATABASE_URL ✅ PostgreSQL 连接串(自动使用 ontology_platform)
TARGET_ENCRYPTION_KEY ✅ 32 字节 Base64 密钥:openssl rand -base64 32
AUTH_SECRET ✅ ≥32 位随机串,签署会话令牌(JWT)
GRAPH_ENDPOINT_HOST_ALIAS 可选 Jena 端点主机名改写;容器默认 localhost=host.docker.internal,外部服务可覆盖
MCP_API_TOKEN 可选 外部 MCP 客户端访问 /api/mcp 用的 Bearer 令牌;平台只把它当一条只读兜底(正规做法是在「MCP 调试 → MCP 接入」里生成,可多条、可撤销)
MCP_API_TOKEN_USER 配 MCP_API_TOKEN 时必填 这条令牌代表哪个账号(账号邮箱):MCP 调用按那个账号的角色权限判,账号停用 / 改角色立即生效
BOOTSTRAP_ADMIN_EMAIL 首次 首个管理员邮箱
BOOTSTRAP_ADMIN_PASSWORD 首次 首个管理员密码
ONTOLOGY_VERSION_DIR 可选 旧部署的磁盘快照目录;只在把历史版本一次性迁进平台库时读取,新部署不需要

2. 安装与启动

pnpm install
pnpm dev

打开 http://localhost:3000。

3. 首次初始化

无需手动调用接口。首次访问平台时自动创建 ontology_platform Schema;若用户表为空, 平台会用 BOOTSTRAP_ADMIN_EMAIL / BOOTSTRAP_ADMIN_PASSWORD 创建首个管理员。 已有用户时不会重新创建,也不会因修改环境变量而重置密码。 POST /api/bootstrap 暂时保留给旧调用方;自动初始化后调用它会返回 409。

4. 常用脚本

命令 用途
pnpm dev 开发服务器
pnpm build / pnpm start 生产构建与启动
pnpm test 单元测试(Vitest,并行跑)
pnpm test:version-store 版本记录契约测试(需平台库)
pnpm test:schema-comments 表 / 字段注释契约测试(需平台库)
pnpm lint ESLint
pnpm typecheck TypeScript 检查
pnpm docker:up / docker:down / docker:logs 容器部署(见下一节)

Docker Compose 部署

编排只包含 app(本体平台)。PostgreSQL(平台库)、业务数据源和可选的 Apache Jena/Fuseki 图引擎都由你单独部署;不用 Jena 时无需运行 Fuseki。已有 Jena 本体仍可连接 外部服务,移除编排服务并不删除 Jena 适配器或 .data/fuseki 旧数据。

cp .env.docker.example .env.docker    # 填 DATABASE_URL 与密钥(模板里有逐项说明)
pnpm docker:up                        # = docker compose --env-file .env.docker up -d --build
pnpm docker:logs                      # 跟日志

pnpm docker:* 都带 --env-file .env.docker:这个文件既给容器注入变量,也给 compose 做变量替换, 所以 APP_PORT / NODE_IMAGE 也写在里面(模板第 0 节)。手动敲命令时记得带上这个参数, 否则这几个变量取不到值。

不带 --env-file 直接 docker compose up -d 也能起(Docker Desktop 上点按钮、IDE 里的 compose up 都走这条路),但那时用的是默认值:APP_PORT 取 3000,Jena 端点中的 localhost 改写为 host.docker.internal;仍需 .env.docker 提供平台库与密钥。固定配置请用 pnpm docker:up。

命令 用途
pnpm docker:up 构建并后台启动(docker compose up -d --build)
pnpm docker:down 停止并删除平台容器(本体定义与快照在平台库里,不会丢)
pnpm docker:logs 跟踪平台日志
pnpm docker:config 打印合并后的编排,排查变量问题

三处容易踩的地方:

  1. 容器里的 localhost 是容器自己。 连宿主机上的平台库要用 host.docker.internal: DATABASE_URL=postgresql://用户:密码@host.docker.internal:5432/库名(compose 已加 host.docker.internal:host-gateway,Linux 上也能这么写)。如果另行部署的 Jena 在宿主机,库里 登记的 endpoint 是 http://localhost:3030/ds,容器默认用 GRAPH_ENDPOINT_HOST_ALIAS=localhost=host.docker.internal 改写;远端 Jena 请直接登记可达地址。
  2. TARGET_ENCRYPTION_KEY 必须与库里已有数据所用的那一把一致:数据资源的凭据是加密后存进平台库的, 换一把钥匙就解不开已登记的连接。AUTH_SECRET 换掉只会让已登录会话失效,可以重新生成。
  3. 首次登录不必再调初始化接口:确认环境中已配置管理员邮箱和密码,平台库为空时会自动创建首个管理员;若库里已有用户,这两个变量不会覆盖现有密码。

其他细节:

  • 端口:宿主机 3000 被占用时用 APP_PORT=3100 docker compose up -d 换一个。
  • 可选 Jena/Fuseki:自行部署、管理数据集和管理员密码,然后在「设置 → 图引擎配置」中登记 可从平台容器访问的地址。升级现有 Compose 配置时,旧 ontology-fuseki 容器可能成为孤儿;本次改动 不自动停止或删除它,.data/fuseki 数据目录也保持原样。旧 .env.docker 中的 FUSEKI_* 参数 不再配置服务,建议手动移除(env_file 仍会把它们注入 app 环境)。 如果旧连接登记的是 http://fuseki:3030,请改成独立服务可达地址,或设置 GRAPH_ENDPOINT_HOST_ALIAS=fuseki=host.docker.internal(服务仍映射到宿主机 3030 时)。
  • 登录态是请求头,不是 Cookie(2026-10-09 起):POST /api/auth/login 在响应体里回一枚会话令牌, 之后每个请求带 Authorization: Bearer <令牌>,浏览器把它存在本地存储里。这样 Postman / curl / 脚本 直接就能调(以前得从浏览器里抄会话 Cookie)。代价是令牌对页面脚本可见(没有 httpOnly 保护), 换来的好处是免 CSRF 且调试方便;有效期仍是 8 小时,服务端每次请求都回库核对用户。
  • 版本在平台库,不占磁盘、不用共享卷:本体定义与实例快照都写在 ontology_platform.ontology_versions 里,容器重建、换机器都不会丢,多实例部署也不需要共享目录。 docker-compose.yml 里那个 /data/ontology-versions 绑定目录只服务于旧部署升级: 以前把版本放在磁盘上的部署,首次访问版本数据时会读这个目录、迁进平台库并删掉磁盘副本 (见「统一版本快照」节)。全新部署用不到它,VERSION_SNAPSHOT_DIR 可以不管。
  • 拉不动 Docker Hub 时用镜像站:NODE_IMAGE=docker.1ms.run/node:24-bookworm-slim docker compose up -d --build (Windows PowerShell 先 $env:NODE_IMAGE="docker.1ms.run/node:24-bookworm-slim")。
  • Oracle 开箱可用:镜像里装好了 Linux 版 Instant Client,ORACLE_CLIENT_LIB_DIR 指向 /opt/oracle/instantclient —— 因为要连的服务端只支持 Thick 模式(Thin 模式会被服务端以 NJS-138 拒掉)。 构建时优先用 docker/oracle/ 下的 instantclient-basiclite-linux.x64-*.zip,没有才去 Oracle 官网下载, 公司网络受限时把 zip 放进 docker/oracle/ 即可离线构建。想换成自备客户端就挂载到 /opt/oracle/instantclient 并设 ORACLE_CLIENT_LIB_DIR(Windows 的 dll 在容器里用不了)。
  • 平台库需要 pg_trgm 与 pgvector 扩展(对象检索层会 CREATE EXTENSION IF NOT EXISTS); 没有权限时检索自动降级成 ILIKE,不影响其他功能。

统一版本快照

一个版本是 不可拆分 的完整快照,不只是类型定义。

版本存在哪

存什么 在哪
本体定义(对象类型 / 关系类型 / 接口 / 指标 / 动作 / 规则 / 概念分组) 平台库 ontology_platform.ontology_versions.definition(jsonb,一行一个版本)
版本元数据(版本号、状态、对象与关系条数、内容哈希、发布时刻) 同一行的其它列
实例快照(对象节点与关系边) 同一行的 snapshot(jsonb):激活历史版本时用它整图回滚
概念检索索引(一行一个概念) ontology_concepts(定义保存/发布时重建)
发布后的图数据 图库:Jena 命名图,或内置类型图的 embedded_graphs 表

定义与快照都在平台库,磁盘上不再有本体数据(.data/ontology-versions 已废弃)。老部署首次访问版本数据时会把磁盘上的那批版本自动迁进平台库并删掉磁盘副本;ONTOLOGY_VERSION_DIR 现在只在这次一次性迁移里被读取。

生命周期

┌─────────────┐    ┌─────────────┐    ┌──────────┐    ┌────────────────┐
│ 1. 创建草稿  │ →  │ 2. 编辑草稿  │ →  │ 3. 校验   │ →  │ 4. 发布 / 激活  │
│ 复制或导出  │    │ 只改草稿记录 │    │ 定义+实例 │    │ 事务重建图      │
└─────────────┘    └─────────────┘    └──────────┘    └────────────────┘
  1. 创建草稿 — 优先复制当前发布版;升级后首版从当前图数据导出
  2. 编辑草稿 — 类型 / 对象 / 关系 / 属性 / 画布位置只改这条草稿记录;写操作须带 versionId
  3. 校验 — 必填/唯一、实例类型、关系端点与契约
  4. 发布 — 由后端适配器整图替换,必须原子:要么整体生效,要么图保持原样
  5. 激活历史 — 同一发布流程;存在草稿时禁止切换

发布的原子性与并发

GraphStore.replaceGraph() 有硬性契约:失败时图数据必须保持替换前的状态,由 capabilities.atomicReplace 声明,发布流程据此决定失败提示的措辞。

后端 原子替换的实现
Apache Jena 单个 SPARQL Update 请求完成「清空 + 插入」(TDB2 上单请求即事务);超过 5000 条三元组时先写入影子命名图,再用一个请求 CLEAR + ADD + DROP 原子切换
内置类型图 PostgreSQL 单行 UPSERT 原子替换发布视图,查询只见旧版本或新版本;Graphology/N3.js 视图按需重建

发布过程写三条审计:VERSION_PUBLISH_STARTED(含后端类型与 atomicReplace)、VERSION_PUBLISHED / VERSION_ACTIVATED、失败时的 VERSION_PUBLISH_FAILED(含 graphReplaced,用于判断图是否已被改动)。同一个本体存储的发布在进程内队列与 PostgreSQL advisory lock 两层串行,多实例部署也不会并发替换同一个本体存储。

发布成功后才更新版本状态,并对账 ontology_* 约束与索引。

稳定标识

elementId() 在重新导入后会变化,不能作长期引用。快照使用 UUID;发布时 UUID 仅事务内连边,完成后从节点移除,不污染业务属性。

部署注意

版本数据在平台库里,多实例部署不需要共享卷。无实例快照的旧归档版本不可激活;当前发布版与草稿会在首次使用时从真实图库生成快照。

本体包(导出与导入)

版本快照是平台内部的形态:平台库 ontology_versions 里一行一条,id 全是本机的 UUID。要在人和环境之间传播, 需要的是另一种东西 —— 本体包:一个 .ontology.json 文件,单文件、自描述、只装结构。

{
  "format": "ontology.bundle",
  "formatVersion": 1,
  "exportedAt": "2026-09-14T06:58:39.413Z",
  "generator": { "name": "ontology-management", "version": "0.1.0" },
  "ontology": { "identifier": "m3-1789283543253", "name": "...", "description": "...", "color": "", "tags": ["m3"] },
  "statistics": { "objectTypes": 3, "relationTypes": 1, "actionTypes": 0, "rules": 0, "objects": 3, "relationships": 0 },
  "dataSources": [{ "id": "<导出端的数据资源 id>", "kind": "ORACLE", "host": "39.164.136.34", "port": 1251, "databaseName": "orcl", "schemaName": "GISTOOLS" }],
  "definition": { "entityTypes": [], "relationshipTypes": [], "actionTypes": [], "rules": [] }
}

三条不变量:

  1. definition 就是平台内部的 OntologyDefinition,原样进出。 不新造一套形状, 所以导出/导入不可能出现"两份定义各说各话"。
  2. 包里绝不写凭据。 数据资源只记连接坐标(kind / host / port / 库 / 模式), 导入端按坐标去匹配本机已登记的资源。
  3. 导入一定停在草稿。 别人的文件不该绕过版本边界——导入只写平台库草稿, 校验、发布仍走平台既有流程。

导入时做的三件事

  1. 换 id。 包里的 UUID 全部重发新号,接口与实现、关系端点、动作作用域、规则条件一起改写 (一次遍历建立映射,避免"边改边查"漏改)。
  2. 接回数据资源。 先按 kind + host + port + 库 + 模式五项全等匹配;只差模式时放宽一次并给出提醒; 还是找不到就把这条来源绑定留空,并在弹窗里点名是哪个类需要重新选表——不静默丢绑定。
  3. 建本体 + 写草稿。 本体名(可改)与标识沿用包里的,标识被占用就自动加序号。

实例数据不在包里:statistics.objects 只是告诉接收方"导出端当时有多少对象"。 所以导入后的本体对象数是 0,需要自己补数据或从数据资源实例化。

也能导入 bkn 的知识网络

导入入口同时认 bkn-foundry 导出的知识网络(module_type: knowledge_network)。服务端会先把它 转成标准本体包再走同一条导入路径 —— 也就是说换 id、接数据资源、写草稿这些规则完全一致。 转换只搬我们装得下的,装不下的逐条报出来(概念域分组、指标、关系的连接规则 mapping_rules、 平台不认识的属性类型),不会静默丢:

  • 属性带上 bkn 的 display_name(中文名)与 comment(说明);
  • primary_keys 落到来源绑定的主键上;没有数据来源的类,主键改记成"必填 + 唯一"并给出提醒;
  • bkn 只写 SCHEMA.TABLE、不带数据库连接,所以来源资源要导入后自己在类型编辑里选一次。

命令行导入(大文件推荐)

界面上传适合小包;一个几百 KB 的 bkn 知识网络(几十个对象类型、上千个属性)建议走命令行: 一条命令、一个请求,服务端一次解析 + 绑定 + 落草稿。

# 先干跑一遍:只解析不落库,看清文件里到底有什么、会丢什么(几十毫秒)
node scripts/import-ontology.mjs "你的文件.json" --dry-run --email admin@example.com --password '******'

# 确认后正式导入(默认停在草稿,和界面导入一致)
node scripts/import-ontology.mjs "你的文件.json" --storage-target "内置类型图" --name "客户账务网络 v6"

# 想一步到位(会真正重建图数据)
node scripts/import-ontology.mjs "你的文件.json" --publish
  • 账号也能用环境变量给:ONTOLOGY_EMAIL / ONTOLOGY_PASSWORD(或直接给 --token 跳过登录)。
  • --storage-target 省略时,若只剩一个没被占用的存储就自动用它;多个候选会把名字列出来。
  • 导入响应里带 timings(解析 / 规划 / 绑定 / 建快照),慢的时候一眼看出慢在哪。
  • 三种输入都支持:bkn 知识网络、平台自己的 ontology.bundle、以及工具导出的本体包。

智能问答与 MCP

REST 与智能问答 / MCP 是两条入口、一层 lib(工具侧只读,且只认已发布版本):

flowchart TB
  UI["界面(工作台 · 本体建模 · 版本记录)"]
  QA["智能问答(问答页)"]
  EXT["外部 MCP 客户端 / Agent"]

  subgraph L_HTTP["HTTP 层 · src/app/api"]
    REST["REST:/api/ontologies/* · /api/ontology/*"]
    RUN["/api/reasoning/runs · stream"]
    MCPE["/api/mcp · /api/mcp/&lt;ontologyId&gt;"]
  end

  subgraph L_TOOLS["工具层(只读)· reasoning/tools/"]
    TOOLS["registry · search · projection · dispatch<br/>11 个只读工具:概念检索 / 类型详情 / 多跳遍历 / 概念分组 / 接口 / 指标 / 动作 / 表结构 / 列画像 / 只读 SQL"]
  end

  subgraph L_SERVICE["服务层 lib(两条入口共用 · 进程内直调,不走 HTTP)"]
    ONTO["platform/ontologies.ts<br/>本体台账 · 受管图存储分配"]
    SNAP["versioning/snapshot.ts<br/>版本 · 定义 · 实例快照 · 内容哈希"]
    PUB["versioning/published-ontology.ts<br/>只取 status = PUBLISHED,工具侧读定义的唯一入口"]
    SRCT["platform/targets · datasource/sources<br/>图引擎连接 · 数据资源登记 · 结构缓存 / 列画像"]
    GRAPHS["infrastructure/graph · instance/object-service<br/>图库读写(Jena / 内置图)· ODS / 业务源虚拟取数"]
    PURE["ontology/*(纯函数)<br/>接口约束 · 关系键 · 数量关系 · 指标口径"]
  end

  subgraph L_STORE["存储"]
    PG[("PostgreSQL · ontology_platform<br/>ontologies · ontology_versions(定义 + 编辑)· ontology_concepts<br/>graph_targets · data_sources · ods_sources / ods_sync_jobs · instance_history · audit_entries")]
    CHODS[("ClickHouse ODS<br/>一张源表一份原始列镜像,查询时形成对象")]
    GRAPH[("图库:Jena / Fuseki 或内置类型图(embedded_graphs)<br/>发布后的投影,不是定义源")]
    BIZ[("业务库(只读):Oracle / PostgreSQL / MySQL<br/>只读事务 + SQL 护栏")]
  end

  UI -->|"读写"| REST
  QA -->|"只读"| RUN
  EXT -->|"只读"| MCPE
  REST -->|&quot;写定义 / 发布 / 激活&quot;| SNAP
  REST --> ONTO
  REST --> SRCT
  REST --> PURE
  RUN --> TOOLS
  MCPE --> TOOLS
  TOOLS -->|"调工具实现"| SNAP
  TOOLS --> PUB
  TOOLS --> GRAPHS
  ONTO --> PG
  SNAP --> PG
  SRCT --> PG
  SRCT --> BIZ
  GRAPHS --> PG
  GRAPHS --> GRAPH
  GRAPHS --> CHODS

  classDef write fill:#fdf6f4,stroke:#e2bbae,color:#a04c38;
  classDef read fill:#f4faf6,stroke:#b9d8c6,color:#2f6b52;
  classDef plain fill:#ffffff,stroke:#cfd9d4,color:#24383a;
  class UI,REST write;
  class QA,EXT,RUN,MCPE,TOOLS read;
  class ONTO,SNAP,PUB,SRCT,GRAPHS,PURE,PG,GRAPH,BIZ,CHODS plain;
  linkStyle 0 stroke:#b4553f,stroke-width:2px;
  linkStyle 1,2,7,8 stroke:#3d7c60,stroke-width:2px;
Loading

两条入口只差三处,其余全部共用(工具实现只 import @/lib/…,不回头 fetch 自家的 /api/ontology,所以换存储时两边零改动):

差异 REST(界面点按钮) 智能问答 / MCP(模型与外部 Agent)
读写 可改定义、发布、激活、改实例 全部只读(run_sql 走只读事务 + SQL 护栏)
看哪一版 草稿 + 全部历史版本 只认 status = PUBLISHED
放行机制 13 个权限点(按模块分组) 工具开关(全局默认 + 按本体覆盖)与访问令牌

「能力验证」这一组是同一个能力的两种用法:平台内的问答与对外的 MCP 服务共用同一套只读工具, 所以不会出现"界面上查得到、MCP 里查不到"的漂移。

智能问答(工具循环)

  • 循环在服务端:AI SDK 的 ToolLoopAgent 负责"模型选工具 → 执行 → 结果回灌 → 再选",平台只负责提供事实工具。
  • 工具全部只读:本体概念检索、对象类型详情、概念分组、接口、多跳遍历、动作定义、表结构(DDL)、只读 SQL。写入业务数据的唯一入口是动作。
  • 旋钮在「问答配置」抽屉里:步数上限、单次工具返回长度、取数行数、历史轮数与系统提示词;默认都不限制(服务端兜底防死循环)。
  • 流式与中断:回答按「思考 / 正文 / 工具步」分段流式回传,可随时停止;提问支持附带图片。
  • 会话历史存在平台库,可回看、可删除;上下文过长时由框架负责裁剪压缩。

MCP(两个服务端)

服务端 地址 鉴权 提供什么
本体数据(平台级) /api/mcp 平台会话 / MCP 访问令牌 / OAuth 访问令牌 本体与 Schema 检索、对象类型详情与多跳、概念分组、接口、动作定义、表结构与只读 SQL
本体数据(本体级) /api/mcp/<本体 id> 同上 同上,但钉死在这一个本体上:不用每次传 ontology_id,工具清单也按这个本体的开关给
建模技能 /api/skills/mcp 免令牌 三套建模技能的正文与参考文件(公开文档,不含凭据)

为什么要两个地址:平台级端点一个覆盖所有本体,查哪个由每次调用的 ontology_id 决定 —— 配置片段里看不出"这条 MCP 查的是谁"。本体级端点把本体写进 URL:模型不用(也不该)自己填 id, 避免查错本体,多个本体可以各配一条(服务名默认带本体 id 前缀)。

工具开关按本体分:MCP 调试 页里的开关写到当前选中的本体上;没有覆盖时跟着全局默认走, 界面上会写明「跟随全局默认」还是「本体 X 单独配置」,并给一个「跟随全局」的出口。 智能问答(/api/reasoning/*)与 MCP 两侧读的是同一份按本体的策略 —— 关掉的工具在哪里都不会发给模型。

「MCP 调试」页把工具逐个列出来:可以改参数、直接运行、看真实返回,也能复制各家客户端的接入配置(默认是通用 mcp.json)。 工具说明按「用途 / 输入 / 产出 / 下一步调谁」写,模型不点开 schema 也知道怎么用。

本体技能

平台自带三套建模技能,目标是让 Agent 按本平台的规范建模,并直接产出能导入的本体包:

技能 干什么 产物
ontology-requirement 需求澄清:把业务描述问成可建模的清单 澄清后的对象类型 / 关系类型 / 动作清单
ontology-builder 本体设计:按建模细则设计对象类型、关系类型、接口、动作 设计稿与校验结论
ontology-bundle 出包交付:把设计编译成平台可直接导入的本体包 .ontology.json
  • 模型只写结构化清单,脚本负责编译:手写 UUID 与 id 引用最容易出错,所以由 skills/ontology-bundle/scripts/build-bundle.mjs 生成最终包(只用 Node 内置模块,Windows / Linux / macOS 同一套命令)。
  • 技能页可以整包下载 zip(解压进 ~/.codex/skills/ 之类的目录),也可以直接走上面的免令牌 MCP。

对象从哪来

平台把"对象"和"对象存在哪"解耦成两层,读路径只有一条:

界面 / 智能问答 / MCP
        │  按「对象类型 + 主键」取对象
        ▼
   对象服务(Object Service)
        │  按当前版本映射,查询时形成虚拟对象
        ├──► ODS 源表层(ClickHouse)  一张源表一份裁剪副本;AUTO 可用时查询时过滤成对象
        └──► 数据资源连接(DataSourceConnector)  Oracle / PostgreSQL / MySQL 只读事务
  • 对象无需物化:列表、全部标签、图谱、问答和本体 SQL 统一虚拟查询。旧 INDEXED 配置不再要求物化;旧索引仅兼容维护,存量数据未自动删除。
  • ODS 是源表层,不是对象层:只镜像选中列和主键,版本切换不复制;全量走影子表原子替换,增量按水位追平。对象来源可设 AUTO / DIRECT / ODS。
  • 回源按对象类型上绑定的数据资源与主键字段读,只走只读事务与语句白名单。
  • 换中间件(例如把检索索引换成独立搜索引擎)只替换扩展点,对象服务、界面与 AI 工具一行都不用改。

角色与安全

对象页支持版本编辑覆盖与“历史数据”:覆盖层仅保留改过字段,历史采集显式冻结定义和源投影、按页压缩保存。版本切换只改变定义和映射,普通查询不读取旧对象索引;实例图谱可选择 1~3 跳的有界邻域。历史快照记录采集区间,跨表不承诺同一事务时点。实现边界和验证命令见 虚拟实例改造验收。

权限是 13 个权限点(按模块分组),角色 = 一组权限点。内置三档不可改不可删,也可以自建角色; admin 永远拥有全部权限。入口在「设置 → 用户与角色」。

内置角色 权限
管理员 全部 13 个权限点
编辑者 建模与发布、改数据资源、改对象与关系、用智能问答;碰不到用户与角色、MCP 访问令牌、图引擎连接
查看者 只读:看本体与对象、用智能问答查数

权限不足返回 403(401 只表示令牌不认);「最后一个能管用户的账号」不许降级 / 停用 / 删除。

  • 会话:Authorization: Bearer <平台会话令牌>,AUTH_SECRET 签署的 JWT,8 小时过期; 令牌由前端存在本地存储(没有 httpOnly 保护,换来免 CSRF + 便于 Postman / 脚本调试)
  • 数据面:图库 / PostgreSQL 仅服务端访问,浏览器不接触密码与主密钥
  • 写入边界:业务写经草稿快照与发布;原生查询一律只读,避免绕过版本

服务端接口

认证与初始化
方法 路径 用途
POST /api/bootstrap 创建 Schema 与首个管理员(仅一次)
POST /api/auth/login 登录,响应体里回会话令牌(token),之后用 Authorization: Bearer
POST /api/auth/logout 空操作(无状态 JWT,登出由前端丢令牌完成)
GET /api/auth/session 当前会话
POST /api/auth/password 改自己的密码(验当前密码,不需要用户管理权限)
GET / POST /api/users 用户清单 / 建账号(要「管理用户与角色」)
PATCH / DELETE /api/users/:userId 改角色 / 重置密码 / 停用;删除(真删)
GET / POST /api/roles 角色清单(含权限点定义)/ 新建角色
PATCH / DELETE /api/roles/:roleId 改 / 删角色(内置角色不可改不可删)
图引擎连接
方法 路径 用途
GET / POST /api/targets 列表 / 登记
GET / PATCH / DELETE /api/targets/:targetId 查看 / 更新 / 删除
GET /api/targets/:targetId/schema 运行时 Schema
POST /api/targets/:targetId/test 连接测试
GET /api/targets/:targetId/clear 清空前的预览:当前有多少对象与关系
POST /api/targets/:targetId/clear 清空图数据(全部节点与关系);需键入本体存储名称确认,仅动图库,平台版本与快照保留
POST /api/targets/:targetId/reset 重置本体存储状态
本体版本
方法 路径 用途
GET / POST /api/ontology 列表 / 创建草稿
GET / PATCH / DELETE /api/ontology/:versionId 读取 / 更新 / 删除草稿
POST /api/ontology/:versionId/validate 校验草稿
POST /api/ontology/:versionId/publish 发布并重建图
POST /api/ontology/:versionId/activate 激活历史快照
GET /api/ontologies/:ontologyId/export 导出本体包(单文件 JSON,仅结构)
POST /api/ontologies/import 从本体包导入:建本体 + 写草稿(不发布)
实例(草稿快照)

写操作面向草稿 versionId;读可按本体存储与版本查询。

方法 路径 用途
GET / POST /api/instances/entities 对象列表 / 创建
GET / PATCH / DELETE /api/instances/entities/:elementId 对象读写删
GET / POST /api/instances/relationships 关系列表 / 创建
GET / PATCH / DELETE /api/instances/relationships/:elementId 关系读写删
GET /api/instances/graph 图数据
GET /api/instances/types 运行时类型
GET /api/instances/meta 元信息
GET /api/instances/search 搜索
GET /api/instances/neighbors 一度邻居扩展(后端无关)
POST /api/instances/positions 画布位置
只读查询
方法 路径 用途
POST /api/query 执行只读 SPARQL,写入一律 409
数据资源(外部关系库)
方法 路径 用途
GET / POST /api/data-sources 列表 / 登记数据资源
GET / PATCH / DELETE /api/data-sources/:sourceId 查看 / 更新(密码留空即不变)/ 删除
POST /api/data-sources/test 用表单里的参数试连一次,不落库
POST /api/data-sources/:sourceId/test 按已保存的连接试连
GET /api/data-sources/:sourceId/views 表与视图清单;schema=* 表示看全库,search= 过滤
GET /api/data-sources/:sourceId/views/:viewName 字段清单 + 若干行数据预览(只读)
智能问答
方法 路径 用途
POST /api/reasoning/runs 起一轮问答(后台跑,立刻回 runId;界面走的就是这一条)
GET /api/reasoning/runs 这个本体上还在跑 / 刚跑完没落库的那些运行
GET /api/reasoning/runs/:runId/events?after=N 接上这一轮(SSE,按游标补看 + 后续增量)
POST /api/reasoning/runs/:runId/cancel 停止这一轮(只有它真的会停;断开连接只是不看了)
POST /api/reasoning/stream 起一轮并就地看完(SSE,给脚本用;运行同样归服务端)
POST /api/reasoning/run 非流式运行,给脚本与调试用
GET /api/reasoning/tools 工具清单与启用状态
GET /api/reasoning/status 模型与运行状态
GET / DELETE /api/reasoning/conversations 会话历史列表 / 清空
GET / DELETE /api/reasoning/conversations/:conversationId 单个会话的轮次 / 删除
MCP 与技能
方法 路径 用途
POST /api/mcp 本体数据 MCP 服务(会话 / MCP 访问令牌 / OAuth 访问令牌)
GET /api/mcp/info 该 MCP 服务的接入信息与工具清单
GET /.well-known/oauth-protected-resource 受保护资源元数据(OAuth 客户端第一步读它)
GET /.well-known/oauth-authorization-server 授权服务器元数据(三个端点)
POST /api/oauth/register 客户端自助注册(公开客户端,匿名可达)
GET POST /api/oauth/authorize 授权同意页的查询与「允许 / 拒绝」(POST 要登录)
POST /api/oauth/token 换访问令牌 / 刷新(匿名可达,公开客户端无密钥)
GET DELETE /api/oauth/clients 已注册的 OAuth 客户端清单与删除(要 mcp.token.manage)
POST /api/skills/mcp 建模技能 MCP 服务(免令牌)
GET /api/skills 技能清单 + MCP 接入信息
GET /api/skills/archive 全部技能打包成 zip
对象检索与审计
方法 路径 用途
POST /api/objects/materialize 按主键取进草稿,保存版本编辑基线
POST /api/object-search 按关键词与过滤条件检索对象
GET /api/audit 审计记录(scope=changes / actions / reads / all,仅管理员)
GET/POST /api/ods ODS 配置清单 / 保存裁剪后的源表镜像
POST /api/ods/:sourceId/sync 后台全量或增量同步 ODS
GET /api/ods/jobs ODS 同步任务与进度

图存储抽象

src/lib/infrastructure/graph 是图存储契约与适配器,src/lib/platform/graph-store 是平台组合入口。业务代码调用 getGraphStore(target),由平台层注入内置图所需的快照仓储:

文件 职责
types.ts GraphTarget、GraphData、RuntimeTypeSet、GraphStore 契约与连接元数据
index.ts createGraphStore(target, embeddedRepository) 工厂,按 target.kind 分派
jena/ Apache Jena / Fuseki 适配器:store / read / replace / statements / protocol / vocabulary 分文件,SPARQL 1.1、RDF ↔ 属性图映射
embedded/ 内置适配器:Graphology 类型图与 N3.js / Comunica 只读 SPARQL;快照通过 EmbeddedGraphRepository 注入,不直接依赖平台库
src/lib/platform/graph-store.ts 平台组合入口:创建 getGraphStore(target),注入 PostgreSQL 快照仓储

本体存储配置字段

字段 说明(Apache Jena)
uri Fuseki 服务地址,如 http://host:3030(也接受 /ds/query、/ds/sparql)
database_name 数据集名
username / password 可选(写入通常需要管理员凭据)
options.namedGraph 可选,写入/读取指定命名图,默认图可留空;平台给每个本体自动分配 urn:ontology:<id>

RDF 与属性图的映射:?s rdf:type ?t → 节点标签,字面量三元组 → 节点属性,资源三元组 → 关系;关系自身属性用 urn:bkn:Relationship 具体化表达,同时保留一条直接三元组,外部 SPARQL 工具照常可查。

内置类型图由代码作为虚拟存储选项提供,不在 graph_targets 中创建根资源记录;不需要配置凭据,也不能删除该选项。新建或导入具体本体时才持久化独立的受管目标。在「总览」中新建或导入本体时默认选择它;需要外部服务时仍可在「设置 → 图引擎配置」中新建 Jena 连接。图引擎配置不是本体,不会自动生成空本体。类型图只包含定义;为了兼容现有手工对象页面,当前发布视图可以暂存少量实例,但海量业务对象不能进入这份 JSONB 视图或进程内 RDF Store。Jena 保留且继续可选,现有 Jena 本体不会自动改变后端;若要迁移定义,可导出本体包,在新存储上导入并核验。当前本体包不携带实例数据。

多个本体放在哪(隔离)

平台的「发布」是整图替换:Jena 侧清掉目标命名图(没配命名图时是默认图)后重写。 因此同一个「数据集 + 命名图」上不能登记两个本体存储——两边会互相看见数据,发布时互相清空。 新建 / 编辑本体存储时平台会拦下这种情况(HTTP 409),并说明怎么改。

Jena 的隔离单位是命名图,不是「多起一套实例」;内置后端由受管目标 ID 隔离,SPARQL 只看当前目标的 RDF 数据集:

做法 适用 说明
命名图(默认做法) Apache Jena 一个数据集里一个本体一个命名图。在「总览」中新建本体时不用选,平台自动分配 urn:ontology:<本体 id>,同一个 Fuseki 上可以并存任意多个本体
多 dataset Apache Jena 需要按环境 / 租户再分一层时,一个 Fuseki 下配多个 dataset,登记存储时选不同数据集
独立实例 Apache Jena 需要资源或权限硬隔离时才单起一套 Fuseki/TDB2;日常使用不需要

新增图后端

  1. 在 GraphTargetKind 登记类型,并在 GRAPH_TARGET_KINDS 补齐连接表单元数据;
  2. 新增实现 GraphStore 的适配器;
  3. 在 createGraphStore 中注册,并由 platform/graph-store.ts 提供该后端需要的仓储或连接实现。

API 路由、版本发布流程与界面组件无需改动。

数据资源

数据资源是外部业务数据来源,和本体存储不是一回事:本体存储(内置或 Jena)管理本体发布视图,数据资源回答「对象类型对应的业务数据从哪来」。

src/lib/datasource 是唯一的数据来源访问入口:

文件 职责
types.ts DataSourceKind、DATA_SOURCE_KINDS 连接表单元数据、DataSourceConnector 契约;纯类型,客户端可直接引用
sql.ts 关系库适配器:TypeORM 建连接,test / listViews / describeView / previewView;Oracle 走数据字典读结构
index.ts openDataSourceConnector(record, credentials) 注册表,按 record.kind 分派
sources.ts · input.ts · structure-cache.ts 数据资源记录的读写、表单校验与结构清单缓存
ddl.ts · column-profile.ts 给模型看的 DDL 与列画像;只读 SQL 护栏在 src/lib/shared/server/sql-guard.ts
source-binding.ts · source-hints.ts · object-name.ts 对象类型到表 / 列的绑定与表名规范化

当前支持 PostgreSQL、MySQL、Oracle。三类共用同一份 SQL 实现,接入新的关系库通常只需要在 DATA_SOURCE_KINDS 里加一条元数据;接入 Elasticsearch、REST、文件这类非关系来源时,在 openDataSourceConnector 里分流到一个新实现即可 —— 界面与 API 不用改。

ODS 源表镜像:数据资源 → 表详情 → ODS 镜像,可勾选列、配置复合主键和 FULL / INCREMENTAL 同步。ClickHouse 表只保存源行;对象类型来源的 AUTO / DIRECT / ODS 决定查询时是否读它。全量先写影子表再原子替换,增量按水位合并;删除检测依赖手动或按小时自动的全量校准。运行任务可取消,进程重启后的遗留任务会标为中断。

对象与数据表的对应关系

参照 Palantir 的模型:类 ≈ 数据集,对象 ≈ 一行,属性 ≈ 一列。因此绑定写在类上,而不是逐个对象上:

绑定项 含义
数据资源 + 表 / 视图 这份来源读哪张表
主键字段(可复合) 主来源里,这几列是一个对象的身份
显示名字段 对象在列表与图谱上的标题
属性映射 类的属性取自哪一份来源的哪个列

一个类挂多份来源(多来源对象类型)

一个类可以从多张表拼属性,对应 Palantir 的 column-wise MDO(官方说明):

  • entityTypes[].sources[0] 是主来源:对象的身份(primaryKey)与标题(titleField)由它决定。
  • 后面的每一份是补充来源:primaryKey 写的是「这张表里哪几列对应对象主键」,按列位置一一对齐,就是两份来源的连接条件。
  • 属性用 properties[].sourceId 指回那份来源,再用 sourceField 指向具体列;sourceId 为空表示主来源。

绑定信息保存在版本快照的类定义里(sources 与 properties[].sourceField / sourceId),草稿改动即时落库。加多来源之前的老快照里是单个 source 字段,读出来会自动折成 sources[0],不会丢绑定。

编辑面板(类 → 编辑)按这个形状做:主来源卡在最上面,补充来源依次挂在下面,每份补充来源的连接键直接画成「主键列 → 本表列」的对位关系;属性映射一行三格:属性、来源、列。

发布前检查会顺带核查来源绑定,分两档:

情况 处理
补充来源选了表却没有连接键、连接键列数和主键对不上、属性指向一份已经不在类上的来源 拦下来,属于配置自相矛盾
主来源还没选表 / 还没指定主键、补充来源还没选表、同一张表挂了两次 只提示(warnings),不拦发布 —— 平台现在还不从绑定取数,建模阶段允许先把结构搭起来

读取成本与缓存

结构清单不便宜(Oracle 要扫一遍数据字典,PG / MySQL 要走一次 ORM 的 getTables),所以读取分两层缓存,都能主动穿透:

层 行为 什么时候失效
服务端 结构清单按「连接 + 容器」缓存 60 秒,命中时不建连接、不查库 超过 60 秒,或请求带 refresh=1(界面上的「刷新结构」)
前端 资源清单、结构清单、表字段与预览按 key 存在会话内存里,切页面回来先渲染缓存再后台取最新一份 改过连接信息(整条丢掉)、超过缓存条数上限、整页刷新

单表读取走精确路径:Oracle 按 owner + 表名 直接查 all_tables / all_views 定位,再取列与预览,不再为了一张表扫整库。

连接配置

类型 连接串 驱动 容器
PostgreSQL postgresql://user@host:5432/db pg 模式(schema),可留空
MySQL mysql://user@host:3306/db mysql2 库名即容器
Oracle oracle://user@host:1521/SERVICE oracledb 模式(schema / 用户),可留空

Oracle 注意两点:服务端版本较旧(11g 及更早)时必须用 Instant Client 走 Thick 模式,把客户端目录配到 ORACLE_CLIENT_LIB_DIR(或放进 .data/oracle-client/);结构清单直接读 all_tables / all_tab_columns 等数据字典,不走 ORM 的 getTables()。

目录结构

分层与依赖(mermaid,GitHub / 编辑器里可直接渲染):

flowchart TB
  UI["界面:工作台 · 本体建模 · 实例图谱 · 智能问答"]
  EXT["外部 MCP 客户端 / Agent"]

  subgraph L_API["接口层 · src/app/api"]
    REST["REST:/api/ontologies/* · /api/ontology/*"]
    RUN["/api/reasoning/*"]
    MCPE["/api/mcp · /api/mcp/&lt;ontologyId&gt;"]
  end

  subgraph L_DOMAIN["领域与平台层 · src/lib"]
    TOOLS["reasoning/tools/(11 个只读工具)"]
    ONTO["ontology/:定义 · 草稿 · 画布 · 接口 · 指标 · 分组 · 体检"]
    VER["versioning/:快照存储与投影 · 已发布定义<br/>instance/:快照编辑 · 发布前校验 · 发布编排"]
    INST["instance/:虚拟对象服务 · 版本编辑 · 动作引擎"]
    DS["datasource/:连接器 · DDL · 只读 SQL 与护栏 · 列画像"]
    REA["reasoning/:工具循环 · 提示词 · 历史 · MCP 服务端"]
    MS["mcp/ · skills/:协议与令牌 · 技能与打包"]
    PLAT["platform/:auth · users · permissions · audit · ontologies · targets"]
    DBM["platform/db/:连接 · 实体 · 迁移"]
    INFRA["infrastructure/:graph · ClickHouse · ODS · persistence<br/>shared/:common · client · server 通用件"]
  end

  subgraph L_STORE["存储"]
    PG[("PostgreSQL · ontology_platform:定义 · 版本编辑 · 概念索引 · ODS 配置/任务 · 历史 · 权限 · 审计")]
    ODS[("ClickHouse:ODS 原始源列镜像")]
    GRAPH[("图库:Jena / Fuseki 或内置类型图")]
    BIZ[("业务库(只读):Oracle / PostgreSQL / MySQL")]
  end

  UI --> L_API
  EXT --> MCPE
  L_API --> L_DOMAIN
  RUN --> TOOLS
  MCPE --> TOOLS
  TOOLS --> VER
  TOOLS --> INST
  TOOLS --> DS
  ONTO --> VER
  VER --> PG
  INST --> PG
  INST --> ODS
  INST --> GRAPH
  DS --> BIZ
  PLAT --> DBM
  DBM --> PG
  INFRA --> GRAPH
  INFRA --> PG
  REA --> MS
Loading

目录细节:

ontology_management/
├── src/
│   ├── app/              # 页面与 API 路由(含 /docs 的 OpenAPI 页面)
│   ├── components/       # 界面组件;workbench/ 页面壳,qa/、type-editor/、action-studio/ 放编辑器区块
│   └── lib/              # 领域与平台代码(根目录只有目录,没有散文件)
│       ├── infrastructure/ # 外部技术适配:graph/ · object-index/ · ods/ · persistence/postgres/(平台库连接、实体、迁移)
│       ├── shared/       # 无业务依赖的通用件:common/ · client/ · server/
│       ├── platform/     # 平台业务:auth · users · permissions · audit · ontologies · targets · 数据访问编排
│       ├── ontology/     # 本体模型:定义 · 对象身份 · 字段换算 · 画布 · 接口 · 指标 · 分组 · 校验规则
│       ├── versioning/   # 版本:快照存储 · 快照投影 · 已发布定义
│       ├── instance/     # 本体实例:对象服务 · 快照编辑 · 发布前校验 · 发布编排 · 动作引擎
│       ├── datasource/   # 数据资源:连接器 · DDL · 只读 SQL 与护栏 · 列画像 · 来源绑定
│       ├── query-dsl/    # 查询语义:SQL 表层解析 · 绑定 · 编译 · ODS / 业务源执行
│       ├── reasoning/    # 智能问答:工具循环 · tools/(工具实现)· 提示词 · 历史 · MCP 服务端
│       ├── mcp/          # MCP 对外契约:协议版本 · 工具 schema · 访问令牌
│       ├── oauth/        # OAuth 2.1:授权码 + PKCE · 客户端 · 刷新令牌
│       └── skills/       # 本体技能清单与打包
├── skills/               # 随平台下发的建模技能(Markdown + 出包脚本)
├── docs/                 # 设计文档与架构决策记录
├── scripts/              # OpenAPI 生成、离线导入等脚本
├── docker/               # Oracle Instant Client 等镜像内资源
├── e2e/ · tests/         # Playwright 端到端与 Vitest 单测(tests/ 与 src/ 同构)
├── .env.example
├── LICENSE
└── package.json

设计细节见 docs/ 与 skills/README.md。

开发约定

  • 包管理统一使用 pnpm(见 packageManager)
  • 业务逻辑优先放在 src/lib,API 路由保持薄封装
  • 改动版本快照 / 发布流程时,同步关注 src/lib/versioning/snapshot.ts、src/lib/instance/version-publication.ts 与相关 ADR
  • 改 src/lib/ontology/index.ts 的本体 schema 时,同步改 skills/ontology-bundle/references/ 下的格式文档与示例包(skills.test.ts 会校验)
  • 新增或修改数据表 / 字段时,表注释与字段注释必须一起补(写进 src/lib/infrastructure/persistence/postgres/comments.ts,迁移 0006 会生成 COMMENT ON)
  • 日常验证统一用 pnpm dev,不在日常流程里跑生产构建
  • 关键界面流程用 pnpm test:e2e;测试使用 3011 端口,不占用日常开发端口 3000
  • 每完成一批功能,把 docs/功能实现记录.md 里对应的功能分区更新掉(能做什么 / 入口 / 限制 / 怎么验证)—— 那是"平台有什么功能"的账本,不记修复过程,别按日期往下堆条目

许可证

本项目采用 Apache License 2.0 开源许可。

Copyright 2026 本体管理平台 Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

本体管理平台 · Ontology Management · Apache-2.0

About

ontology_management

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages