用途
本文档是 Twenty 开源项目服务端内部开发规则的一部分,用于指导开发者参与 Twenty 代码库本身的贡献,具体场景是创建新的「可同步实体(Syncable Entity)」。文档明确说明其目标是对 twentyhq/twenty 服务端内部进行开发,而不是在 Twenty 之上构建应用。本步骤为六步流程中的第一步(Step 1/6),定位为整个流程的基础——所有后续步骤都依赖此处定义的类型正确无误。适用时机是:在创建任何新的可同步实体时,第一步就要完成本步骤,且必须在其他步骤之前完成。
主要能力(本步骤涵盖的内容)
文档说明本步骤需要创建以下内容:
- Metadata 名称常量(位于 twenty-shared)
- TypeORM 实体(继承 SyncableEntity)
- 扁平实体类型(Flat entity types)
- 动作类型(通用 universal + 扁平 flat)
- 中央常量注册(共 5 个常量)
Step 1:新增元数据名称
文件路径为 packages/twenty-shared/src/metadata/all-metadata-name.constant.ts,在 ALL_METADATA_NAME 中新增条目,示例为 myEntity: 'myEntity'。
Step 2:创建 TypeORM 实体
文件路径为 src/engine/metadata-modules/my-entity/entities/my-entity.entity.ts。文档给出的示例实体使用 @Entity({ name: 'myEntity' }) 装饰器,继承 SyncableEntity,包含 name、label、isCustom 等列,并演示了外键(@ManyToOne / @JoinColumn)与 JSONB 列(@Column({ type: 'jsonb' }))的写法。
关键规则包括:必须继承 SyncableEntity(提供 id、universalIdentifier、applicationId 等字段);必须有 isCustom 布尔列;JSON 数据使用 @Column({ type: 'jsonb' })。
Step 3:定义扁平实体类型
文件路径为 src/engine/metadata-modules/flat-my-entity/types/flat-my-entity.type.ts。通过 FlatEntityFrom<MyEntityEntity> 生成 FlatMyEntity 类型。若实体有索引查找,还需定义映射文件,例如 FlatMyEntityMaps,其中包含 byId、byName 等索引。
Step 4:定义可编辑属性
文件路径为 src/engine/metadata-modules/flat-my-entity/constants/editable-flat-my-entity-properties.constant.ts,定义 EDITABLE_FLAT_MY_ENTITY_PROPERTIES 常量数组。规则是只包含可以更新的属性,排除 id、createdAt、universalIdentifier 等。
Step 5:定义动作类型
文件路径为 src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/my-entity/types/workspace-migration-my-entity-action.type.ts。文档区分了两类动作:通用动作(Universal actions,供 builder/runner 使用,包含 create/update/delete)与扁平动作(Flat actions,runner 内部使用,同样包含 create/update/delete),并给出了各自的类型定义示例。
Step 6:在中央常量中注册
共需注册 5 个常量:
6a. AllFlatEntityTypesByMetadataName(文件 .../flat-entity/types/all-flat-entity-types-by-metadata-name.type.ts):注册 flatEntityMaps、universalActions、flatActions、flatEntity、universalFlatEntity、entity。
6b. ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME(文件 .../flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant.ts):为每个属性配置。规则说明:toCompare: true 表示可编辑属性(会检查变更);toStringify: true 表示 JSONB/对象属性(需要 JSON 序列化);universalProperty 映射到通用版本(用于外键及带 SerializedRelation 的 JSONB)。
6c. ALL_ONE_TO_MANY_METADATA_RELATIONS(文件 .../flat-entity/constant/all-one-to-many-metadata-relations.constant.ts):该常量有类型检查,metadataName、flatEntityForeignKeyAggregator、universalFlatEntityForeignKeyAggregator 的值由实体类型定义推导。聚合器命名规则为:移除关系属性名末尾的 's',再追加 Ids 或 UniversalIdentifiers。指向不可同步实体的关系填 null。
6d. ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY(文件 .../flat-entity/constant/all-many-to-one-metadata-foreign-key.constant.ts):底层原语常量,仅包含 foreignKey,即存储外键的、以 Id 结尾的列名,并针对实体属性做类型检查。其中 workspace: null、application: null。
6e. ALL_MANY_TO_ONE_METADATA_RELATIONS(文件 .../flat-entity/constant/all-many-to-one-metadata-relations.constant.ts):由前两个常量推导而来(foreignKey 类型与 universalForeignKey 推导来自 6d;inverseOneToManyProperty 键约束来自 6c)。这是工具与乐观工具链消费的主要常量。其规则为:workspace: null, application: null 始终存在且始终为 null(不可同步关系);inverseOneToManyProperty 必须是目标 metadataName 在 ALL_ONE_TO_MANY_METADATA_RELATIONS 中的键,若目标实体不暴露反向一对多关系则为 null;universalForeignKey 由 foreignKey 把 Id 后缀替换为 UniversalIdentifier 推导得到。文档还给出了推导依赖关系图,并说明乐观工具在运行时通过在 ALL_ONE_TO_MANY_METADATA_RELATIONS 中查找 inverseOneToManyProperty 来解析聚合器。
使用方式
文档以「Quick Start」与分步骤的形式给出操作说明,每步都指明目标文件路径、示例代码和关键规则。开发者需按 Step 1 至 Step 6 的顺序修改或新增对应文件,最后通过检查清单确认完成情况。
进入 Step 2 之前的检查清单包括:元数据名称已加入 ALL_METADATA_NAME;TypeORM 实体已创建(继承 SyncableEntity);isCustom 列已添加;扁平实体类型已定义;扁平实体映射类型已定义(如需要);可编辑属性常量已定义;通用与扁平动作类型已定义;已在 AllFlatEntityTypesByMetadataName 注册;已在 ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME 注册;已在 ALL_ONE_TO_MANY_METADATA_RELATIONS 注册(若实体有一对多关系);已在 ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY 注册;已在 ALL_MANY_TO_ONE_METADATA_RELATIONS 注册;TypeScript 编译无错误。
完成本步骤后,文档指向下一步:「Syncable Entity: Cache & Transform (Step 2/6)」,并提示完整工作流参见 @creating-syncable-entity 规则。
适用场景
适用于正在为 Twenty 服务端代码库贡献代码、需要新增可同步实体的开发者。前提是参与 Twenty 内部代码开发,而非基于 Twenty 构建应用。
限制
文档未说明该流程在 Twenty 之外的适用性、未提供收费或价格信息、未给出完整运行环境或依赖版本信息,相关内容暂未提供。所有代码与命令均有原文示例,实际使用应以代码库当前状态为准。