Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 91e163640a | |||
| 973f74d0d8 | |||
| 41f59dda72 |
@@ -1,67 +1,70 @@
|
||||
# DatAlive 低代码设计器数据结构设计
|
||||
# DatAlive 低代码设计器 - Agent 指南
|
||||
|
||||
## 项目介绍
|
||||
## 头号铁律:不要直接改代码
|
||||
|
||||
本项目的实现目标是设计一个尽可能通用的低代码设计器平台的核心数据结构,该平台能够支持以拖拽和配置组件、路由、状态、事件、过滤器、页面等实体元素,以可视化的交互方式搭建数字大屏、中后台系统以及产品官网等多类应用。
|
||||
> **严禁直接修改项目源代码。** Agent 的工作模式:阅读 → 给出方案/代码片段 → 由用户手动落地。
|
||||
> 未经用户明确指示前,不要使用 `Edit` / `Write` / `ast_grep_replace` / `lsp_rename` 等会改动文件的工具。
|
||||
> 这是项目自定的最高优先级协作规则(见历史 commit `6d99132`),优先级高于一切默认行为。
|
||||
|
||||
其中,当前阶段的首要目标场景是**数字大屏**。围绕该场景,平台的核心 `Schema` 结构已经进行了更深入的分析、约束与推演;而对于中后台系统与产品官网场景,现阶段主要完成的是字段层面的前瞻性预留,以保证整体结构具备后续扩展空间,但尚未进行同等深度的专项分析与完备性验证。
|
||||
## 项目阶段(决定 Agent 期望)
|
||||
|
||||
所谓“核心数据结构”,主要是在平台中设计应用或大屏系统时所依赖的一套统一配置蓝图。
|
||||
- 当前仅有**核心 Schema 类型定义**,全部位于 `src/schema/`。
|
||||
- `src/index.ts`、`src/schema/index.ts` **当前为空**,没有运行时代码、组件、引擎、测试。
|
||||
- README 中的 `bun run index.ts` 不会有任何输出 —— 不要尝试"运行"或"测试"项目。
|
||||
- 远期路线(未实现,勿擅自引入):`React + Vite + React Router/Tanstack Router + Tanstack Query + Zustand`,五大引擎(工作区 / 画布 / 渲染 / 数据 / 交互)。
|
||||
|
||||
这套蓝图既需要能够描述设计时配置,也需要能够描述运行时配置,其中:
|
||||
## 工具链与命令
|
||||
|
||||
- 设计时配置,指用户在设计器中拖拽、配置组件、路由、状态、事件、过滤器、页面等元素时,需要被持久化保存的配置信息。
|
||||
- 运行时配置,指用户完成设计后,在最终应用运行时需要被加载和消费的配置信息。
|
||||
- 包管理:**Bun**(lockfile = `bun.lock`)。**勿用 npm/pnpm/yarn**。
|
||||
- `package.json` **没有 `scripts` 字段**,不存在 lint / test / build / typecheck 命令。
|
||||
- 类型检查唯一手段:`bunx tsc --noEmit`(`tsconfig.json` 已 `noEmit: true` + `strict` 全开 + `noUncheckedIndexedAccess`)。
|
||||
- 没有 ESLint / Prettier / Vitest / CI / pre-commit / codegen / dev server。
|
||||
|
||||
在本项目中,`Schema` 的角色应被明确定位为:**整个应用配置的持久化表现形式与统一交换格式**。
|
||||
## 语言
|
||||
|
||||
用户保存到数据库的是这份 `Schema`,导出到本地的是这份 `Schema`,从外部导入到平台中的也是这份 `Schema`。但平台在运行过程中,**不会直接以 `Schema` 作为工作内存来驱动各项能力**。相反,平台会在导入 `Schema` 后,将其解析、校验、规范化,并拆分到与各引擎职责对应的内部状态 `Store` 中;而在保存、导出或发布时,再将各引擎 `Store` 中的稳定数据重新聚合为 `Schema`,用于持久化或输出。
|
||||
- 注释、文档、PR/commit 信息均用**中文**;类型与变量用英文。新增内容请保持。
|
||||
- `docs/` 下文件名为中文,部分终端(PowerShell + GBK)会显示乱码 —— 用 `Glob "docs/*.md"` 或 `Read` 直接以 UTF-8 读取,不要试图通过 shell ls 解读。
|
||||
|
||||
因此可以认为:
|
||||
## Schema 架构铁律
|
||||
|
||||
- `Schema` 面向持久化、导入导出与跨边界交换;
|
||||
- `Store` 面向平台运行时、引擎协作与高频状态操作。
|
||||
修改 `src/schema/**` 前必读。这些约定在多个文件的 JSDoc 中反复强调,违反会污染整个蓝图:
|
||||
|
||||
此外,平台在整体运行语义上需要明确区分 `设计态(Design Mode)`、`预览态(Preview Mode)` 与 `运行态(Runtime Mode)` 三种模式。三态的切换应被视为平台的**运行时上下文(AppMode)** 差异,而不是 `Schema` 本身的结构差异。换言之,`AppMode` 不属于需要持久化存储的 `Schema` 蓝图,而应由外部宿主容器或平台运行时环境显式注入。
|
||||
1. **Schema vs Store 二元分离**
|
||||
- Schema 仅承载需要持久化、可导入导出的稳定配置。
|
||||
- 派生状态(`isLoading / data / error`)、`AppMode`、`parentId`、设计器选中态、缓存等**永不进 Schema**。
|
||||
2. **`AppMode` 不是 Schema 字段**
|
||||
- `design / preview / runtime` 三态由宿主容器在运行时注入。
|
||||
3. **所有可寻址实体继承 `Entity`** (`src/schema/shared/entity.ts`):`id`(UUID,RPC 寻址 + React key)+ `label`(仅 UI 展示)。
|
||||
- **`label` 严禁出现在表达式或数据流绑定中**,那里只能用 `id` 或 `Variable.key`。
|
||||
4. **`JsonValue`** (`src/schema/shared/json-value.ts`) 是序列化铁壁。Schema 中用户可填写的纯数据字段必须用它,不要用 `any` / `object` / `unknown`,更不能允许 `Function / Date / RegExp`。
|
||||
5. **`DynamicExpression`** (`src/schema/shared/dynamic-expression.ts`) 是统一逃生舱:`type: 'code'` + `code: string`(**函数体片段**,需含 `return`)。引擎用 `new Function('context', code)` 编译,注入 `context: { variables, queries, event?, data? }`。新增 code 模式字段一律 `extends DynamicExpression`。
|
||||
6. **二元联合 `fixed | code` 模式** —— 见 `RestRequest`、`ActionParams`、`Condition`、`Filter`、`QueryConfig`、`MutationConfig`、`DataSourceConfigByRest`。新增可逃生字段时延续此命名与判别式。
|
||||
7. **`null` 在 REST 配置中具有显式抹除语义**:`RestRequestByFixed.params/headers` 中的 `null` 表示从合并后的全局 DataSource 配置中**物理删除**该键,并非置空字符串。
|
||||
8. **数组字段必须显式 `[]`,不允许 `undefined`** —— `interactions` / `children` / `routes` / `pages` / `filterIds` 等。引擎依赖此约定避免兜底分支。
|
||||
9. **没有 `MutationConfigByStatic`** —— 写操作必有副作用,不允许 mock 变体。
|
||||
10. **Action 不枚举具体类型**(拒绝 `ShowToast` / `Navigate` 这类设计),统一用 `target: { type, id } + method + params` 的泛化 RPC 模型。
|
||||
11. **`Variable.key` 是表达式中可见的真实标识符**:必须满足 `/^[a-zA-Z_$][a-zA-Z0-9_$]*$/` 且全局唯一;与 `label` 严格区分。
|
||||
12. **`parentId` 永不持久化**:组件树是嵌套结构,扁平 `parentId` 字典由引擎在内存中按需推导。
|
||||
|
||||
其中:
|
||||
## 命名与组织约定
|
||||
|
||||
- `设计态` 用于可视化编辑、拖拽编排与配置应用结构;
|
||||
- `运行态` 用于面向最终用户提供纯净、完整的应用运行体验;
|
||||
- `预览态` 则用于在不进入正式运行环境的前提下,以尽可能接近真实运行态的方式对应用进行预览、验证与调试。
|
||||
- 文件名 **kebab-case**:`component-data.ts`、`data-source-by-rest.ts`。
|
||||
- 标记联合命名 **`<Type>By<Variant>`**:`ComponentDataByStatic`、`QueryConfigByRest`、`FilterByCode`、`DataSourceConfigByRestWithCode`。
|
||||
- 每个 schema 域目录有自己的 `index.ts` barrel;跨域请从 barrel `import type { ... } from '../shared'`,不要写 `'../shared/entity'`。
|
||||
- 现有域:`application / component / data-source / filter / interaction / mutation / page / query / route / shared / variable`。
|
||||
- `src/schema/index.ts` 当前为空;如需新增聚合导出,请在此处汇总。
|
||||
|
||||
`预览态` 既不同于可任意编辑配置的 `设计态`,也不同于面向最终用户的纯净 `运行态`,而是一种介于两者之间的**受控运行模式**。在该模式下,平台应尽可能复用与 `运行态` 相同的 `Schema` 渲染主链路,放行业务交互、数据请求、事件流转与页面跳转,使用户或实施人员能够提前验证应用在真实运行中的行为表现。
|
||||
## 设计文档(在 `docs/`,修改 Schema 前对齐)
|
||||
|
||||
同时,`预览态` 还应具备必要的白盒调试与观测能力,用于辅助定位应用配置中的问题,例如:
|
||||
- `应用运行模式架构规范.md` — `AppMode` 三态边界、`preview` 与 `runtime` 的同源异构差异。
|
||||
- `实体生命周期引擎实现规范.md` — `Interaction.event` 命名表(`onLaunch / onLoad / onEnter / onLeave / onChange / onSuccess / onError / onSettled / onMount / onUnmount` 等)以及谁挂载哪些事件。
|
||||
- `设计器静态依赖分析方案.md` — `DynamicExpression` 的 AST 解析、依赖图谱、变量重命名级联策略。
|
||||
- `设计器悬浮组件架构规范.md` — Modal/Drawer 不享受 Schema 特权;`isOverlay` 是 Component Registry 元数据,不进 Schema。
|
||||
- `设计器选中与分组交互规范.md` — `selectedIds` / `activeContainerId` 仅在设计态运行时 Store。
|
||||
|
||||
- 数据请求的发起、成功、失败与错误信息;
|
||||
- 过滤器接收的输入参数是否正确,以及过滤结果是否异常;
|
||||
- 事件流的触发顺序、条件命中情况、动作执行过程与中断原因;
|
||||
- 表达式求值、生命周期触发、关键动作执行等运行日志;
|
||||
- 将错误、警告与日志尽可能关联到具体的组件、事件、过滤器、数据源或动作节点。
|
||||
## 常见误区
|
||||
|
||||
因此,`预览态` 需要被纳入平台整体架构设计中,但其影响应主要体现在运行时上下文、引擎挂载策略、错误处理策略以及内部 `Store` 的组织方式上,而不应膨胀为一套独立的 `Schema` 结构维度。
|
||||
|
||||
`Schema` 仍只负责承载跨模式稳定且需要被持久化的应用配置,而模式切换过程中产生的会话状态、派生状态、调试状态、缓存状态与临时控制状态,应由运行时 `Store` 负责管理。
|
||||
|
||||
在完成核心 `Schema` 结构设计的里程碑阶段后,项目下一阶段的重点将转向整个平台的技术路线与实现方案设计。
|
||||
|
||||
这意味着,后续工作不再仅仅聚焦于“应用配置如何被描述”,而是要进一步回答:平台应如何基于既定 `Schema` 组织内部状态 `Store`、构建运行时上下文、拆分核心模块,并驱动各个引擎协同工作。
|
||||
|
||||
其中,一个关键目标是逐步明确并落地平台的五大核心引擎,包括:
|
||||
|
||||
- 工作区引擎
|
||||
- 画布引擎
|
||||
- 渲染引擎
|
||||
- 数据引擎
|
||||
- 交互引擎
|
||||
|
||||
现阶段的实现目标,是在既定 `Schema` 蓝图的基础上,进一步规划整个平台的技术架构、状态模型与引擎协作机制,为后续设计器与运行时系统的工程化实现提供稳定依据。
|
||||
|
||||
在技术栈方面,本项目希望积极拥抱 `React` + `Vite` 的最新生态体系,包括但不限于 `React`、`React Router` 或 `Tanstack Router`、`Tanstack Query`、`Zustand` 等。
|
||||
|
||||
## 项目规则
|
||||
|
||||
### 协作规则
|
||||
|
||||
1. 严禁直接修改项目代码,仅展示你的方案,由我来手动修改代码。
|
||||
- 不要在 `Page` 下新增 `modals: Component[]` 等"特权数组",悬浮组件统一走 `components` 树。
|
||||
- 不要把组件注册元数据(`isOverlay` / `isContainer` / `setters`)放进 Schema —— 那是物料库静态字典。
|
||||
- 不要把 `prefetch / polling / enabled` 等查询配置复制到 `Mutation`,`Mutation` 只能命令式触发。
|
||||
- 不要把 React 生命周期等价于业务生命周期 —— 全部走 `Interaction`,避免 Strict Mode 双调用陷阱。
|
||||
|
||||
@@ -28,7 +28,25 @@ export interface Component extends Entity {
|
||||
*/
|
||||
condition?: Condition;
|
||||
layout: ComponentLayout;
|
||||
/**
|
||||
* 组件通用样式
|
||||
*
|
||||
* 承载跨组件通用的、标准的 CSS 视觉属性,仅作用于组件的最外层 DOM 容器。
|
||||
* 必须为静态键值对,不支持动态表达式(DynamicExpression),以保证渲染性能并斩断“无意义的 React 渲染瀑布”。
|
||||
* 任何基于数据流或业务状态的动态视觉变化,应通过 props 或事件触发的 Action 来实现。
|
||||
*
|
||||
* @example { backgroundColor: '#fff', borderRadius: 4, boxShadow: '0 2px 4px rgba(0,0,0,0.1)' }
|
||||
*/
|
||||
style: CSSProperties;
|
||||
/**
|
||||
* 组件私有属性
|
||||
*
|
||||
* 承载与具体组件类型(type)强绑定的业务语义、内部结构和私有状态。
|
||||
* 支持动态表达式(DynamicExpression),允许属性值随数据流或环境变量动态变化。
|
||||
* 如果组件没有任何自定义属性,该值必须为空对象 `{}`,以消除空值检查成本。
|
||||
*
|
||||
* @example { text: '提交', disabled: false, size: 'large', type: 'primary' }
|
||||
*/
|
||||
props: Record<string, ComponentPropValue>;
|
||||
/**
|
||||
* 图层管理属性
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// TODO: 完善 CSSProperties 接口
|
||||
export interface CSSProperties {
|
||||
[key: string]: string;
|
||||
[key: string]: string | number | undefined;
|
||||
}
|
||||
|
||||
+4766
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user