npm package: @scenemesh/entity-engine
Description: 一个“元数据驱动 + 组件适配 + 动态关系 + 视图管线”式的实体引擎。以 **Model + View + FieldType + SuiteAdapter + DataSource** 为五大支点，统一 CRUD / 查询 / 引用管理 / 视图渲染 / 扩展注册，支持在运行期无侵入拼装出 **表单、网格、主从、看板、仪表盘、流程/树形视图** 等多形态界面。
Author: SceneMesh Team
Latest version: 0.2.17

# @scenemesh/entity-engine

一个“元数据驱动 + 组件适配 + 动态关系 + 视图管线”式的实体引擎。以 **Model + View + FieldType + SuiteAdapter + DataSource** 为五大支点，统一 CRUD / 查询 / 引用管理 / 视图渲染 / 扩展注册，支持在运行期无侵入拼装出 **表单、网格、主从、看板、仪表盘、流程/树形视图** 等多形态界面。

**设计原则：配置驱动、运行补全、插槽扩展、最小绑定、可模块化注入。** 适合构建中后台、数据工作台、领域建模平台、低代码/AI 辅助生成系统。


## 目录一览

1. 特性速览
2. 与 workbench 集成全景示例（真实用法）
3. 安装与 Peer 依赖
4. 快速上手（客户端 / 服务端 / 混合渲染）
5. 核心概念与架构示意
6. 模型 (Model) 与视图 (View) 元数据
7. 视图渲染与插槽扩展 (Renderers & Slots)
8. 组件套件 (Suite Adapter) 与自定义 Widget
9. 数据源与引用关系（References / Trees / Grouping）
10. 查询 DSL（条件表达表达式结构）
11. 服务端接入（Next.js Route Handler / tRPC 端点）
12. 多租户架构（PostgreSQL Schema 隔离）
13. 模块化扩展（动态加载 & AI 模块示例）
14. 权限 / 导航 / 会话集成
15. 调试与开发辅助（View Inspector / Studio Launcher）
16. Roadmap
17. FAQ
18. License


## 1. 特性速览

| 能力 | 说明 |
| ---- | ---- |
| 元数据驱动 | 使用 `IEntityModel` + `IEntityView` 描述领域与 UI 形态，减少硬编码。 |
| 运行时补全 | 视图缺省字段、Widget、顺序等由 FieldTyper 与模型自动推导。 |
| 插槽扩展 | 通过命名渲染器 (Named Renderer) 在壳层 / 工具栏 / 行内插入自定义区域。 |
| 多视图内置 | `form` / `grid` / `master-detail` / `shell` / `kanban` / `dashboard`。 |
| 引用关系统一 | 基于引用表抽象支持一对多、多对多、树、反向查询、计数。 |
| 多对多编辑 | 内置 `ReferenceEditMMComp` 管理选择/删除/批量操作。 |
| 查询 DSL | 嵌套 AND/OR/NOT、Between/In/Contains 等操作符统一结构表达。 |
| 数据源抽象 | `IEntityDataSource` 屏蔽实现，默认 tRPC + Prisma（可扩展 REST / GraphQL）。 |
| 模块化 | 运行期动态加载模块（esm.sh / 本地），扩展模型、组件、动作、AI 工具。 |
| 组件套件 | UI 套件适配器（Mantine / 自定义 / additions suite），解耦 UI 风格。 |
| 行为注册 | Action / Event / Servlet 三类行为管线统一注册与调用。 |
| DevTools | View Inspector / Studio Launcher 提供运行态调试与可视化。 |
| 类型安全 | TypeScript + zod（字段 schema 可选）保障运行与编译期安全。 |

> 目标：用最少的“约束 + 元信息”表达，驱动出尽可能多的动态 UI 与行为。
		- [新增视图实现](#新增视图实现)
		- [自定义 Widget](#自定义-widget)
		- [命名 Renderer (Slot)](#命名-renderer-slot)
	- [字段类型扩展 (Field Type Extension)](#字段类型扩展-field-type-extension)
	- [数据源扩展 (DataSource Extension)](#数据源扩展-datasource-extension)
	- [校验与默认值 (Validation \& Defaults)](#校验与默认值-validation--defaults)
	- [tRPC 集成 (tRPC Integration)](#trpc-集成-trpc-integration)
	- [常用接口参考 (API Reference Snapshot)](#常用接口参考-api-reference-snapshot)
		- [IEntityModel](#ientitymodel)
		- [IEntityField](#ientityfield)
		- [IEntityView](#ientityview)
		- [IEntityDataSource (节选)](#ientitydatasource-节选)
	- [Roadmap](#roadmap)
	- [贡献指南 (Contributing)](#贡献指南-contributing)
	- [许可 (License)](#许可-license)
	- [常见问题 (FAQ)](#常见问题-faq)
	- [致谢 (Acknowledgements)](#致谢-acknowledgements)

---

## 2. 与 workbench 集成全景示例

`apps/workbench` 展示了一个真实集成：

**客户端 Provider 封装示例**（简化自 `entity-engine-provider-warpper.tsx`）：

```tsx
// src/entity/provider/entity-engine-provider-warpper.tsx
'use client';
import { useRouter } from 'next/navigation';
import { createEntityEngineProvider, useEntityEngine, EntityViewInspector } from '@scenemesh/entity-engine';
import { AdditionsSuiteAdapter } from '@scenemesh/entity-suite-additions';
import { EntityAIModule } from '@scenemesh/entity-engine-aimodule';
import { EntityEngineStudioLauncher } from '@scenemesh/entity-engine-studio';

export function EntityEngineProviderWrapper({ children }: { children: React.ReactNode }) {
  const router = useRouter();
  const EntityEngineProvider = createEntityEngineProvider({
    // config: { models, views }, // 可按需注入模型与视图
    suiteAdapters: [new AdditionsSuiteAdapter()],
    suiteAdapter: { suiteName: 'additions', suiteVersion: '1.0.0' },
    router: { navigate: (path, state) => router.push(path) },
    permissionGuard: { checkPermission: async () => true },
    renderers: [
      { ...EntityViewInspector },
      { ...EntityEngineStudioLauncher },
      { name: 'view-tool-2', slotName: 'view-tool', renderer: (ctx) => <button>工具扩展</button> },
    ],
    settings: {
      baseUrl: process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8082',
      endpoint: process.env.NEXT_PUBLIC_API_ENDPOINT || '/api/ee',
      authenticationEnabled: true,
    },
    modules: [new EntityAIModule()],
  });
  return <EntityEngineProvider>{children}</EntityEngineProvider>;
}
```

**服务端路由集成（Next.js App Router）**：

```ts
// app/api/ee/[[...slug]]/route.ts
import { EnginePrimitiveInitializer, fetchEntityEntranceHandler } from '@scenemesh/entity-engine/server';
import { EntityAIModule } from '@scenemesh/entity-engine-aimodule';
import { models, views } from 'src/entity/model-config';

const init = new EnginePrimitiveInitializer({ models, views, modules: [new EntityAIModule()] });
const handler = (req: Request) => fetchEntityEntranceHandler({ request: req, endpoint: '/api/ee', initializer: init });
export { handler as GET, handler as POST };
```

**在界面中使用容器组件（动态视图渲染）**：

```tsx
import { EntityViewContainer } from '@scenemesh/entity-engine';

export function ProductGrid() {
	return (
		<EntityViewContainer
			modelName="product"
			viewType="grid"
			viewName="productGridView"
			maintain={{ pageSize: 20 }}
		/>
	);
}
```

**树 + 引用 + 流程可视化结合（节选自场景设计器）**：

```ts
const ds = engine.datasourceFactory.getDataSource();
// 基于引用关系查找根节点
await ds.findMany({
	modelName: 'scene',
	query: {
		pageIndex: 1,
		pageSize: 1,
		references: {
			fromModelName: 'product',
			fromFieldName: 'rootScene',
			fromObjectId: currentProductId,
			toModelName: 'scene',
		},
	},
});
// 树结构展开
await ds.findTreeObjects({ modelName: 'scene', fieldName: 'children', rootObjectId });
```

**AI 模块集成**：`EntityAIModule` 注入后可在渲染器/工具链中暴露 AI 辅助功能（例如智能填表、生成字段描述、查询建议等）。

> 更多完整示例可参考：`apps/workbench/src/entity` 与 `apps/workbench/src/viewports/scene`。

---

## 3. 安装与 Peer 依赖

安装

```bash
# npm
npm i @scenemesh/entity-engine

# yarn
yarn add @scenemesh/entity-engine

# pnpm
pnpm add @scenemesh/entity-engine
```

必需 peer 依赖

- react >=18 <20
- react-dom >=18 <20
- react-hook-form >=7 <8
- Mantine（供内置视图与检查器使用）
	- @mantine/core 8.2.5
	- @mantine/hooks 8.2.5
	- @mantine/modals 8.2.5
	- @mantine/notifications 8.2.5
	- mantine-datatable 8.2.0

可选 peer（仅使用 server 能力时）

- @prisma/client（与 prisma CLI）

样式引入（必需）

```ts
import '@scenemesh/entity-engine/main.css'
```


## 4. 快速上手

> 假设你在一个包含本包的 monorepo（已安装依赖）中开发。

Next.js（App Router）最小用法：

```tsx
// app/layout.tsx
import '@scenemesh/entity-engine/main.css'
import { EntityEngineProvider } from 'src/entity-provider' // 参考下文示例或自行封装 Provider

export default function RootLayout({ children }: { children: React.ReactNode }) {
	return (
		<html lang="zh-CN">
			<body>
				<EntityEngineProvider>{children}</EntityEngineProvider>
			</body>
		</html>
	)
}
```

Vite（或 CRA）最小用法：

```tsx
// src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import '@scenemesh/entity-engine/main.css'
import { EngineInitializer, getEntityEngine } from '@scenemesh/entity-engine'

async function bootstrap() {
	const initializer = new EngineInitializer([], [])
	await getEntityEngine(initializer)
	ReactDOM.createRoot(document.getElementById('root')!).render(
		<React.StrictMode>
			<div>Entity Engine Ready</div>
		</React.StrictMode>
	)
}
bootstrap()
```

提示：本包将 React/ReactDOM、部分 UI 库设为 peer 依赖；构建产物 external 常见 UI 库，避免与你的应用重复打包或版本冲突。

### 构建 / 开发

```bash
# 构建产物 (dist)
yarn build

# 持续编译 (tsc --watch)
yarn dev

# 数据库（生成 Prisma Client / 迁移）
yarn db:generate     # prisma migrate dev
yarn db:migrate      # prisma migrate deploy
yarn db:push         # prisma db push
yarn db:studio       # 启动数据浏览
```

### 初始化引擎（最小）

```ts
import { EngineInitializer, getEntityEngine } from '@scenemesh/entity-engine';

// 1. 定义模型（最小示例）
const UserModel = {
	name: 'user',
	title: '用户',
	fields: [
		{ name: 'id', title: 'ID', type: 'string', isPrimaryKey: true },
		{ name: 'name', title: '姓名', type: 'string', searchable: true, isRequired: true },
		{ name: 'age', title: '年龄', type: 'number', searchable: true },
		{ name: 'role', title: '角色', type: 'enum', typeOptions: { options: [ { label: '管理员', value: 'admin' }, { label: '访客', value: 'guest' } ] }, searchable: true },
	],
} as const;

// 2. 定义视图（若不定义，也可由元数据自动补全创建默认视图）
const UserGridView = {
	name: 'user-grid',
	title: '用户列表',
	modelName: 'user',
	viewType: 'grid',
	items: [
		{ name: 'id', width: 120 },
		{ name: 'name', flex: 1 },
		{ name: 'age', width: 80 },
		{ name: 'role', width: 120 },
	],
};

// 3. 初始化（一次性调用）
async function bootstrap() {
	const initializer = new EngineInitializer([UserModel], [UserGridView]);
	const engine = await getEntityEngine(initializer);
	console.log(engine.toString());
}

bootstrap();
```

### 在 React 中使用某个视图（手动装配模式）

```tsx
import React from 'react';
import { getEntityEngine } from '@scenemesh/entity-engine';

export function UserGridContainer() {
	const [engine, setEngine] = React.useState<any>();
	React.useEffect(() => {
		getEntityEngine().then(setEngine); // 已初始化后无需再次传入 initializer
	}, []);
	if (!engine) return <div>Loading...</div>;

	const view = engine.metaRegistry.findView('user', 'grid');
	if (!view) return <div>View not found</div>;
	const supplemented = view.toSupplementedView();

	const gridView = engine.componentRegistry.getView('grid');
	if (!gridView) return <div>Grid view component missing</div>;
	const Comp = gridView.Component;
	return <Comp model={engine.metaRegistry.getModel('user')!} viewData={supplemented} behavior={{ mode: 'display' }} />;
}
```


---

## 5. 核心概念与架构

| 概念 | 接口 / 类 | 作用 |
| ---- | --------- | ---- |
| 实体字段 | `IEntityField` | 描述字段元信息（类型、校验、引用、搜索能力等）。 |
| 实体模型 | `IEntityModel` / `EntityModelDelegate` | 字段集合 + 行为补全（默认值 / Schema / QueryMeta）。 |
| 实体视图 | `IEntityView` / `EntityViewDelegate` | 描述一个模型的某种可视化（grid / form / master-detail / shell）。 |
| 视图字段项 | `IEntityViewField` | 与模型字段映射，可定义 widget、顺序、显示条件等。 |
| 引擎 | `EntityEngine` | 单例；聚合 metaRegistry / fieldTyperRegistry / dataSourceFactory / componentRegistry。 |
| 元数据注册表 | `EntityMetaRegistry` | 管理模型、视图、菜单；生成缺省视图。 |
| 组件注册表 | `EntityComponentRegistry` | 管理视图实现、Widget 套件、命名 Renderer。 |
| 组件套件适配器 | `IEntityComponentSuiteAdapter` | 一组 Widget 的命名空间（built-in 套件）。 |
| Widget | `EntityWidget` | 针对单字段或容器/引用呈现的可复用 UI 单元。 |
| 渲染器 | `IEntityNamedRenderer` | Slot 渲染扩展点（装饰 / 布局 / 行内渲染）。 |
| 字段类型 Typer | `IModelFieldTyper` | 决定默认值 / 默认 Widget / 查询能力。 |
| 数据源 | `IEntityDataSource` | CRUD + 引用 + 树形查询抽象。默认实现：tRPCEntityObjectDataSource。 |
| 初始化器 | `EngineInitializer` | 首次创建引擎时批量注册模型、视图、套件、渲染器。 |

---

### 架构概览

```text
									 +---------------------------+
									 |        EntityEngine       | (Singleton)
									 +---------------------------+
										 |       |         |     |
										 v       v         v     v
							 +---------+ +-----------+ +--------+ +----------------+
							 | Meta    | | FieldType | | Data   | | Component      |
							 | Registry| | Registry  | |Source  | | Registry       |
							 +----+----+ +-----+-----+ +---+----+ +-------+--------+
										|            |          |              |
					Models <->|            |          |              |<-> Views Impl
					Views  <->|            |          |              |<-> Widget Suites
										|            |          |              |<-> Renderers
										|            |          |              |
										v            v          v              v
							 Delegates    FieldTypers   TRPC DS     React Components
```

关键流：
1. 初始化阶段：`EngineInitializer` 注册模型 / 视图 / 套件 / 渲染器。
2. 运行时请求某视图：从 `metaRegistry` 获取 `IEntityViewDelegate`，补全 => 视图组件执行数据加载（通过 `datasourceFactory.getDataSource()`）。
3. 用户操作（增删改） -> DataSource (tRPC) -> Server (Prisma) -> 结果回显。

---

## 6. 目录结构概览

简化摘录：

```
src/
	core/
		engine/                # 引擎与初始化
		datasources/           # 数据源工厂 & tRPC 实现
		delegate/              # Delegate 封装 (Model/View/Menu)
		fieldtypes/            # 字段类型注册表
		theme/                 # 主题 (占位 / 可扩展)
		types/                 # 核心类型接口 (engine / delegate / datasource ...)
	components/
		views/                 # 视图实现 (form / grid / mastail / shell)
		types/                 # 视图 & widget 类型定义
		share/                 # 公共共享组件 (search-panel 等)
	build-ins/
		suite/                 # 内置组件套件 & widgets
	services/api/trpc/       # tRPC 客户端工具
	lib/data/                # 数据转换工具 (convertRawEntityObject 等)
	types/                   # 元数据 / 数据 / 字段 / 样式 类型
	uikit/                   # UI 基础 (provider / surface 等)
```

---

## 7. 模型与视图元数据

模型（`IEntityModel`）定义领域结构，视图（`IEntityView`）定义展现形态。未定义的视图可按模型自动补全生成。大型项目建议将模型拆分多个文件并汇总导出。

### 示例：片段（来自 workbench `model-config.ts`）

```ts
export const models: IEntityModel[] = [
	{
		name: 'product',
		title: '产品',
		fields: [
			{ name: 'name', title: '名称', type: 'string', isRequired: true, searchable: true },
			{ name: 'price', title: '价格', type: 'number' },
			{ name: 'rootScene', title: '根场景', type: 'one_to_one', refModel: 'scene' },
		],
	},
	{
		name: 'scene',
		title: '场景',
		fields: [
			{ name: 'title', title: '标题', type: 'string', isRequired: true },
			{ name: 'children', title: '子场景', type: 'one_to_many', refModel: 'scene' },
		],
	},
];
```

### 视图定义示例

```ts
export const views: IEntityView[] = [
	{
		name: 'productGridView',
		title: '产品列表',
		modelName: 'product',
		viewType: 'grid',
		items: [ { name: 'name' }, { name: 'price' }, { name: 'rootScene' } ],
	},
	{
		name: 'sceneFormView',
		title: '场景表单',
		modelName: 'scene',
		viewType: 'form',
		items: [ { name: 'title' }, { name: 'children', widget: 'reference-many' } ],
	},
];
```

## 8. 视图渲染与插槽扩展

通过注册命名渲染器（`IEntityNamedRenderer`）向视图生命周期插入 UI：

| slotName 示例 | 典型用途 |
| -------------- | -------- |
| `view-tool` | 表格/表单顶部工具条扩展 |
| `shell-settings-item2` | 系统壳层设置菜单条目 |
| `record-inline` | 行内扩展按钮/标签 |

注册示例：

```ts
renderers: [
	{ name: 'view-tool-2', slotName: 'view-tool', renderer: (ctx) => <span>工具扩展 {ctx.model.name}</span> },
	{ ...EntityViewInspector }, // 内置调试器
]
```

> 上层应用可通过 DSL + 权限系统动态控制哪些渲染器激活。

## 9. 组件套件 (Suite Adapter) 与自定义 Widget

组件套件用于将“抽象字段语义”映射为“具体 UI 实现”，不同 `suiteAdapter` 可复用同一组模型与视图元数据。

实现要点：
1. 实现接口 `IEntityComponentSuiteAdapter`
2. 提供 `suiteName`、版本与 `getWidget(name)`
3. 在 Provider 中通过 `suiteAdapters` 注册，并指定当前使用的 `suiteAdapter`

> 你可以同时注册多套适配器（例如 Mantine / Additions），再让用户在运行时切换主题或 UI 表现。

## 10. 数据源与引用 / 树 / 分组

数据源接口：`IEntityDataSource`，默认实现：`TRPCEntityObjectDataSource`。

常用方法：

| 方法 | 作用 |
| ---- | ---- |
| `findMany` | 分页查询实体对象 |
| `create / update / delete` | 基础 CRUD |
| `findReferences / findReferencesCount` | 引用关系列表与计数 |
| `createReference / deleteReference / deleteReferences` | 多对多关系增删 |
| `findTreeObjects` | 递归树结构（支持 children 字段） |
| `findGroupedObjects` | 根据字段或时间/范围聚合分组 |

多对多引用 UI 可直接使用内置组件：

```tsx
import { ReferenceEditMMComp } from '@scenemesh/entity-engine';
// 在一个自定义表单 Widget 内：
<ReferenceEditMMComp
	fieldType={{ /* 来自 view 字段解析 */ }}
	object={currentObject}
	value={selectedIds}
	onChange={(ids) => setSelectedIds(ids)}
/>
```

## 11. 查询 DSL

查询结构由 `IEntityQuery` + `IEntityQueryItem` 组成：

```ts
const query = {
	pageIndex: 1,
	pageSize: 20,
	filter: {
		and: [
			{ field: 'name', operator: 'contains', value: 'x' },
			{ or: [ { field: 'status', operator: 'eq', value: 'active' }, { field: 'status', operator: 'eq', value: 'draft' } ] },
		],
	},
};
```

> 未来规划：提供“可视化 Query Builder + 表达式编译器”生成最终 Prisma where 条件。

## 11. 服务端接入（Next.js）

沿用 tRPC 风格：

1. 创建 `EnginePrimitiveInitializer` 注入模型与视图
2. 在 Route Handler 中调用 `fetchEntityEntranceHandler`
3. 客户端 Provider 使用相同 endpoint

已支持的后端能力：对象 CRUD / 引用 / 树 / 分组 / 视图+模型增量下发。

## 12. 多租户架构（Multi-Tenancy Architecture）

基于 **PostgreSQL Schema 隔离**，每个租户拥有独立 schema，通过 `PrismaService` 管理连接池，实现数据强隔离与高性能并发访问。JWT token 自动提取 `tenantId` 并切换到对应 schema。

### 核心特性

| 特性 | 说明 |
| ---- | ---- |
| **Schema 隔离** | 每个租户独立 PostgreSQL schema（`tenant_<id>`），原生数据隔离 |
| **连接池复用** | 自动管理租户 Prisma 客户端，按需创建与复用连接 |
| **JWT 自动提取** | 从 Authorization header 解析 tenantId，无需手动传参 |
| **强制访问控制** | 数据 API 自动验证租户上下文，防止越权访问 |
| **灵活 ID 格式** | 支持 UUID（推荐）和 Base62 短 ID（10-12位） |

### 服务端使用

**1. 直接使用 PrismaService（适用于自定义后端逻辑）**

```typescript
import { PrismaService } from '@scenemesh/entity-engine/server';

// 获取租户专用的 Prisma 客户端
const tenantId = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'; // 从 JWT 提取
const prisma = await PrismaService.getTenantClient(tenantId);

// 操作租户数据（自动使用租户 schema）
const users = await prisma.entityObject.findMany({
  where: { modelName: 'user' }
});

// 连接池管理
PrismaService.getActiveConnectionCount();      // 查看活跃连接数
await PrismaService.disconnectTenant(tenantId); // 断开指定租户连接
```

**2. tRPC 集成（已内置，开箱即用）**

tRPC context 自动从 JWT token 提取 `tenantId` 并创建租户上下文：

```typescript
// src/services/api/trpc.ts (已实现，无需修改)
export const createTRPCContext = async (opts, initializer) => {
  const engine = await getEntityEnginePrimitive(initializer);

  // 自动从 Authorization header 解析 JWT
  const authHeader = opts.headers.get('authorization');
  let tenantId: string | undefined;
  let db: PrismaClient | undefined;

  if (authHeader?.startsWith('Bearer ')) {
    // 解析 JWT payload 获取 tenantId
    const payload = parseJWT(token);
    tenantId = payload.tenantId;

    // 获取租户专用数据库客户端
    if (tenantId && PrismaService.isValidTenantId(tenantId)) {
      db = await PrismaService.getTenantClient(tenantId);
    }
  }

  return { db, engine, tenantId };
};
```

**JWT Token Payload 结构示例**：

```json
{
  "userId": "user_123",
  "tenantId": "550e8400-e29b-41d4-a716-446655440000",
  "role": "admin",
  "iat": 1735545600,
  "exp": 1735632000
}
```

### 客户端集成

客户端 tRPC 调用自动注入 `Authorization` header（从 `localStorage.access_token` 读取）：

```typescript
// src/services/api/trpc/react.tsx (已实现)
httpBatchLink({
  url: getUrl('/trpc'),
  headers: () => {
    const headers = new Headers();
    const token = localStorage.getItem('access_token');
    if (token) {
      headers.set('Authorization', `Bearer ${token}`);
    }
    return headers;
  }
})
```

### 数据隔离保障

所有数据 API 内部自动执行租户检查：

```typescript
// 数据 API（如 listObjects、createObject）强制要求租户上下文
function requireTenantDatabase(ctx: ApiContext): asserts ctx {
  if (!ctx.db || !ctx.tenantId) {
    throw new Error('Authentication required: Please login to access tenant data');
  }
}

// 元数据 API（如 findPlainConfig）不需要租户隔离
export async function findPlainConfigLogic(ctx: ApiContext, input) {
  // 仅访问模型/视图元数据，无需租户数据库
  return ctx.engine.metaRegistry.getModel(input.modelName);
}
```

### 最佳实践

- ✅ **适用场景**：多租户 SaaS、企业级应用、数据隔离要求高的场景
- ⚠️ **注意事项**：
  - 租户 schema 需要独立执行 Prisma 迁移
  - JWT token 必须可信（使用签名验证）
  - 生产环境建议监控连接池大小与内存占用

> 更多细节（schema 迁移、性能优化、故障排查）请参见官方文档。

---

## 13. 模块化扩展 & AI 集成

模块（`IEntityModule`）可：
- 注册额外模型 / 视图
- 注册渲染器 / 动作 / Servlet
- 注入 AI 功能（见 `EntityAIModule`）

动态加载：客户端可通过 `esm.sh/<package>/dist/index.js` 按需拉取（需保证导出 default）。

## 14. 权限 / 导航 / 会话

Provider 选项：

| 选项 | 作用 |
| ---- | ---- |
| `router.navigate(path,state)` | 桥接到应用路由（Next.js push / React Router） |
| `permissionGuard.checkPermission(action)` | 统一权限校验入口 |
| `settings` | baseUrl / endpoint / authenticationEnabled |
| `modules` | 注入模块数组 |

> 你可在 `checkPermission` 里访问全局用户上下文，实现模型/字段/操作级别控制。

## 15. 调试与开发工具

| 工具 | 描述 |
| ---- | ---- |
| `EntityViewInspector` | 在运行时查看当前视图的补全后结构（模型 / 字段 / widget 解析结果）。 |
| `EntityEngineStudioLauncher` | 打开交互式运行时面板，未来扩展模型编辑 / 视图热更新。 |
| 日志 | `TRPCEntityObjectDataSource` 在 URL 变更时输出新客户端创建日志。 |

## 16. Roadmap

- [ ] 查询 DSL -> 编译器 + 单元测试
- [ ] 模型 / 视图 版本化与快照导出
- [ ] 引用关系附加属性（排序 / 标签 / 权重）
- [ ] 渲染器 DevTools 面板
- [ ] 模块远程签名校验与缓存策略
- [ ] 多数据源聚合（federation）
- [ ] 表达式求值沙箱化 (CEL / jsep)
- [ ] 视图性能探针 & 监控面板
- [ ] AI 辅助：模型结构生成 / 视图建议 / 查询自然语言解析

## 17. FAQ

**Q: 可以只用数据源而不使用内置视图吗？**  
A: 可以。直接 `getEntityEngine().datasourceFactory.getDataSource()` 调用 CRUD。

**Q: 如何扩展一个新视图类型？**  
A: 实现 `EntityView` 接口（或继承内置基类），在 `componentRegistry.registerView()` 注册。

**Q: 可以在多引擎实例间隔离吗？**  
A: 当前主设计是单例。后续将加入多实例 + context 方案。

**Q: 引用是否支持附加元数据？**  
A: 当前结构最简。可在后端扩展引用表（例如增加 jsonb 列）并在数据源扩展。

**Q: SSR 支持吗？**  
A: 是。服务端使用 `EnginePrimitiveInitializer`，客户端使用 `createEntityEngineProvider`。注意避免重复初始化。

## 18. License

MIT © scenemesh

---

> 如果你在集成上遇到困难，或希望我进一步为你的场景定制示例/脚手架，可直接在仓库发起 Issue 或讨论。


### 1. 注册额外视图与组件套件

```ts
import { EngineInitializer, getEntityEngine } from '@scenemesh/entity-engine';

class MySuiteAdapter { /* implements IEntityComponentSuiteAdapter */ }
class MyRenderer { name = 'toolbar-extra'; slotName = 'toolbar'; renderer = () => <div>Extra</div>; }

const initializer = new EngineInitializer([UserModel], [UserGridView], [new MySuiteAdapter()], [new MyRenderer()]);
await getEntityEngine(initializer);
```

### 2. 访问数据源 CRUD

```ts
const engine = await getEntityEngine();
const ds = engine.datasourceFactory.getDataSource();
await ds.create({ modelName: 'user', data: { values: { name: 'Lucy', age: 20, role: 'guest' } } });
const { data, count } = await ds.findMany({ modelName: 'user', query: { pageIndex: 1, pageSize: 10 } });
```

### 3. 动态生成默认视图

如果未显式注册某模型的某种 viewType（例如 `grid`），调用：

```ts
const v = engine.metaRegistry.findView('user', 'grid'); // 若无则按模型字段生成
```

### 4. 条件显示 / 只读 / 必填逻辑

`IEntityViewField` 支持：

| 属性 | 含义 | 示例 |
| ---- | ---- | ---- |
| hiddenWhen | 条件表达式为 true 时隐藏 | `role=="guest"` |
| showWhen | 条件表达式为 true 时显示 | `age>18` |
| readOnlyWhen | 条件成立时只读 | `role=="admin"` |
| disabledWhen | 条件成立时禁用 | `age<1` |
| requiredWhen | 条件成立时必填 | `role=="admin"` |

（表达式解析器按需在上层应用实现，可替换为任意逻辑解析方案）

### 5. 在应用中通过 Provider 集成（Provider Integration）

`apps/workbench/src/entity/provider` 目录展示了如何在 Next.js (App Router) 环境中一次性封装引擎：

核心点：

1. 使用 `createEntityEngineProvider` 生成 React 上下文 Provider（内部完成 `EntityEngine` 初始化与依赖注入）。
2. 注入多套组件套件：示例中同时使用 `SemiSuiteAdapter` 与 `MUISuiteAdapter`，并指定一个当前使用的套件 `suiteAdapter`（可作为默认/首选套件描述）。
3. 包裹在 `TRPCReactProvider` 外层（或内层）以提供数据访问上下文。
4. 自定义 `router.navigate` 以适配 Next.js 的 `useRouter().push()`。
5. 提供 `permissionGuard.checkPermission` 异步函数集中处理权限校验（此处示例直接放行）。
6. 注册自定义 `renderers`（命名插槽扩展）以及内置 `EntityViewInspector` 以调试视图元数据。

示例代码（建议放在 `src/entity-provider.tsx`）：

```tsx
'use client';
import { useRouter } from 'next/navigation';
import { createEntityEngineProvider, EntityViewInspector } from '@scenemesh/entity-engine';
import { MUISuiteAdapter } from '@scenemesh/entity-suite-mui';
import { SemiSuiteAdapter } from '@scenemesh/entity-suite-semi';
import { TRPCReactProvider } from '@scenemesh/entity-engine/services/api/trpc/react';

import { models, views } from 'src/entity/model-config'; // 你的模型与视图配置

import React from 'react'
import { createEntityEngineProvider, EntityViewInspector, type IEntityNamedRenderer } from '@scenemesh/entity-engine'

// 你的模型与视图（最小示例）
const models = [ { name: 'user', title: '用户', fields: [ { name: 'id', title: 'ID', type: 'string', isPrimaryKey: true }, { name: 'name', title: '姓名', type: 'string' } ] } ] as any
const views = [ { name: 'user-grid', title: '用户列表', modelName: 'user', viewType: 'grid', items: [ { name: 'id' }, { name: 'name' } ] } ] as any

// 自定义插槽渲染器（可选）
const ViewToolbar: IEntityNamedRenderer = { name: 'view-tool-2', slotName: 'view-tool', renderer: (ctx) => <div>工具区 {ctx.model.name}</div> }

export function EntityEngineProvider({ children }: { children: React.ReactNode }) {
	const router = useRouter()

	// 使用 memo 避免每次渲染都重新创建 Provider 组件
	const Provider = React.useMemo(() => createEntityEngineProvider({
		models,
		views,
		suiteAdapter: { suiteName: 'build-in', suiteVersion: '1.0.0' },
		router: { navigate: (path, state) => router.push(path) },
		permissionGuard: { checkPermission: async () => true },
		renderers: [ ViewToolbar, { ...EntityViewInspector } ],
		serverInfo: { baseUrl: '', endpoint: '/api/ee' },
	}), [router])

	return <Provider>{children}</Provider>
}
```

在页面中直接使用：

```tsx
// app/layout.tsx 或某上层布局
import { EntityEngineProvider } from 'src/entity-provider';

export default function RootLayout({ children }: { children: React.ReactNode }) {
	return (
		<html lang="zh-CN">
			<body>
				<EntityEngineProvider>
					{children}
				</EntityEngineProvider>
			</body>
		</html>
	);
}
```

这样任意子组件即可通过（假设库已导出相应 hooks，如未来 `useEntityEngine()`）获取引擎实例与上下文数据，实现：

- 视图渲染（Grid/Form/MasterDetail）
- 数据 CRUD / 引用查询
- 自定义插槽渲染扩展（toolbar / shell settings）
- 权限与路由统一入口

> 若需按租户/用户隔离实例，可在 `createEntityEngineProvider` 外再包一层，根据参数动态构建不同 initializer。

---

## 查询与过滤 (Query & Filter)

查询结构：`IEntityQuery`。

```ts
type IEntityQuery = {
	pageSize?: number;
	pageIndex?: number;
	sortBy?: Record<string, 'asc' | 'desc'>;
	references?: { fromModelName; fromFieldName; fromObjectId; toModelName };
	filter?: IEntityQueryItem; // 递归 AND / OR / NOT 结构
}
```

叶子条件：

```ts
{ field: 'age', operator: QueryOperator.GT, value: 18 }
```

复合条件：

```ts
{
	and: [
		{ field: 'role', operator: QueryOperator.EQ, value: 'admin' },
		{ or: [
				{ field: 'age', operator: QueryOperator.GT, value: 30 },
				{ field: 'age', operator: QueryOperator.IS_NULL, value: null }
			]
		}
	]
}
```

支持操作符（QueryOperator）：`EQ, NE, GT, GTE, LT, LTE, CONTAINS, STARTS_WITH, ENDS_WITH, IN, NOT_IN, BETWEEN, IS_NULL, IS_NOT_NULL` 等。

引擎可通过 `modelDelegate.getQueryMeta()` 给 UI 构建器提供字段支持的操作符列表及枚举选项。

---

## 组件与视图扩展 (Views & Widgets Extensibility)

### 新增视图实现

```ts
import { EntityView } from '@scenemesh/entity-engine';
export class TimelineView extends EntityView { 
	readonly info = { viewName: 'timeline', displayName: '时间线视图' };
	readonly Component = (props) => <div>TODO Timeline of {props.model.name}</div>;
}

// 注册
engine.componentRegistry.registerView(new TimelineView());
```

### 自定义 Widget

```ts
import { EntityWidget } from '@scenemesh/entity-engine';
class BadgeWidget extends EntityWidget {
	readonly info = { widgetName: 'badge', displayName: '徽章' };
	readonly Component = ({ value }) => <span className="badge">{value}</span>;
}

class BadgeSuiteAdapter { // implements IEntityComponentSuiteAdapter
	suiteName = 'badge-suite'; suiteVersion = '0.0.1';
	private widgets = new Map([['badge', new BadgeWidget()]]);
	getWidget(n){ return this.widgets.get(n); }
	getWidgets(){ return [...this.widgets.values()]; }
}
engine.componentRegistry.registerAdapter(new BadgeSuiteAdapter());
```

### 命名 Renderer (Slot)

```ts
engine.componentRegistry.registerRenderer({
	name: 'grid-toolbar-extra',
	slotName: 'grid.toolbar.right',
	renderer: () => <button>导出 CSV</button>
});
```

---

## 字段类型扩展 (Field Type Extension)

实现 `IModelFieldTyper`：

```ts
import { z } from 'zod';
class GeoPointFieldTyper { // implements IModelFieldTyper
	get title(){ return '地理点'; }
	get type(){ return 'geopoint'; }
	get icon(){ return 'map_pin'; }
	get description(){ return '经纬度'; }
	getDefaultValue(){ return { lat: 0, lng: 0 }; }
	getDefaultSchema(){ return z.object({ lat: z.number(), lng: z.number() }); }
	getQueryItemMeta(field){ return { field, operators: [/* ... */] }; }
	getDefaultWidgetType(viewType:string){ return 'map'; }
}
engine.fieldTyperRegistry.registerFieldTyper(new GeoPointFieldTyper());
```

随后在模型字段中使用 `type: 'geopoint'`。

---

## 数据源扩展 (DataSource Extension)

默认实现：`TRPCEntityObjectDataSource`。

自定义：

```ts
class RestEntityDataSource { // implements IEntityDataSource
	async findOne({ id }) { /* fetch(`/api/entity/${id}`) */ }
	async findMany({ modelName, query }) { /* ... */ return { data: [], count: 0 }; }
	// 其余方法按接口补全
}

class MyDataSourceFactory { // implements IEntityDataSourceFactory
	private ds = new RestEntityDataSource();
	getDataSource(){ return this.ds; }
}

// 在初始化时替换
// 方式一：fork 引擎创建逻辑
// 方式二：后续扩展 createEntityEngine 暴露工厂注入（TODO: 参见 Roadmap）
```

---

## 校验与默认值 (Validation & Defaults)

1. 字段可以直接提供 `schema: ZodTypeAny`；否则按类型自动推导。
2. 模型委托 `EntityModelDelegate.schema` 聚合所有字段 schema -> 用于 form 校验。
3. 未提供值时，通过 `toSupplementedValues` 使用字段默认值或类型默认值填充。

> 注意：复杂业务校验（交叉字段、异步校验）可在上层表单库 / 后端再补充。

---

## tRPC 集成 (tRPC Integration)

文件：`src/services/api/trpc/utils.ts`

```ts
export const vanillaTrpcClient = createTRPCClient<AppRouter>({ links: [ httpBatchLink({ url, transformer: superjson }) ] });
```

数据源 `TRPCEntityObjectDataSource` 通过 `vanillaTrpcClient.model.*` 调用，例如：

```ts
await vanillaTrpcClient.model.listObjects.query({ modelName, pagination, reference, filter });
```

> SSR 关闭 (`ssr: false`)，如需要服务端渲染可扩展配置。

---

## 常用接口参考 (API Reference Snapshot)

> 摘要列出关键接口字段，详见源码 `src/**`。

### IEntityModel

```ts
interface IEntityModel { name: string; title: string; description?: string; fields: IEntityField[] }
```

### IEntityField

```ts
interface IEntityField { name; title; type; isRequired?; isPrimaryKey?; isUnique?; searchable?; defaultValue?; refModel?; refField?; schema?; order?; }
```

### IEntityView

```ts
interface IEntityView { name; title; modelName; viewType; items: IEntityViewField[]; density?; canEdit?; canNew?; canDelete?; }
```

### IEntityDataSource (节选)

```ts
interface IEntityDataSource {
	findOne({ id }): Promise<IEntityObject | null | undefined>;
	findMany({ modelName, query }): Promise<{ data: IEntityObject[]; count: number }>;
	create({ modelName, data, reference? }): Promise<IEntityObject | null | undefined>;
	update({ id, data }): Promise<boolean>;
	delete({ id }): Promise<boolean>;
}
```

---

## Roadmap

| 状态 | 目标 | 说明 |
| ---- | ---- | ---- |
| ✅ | 基础引擎单例 / 模型 / 视图补全 | 当前实现 |
| ✅ | tRPC 数据源 CRUD & 引用 & 树 | `TRPCEntityObjectDataSource` |
| ✅ | 内置视图 (form / grid / mastail / shell) | 可扩展注册更多 |
| ⏳ | 数据源注入定制 API | 允许外部直接提供自定义 factory |
| ⏳ | 视图运行时条件解析器抽象 | 允许替换表达式解析策略 |
| ⏳ | 字段类型可配置默认 WidgetMap | 细粒度控制 per viewType |
| ⏳ | 国际化 (i18n) 插件化 | 与 `locales` 目录集成 |
| ⏳ | 权限与操作策略接口 | 结合 `permission.types` |
| ⏳ | 测试覆盖提升 | Unit + Integration + 可视回归 |

欢迎在 Issue / PR 中补充你的需求。

---

## 贡献指南 (Contributing)

1. Fork / 新建分支：`feat/x`、`fix/x`。
2. 安装依赖并执行 `yarn build` 确保通过。
3. 提交前运行：

	```bash
	yarn lint && yarn fm:check
	```

4. 附带最小复现或使用示例。
5. 遵循语义化提交（建议）：`feat: ...` / `fix: ...` / `docs: ...` 等。

---

## 许可 (License)

当前 `package.json` 标记为 `private: true`，尚未明确开源 License。若计划公开发布，建议：

1. 选择合适协议（MIT / Apache-2.0 / MPL-2.0 等）。
2. 添加 `LICENSE` 文件并在 `package.json` 中声明 `"license": "MIT"`（示例）。
3. 更新本 README 中的许可章节。

---

## 常见问题 (FAQ)

| 问题 | 说明 |
| ---- | ---- |
| 为什么需要 EngineInitializer? | 保证首次创建时批量注册，避免重复注册与竞态。 |
| 可以二次调用 getEntityEngine(initializer)? | 第二次会忽略传入的 initializer（已存在实例）；如需重置需扩展清理逻辑。 |
| 未定义视图时字段顺序如何? | 使用字段的 `order`，缺省为 0；同序时按声明顺序。 |
| 查询表达式如何解析? | 核心未内置解析器，留给上层（前端构造统一结构后传至后端）。 |
| 如何做权限控制? | 未来 Roadmap 中将引入权限接口，可对模型 / 字段 / 动作进行裁剪。 |

---

## 致谢 (Acknowledgements)

本项目借鉴了多种低代码 / 元数据驱动思想（如 Ad Hoc Admin、Headless CMS、tRPC 模式），感谢社区生态。

---

如有问题或改进建议，欢迎提交 Issue / PR。

> Keep building data-driven UI with less boilerplate.