syncable-entity-types-and-constants

Syncable Entity: Types & Constants (Step 1/6)

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "syncable-entity-types-and-constants" with this command: npx skills add twentyhq/twenty/twentyhq-twenty-syncable-entity-types-and-constants

Syncable Entity: Types & Constants (Step 1/6)

Purpose: Define all types, entities, and register in central constants. This is the foundation - everything else depends on these types being correct.

When to use: First step when creating any new syncable entity. Must be completed before other steps.

Quick Start

This step creates:

  • Metadata name constant (twenty-shared)

  • TypeORM entity (extends SyncableEntity )

  • Flat entity types

  • Action types (universal + flat)

  • Central constant registrations (5 constants)

Step 1: Add Metadata Name

File: packages/twenty-shared/src/metadata/all-metadata-name.constant.ts

export const ALL_METADATA_NAME = { // ... existing entries myEntity: 'myEntity', } as const;

Step 2: Create TypeORM Entity

File: src/engine/metadata-modules/my-entity/entities/my-entity.entity.ts

import { Entity, Column, ManyToOne, JoinColumn } from 'typeorm'; import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';

@Entity({ name: 'myEntity' }) export class MyEntityEntity extends SyncableEntity { @Column({ type: 'varchar' }) name: string;

@Column({ type: 'varchar' }) label: string;

@Column({ type: 'boolean', default: true }) isCustom: boolean;

// Foreign key example (optional) @Column({ type: 'uuid', nullable: true }) parentEntityId: string | null;

@ManyToOne(() => ParentEntityEntity, { nullable: true }) @JoinColumn({ name: 'parentEntityId' }) parentEntity: ParentEntityEntity | null;

// JSONB column example (optional) @Column({ type: 'jsonb', nullable: true }) settings: Record<string, any> | null; }

Key rules:

  • Must extend SyncableEntity (provides id , universalIdentifier , applicationId , etc.)

  • Must have isCustom boolean column

  • Use @Column({ type: 'jsonb' }) for JSON data

Step 3: Define Flat Entity Types

File: src/engine/metadata-modules/flat-my-entity/types/flat-my-entity.type.ts

import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type'; import { type MyEntityEntity } from 'src/engine/metadata-modules/my-entity/entities/my-entity.entity';

export type FlatMyEntity = FlatEntityFrom<MyEntityEntity>;

Maps file (if entity has indexed lookups):

// flat-my-entity-maps.type.ts export type FlatMyEntityMaps = { byId: Record<string, FlatMyEntity>; byName: Record<string, FlatMyEntity>; // Add other indexes as needed };

Step 4: Define Editable Properties

File: src/engine/metadata-modules/flat-my-entity/constants/editable-flat-my-entity-properties.constant.ts

export const EDITABLE_FLAT_MY_ENTITY_PROPERTIES = [ 'name', 'label', 'description', 'parentEntityId', 'settings', ] as const satisfies ReadonlyArray<keyof FlatMyEntity>;

Rule: Only include properties that can be updated (exclude id , createdAt , universalIdentifier , etc.)

Step 5: Define Action Types

File: src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/my-entity/types/workspace-migration-my-entity-action.type.ts

import { type FlatMyEntity } from 'src/engine/metadata-modules/flat-my-entity/types/flat-my-entity.type'; import { type UniversalFlatMyEntity } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-my-entity.type';

// Universal actions (used by builder/runner) export type UniversalCreateMyEntityAction = { type: 'create'; metadataName: 'myEntity'; universalFlatEntity: UniversalFlatMyEntity; };

export type UniversalUpdateMyEntityAction = { type: 'update'; metadataName: 'myEntity'; universalFlatEntity: UniversalFlatMyEntity; universalUpdates: Partial<UniversalFlatMyEntity>; };

export type UniversalDeleteMyEntityAction = { type: 'delete'; metadataName: 'myEntity'; universalFlatEntity: UniversalFlatMyEntity; };

// Flat actions (internal to runner) export type FlatCreateMyEntityAction = { type: 'create'; metadataName: 'myEntity'; flatEntity: FlatMyEntity; };

export type FlatUpdateMyEntityAction = { type: 'update'; metadataName: 'myEntity'; flatEntity: FlatMyEntity; updates: Partial<FlatMyEntity>; };

export type FlatDeleteMyEntityAction = { type: 'delete'; metadataName: 'myEntity'; flatEntity: FlatMyEntity; };

Step 6: Register in Central Constants

6a. AllFlatEntityTypesByMetadataName

File: src/engine/metadata-modules/flat-entity/types/all-flat-entity-types-by-metadata-name.ts

export type AllFlatEntityTypesByMetadataName = { // ... existing entries myEntity: { flatEntityMaps: FlatMyEntityMaps; universalActions: { create: UniversalCreateMyEntityAction; update: UniversalUpdateMyEntityAction; delete: UniversalDeleteMyEntityAction; }; flatActions: { create: FlatCreateMyEntityAction; update: FlatUpdateMyEntityAction; delete: FlatDeleteMyEntityAction; }; flatEntity: FlatMyEntity; universalFlatEntity: UniversalFlatMyEntity; entity: MyEntityEntity; }; };

6b. ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME

File: src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant.ts

export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = { // ... existing entries myEntity: { name: { toCompare: true }, label: { toCompare: true }, description: { toCompare: true }, parentEntityId: { toCompare: true, universalProperty: 'parentEntityUniversalIdentifier', }, settings: { toCompare: true, toStringify: true, universalProperty: 'universalSettings', }, }, } as const;

Rules:

  • toCompare: true → Editable property (checked for changes)

  • toStringify: true → JSONB/object property (needs JSON serialization)

  • universalProperty → Maps to universal version (for foreign keys & JSONB with SerializedRelation )

6c. ALL_ONE_TO_MANY_METADATA_RELATIONS

File: src/engine/metadata-modules/flat-entity/constant/all-one-to-many-metadata-relations.constant.ts

This constant is type-checked — values for metadataName , flatEntityForeignKeyAggregator , and universalFlatEntityForeignKeyAggregator are derived from entity type definitions. The aggregator names follow the pattern: remove trailing 's' from the relation property name, then append Ids or UniversalIdentifiers .

export const ALL_ONE_TO_MANY_METADATA_RELATIONS = { // ... existing entries myEntity: { // If myEntity has a childEntities: ChildEntityEntity[] property: childEntities: { metadataName: 'childEntity', flatEntityForeignKeyAggregator: 'childEntityIds', universalFlatEntityForeignKeyAggregator: 'childEntityUniversalIdentifiers', }, // null for relations to non-syncable entities someNonSyncableRelation: null, }, } as const;

6d. ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY

File: src/engine/metadata-modules/flat-entity/constant/all-many-to-one-metadata-foreign-key.constant.ts

Low-level primitive constant. Only contains foreignKey — the column name ending in Id that stores the foreign key. Type-checked against entity properties.

export const ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY = { // ... existing entries myEntity: { workspace: null, application: null, parentEntity: { foreignKey: 'parentEntityId', }, }, } as const;

6e. ALL_MANY_TO_ONE_METADATA_RELATIONS

File: src/engine/metadata-modules/flat-entity/constant/all-many-to-one-metadata-relations.constant.ts

Derived from both ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY (for foreignKey type and universalForeignKey derivation) and ALL_ONE_TO_MANY_METADATA_RELATIONS (for inverseOneToManyProperty key constraint). This is the main constant consumed by utils and optimistic tooling.

export const ALL_MANY_TO_ONE_METADATA_RELATIONS = { // ... existing entries myEntity: { workspace: null, application: null, parentEntity: { metadataName: 'parentEntity', foreignKey: 'parentEntityId', inverseOneToManyProperty: 'myEntities', // key in ALL_ONE_TO_MANY_METADATA_RELATIONS['parentEntity'], or null if no inverse isNullable: false, universalForeignKey: 'parentEntityUniversalIdentifier', }, }, } as const;

Derivation dependency graph:

ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY ALL_ONE_TO_MANY_METADATA_RELATIONS (foreignKey only) (metadataName, aggregators) │ │ │ FK type + universalFK derivation │ inverseOneToManyProperty keys │ │ └────────────────┬───────────────────────┘ ▼ ALL_MANY_TO_ONE_METADATA_RELATIONS (metadataName, foreignKey, inverseOneToManyProperty, isNullable, universalForeignKey)

Rules:

  • workspace: null , application: null — always present, always null (non-syncable relations)

  • inverseOneToManyProperty — must be a key in ALL_ONE_TO_MANY_METADATA_RELATIONS[targetMetadataName] , or null if the target entity doesn't expose an inverse one-to-many relation

  • universalForeignKey — derived from foreignKey by replacing the Id suffix with UniversalIdentifier

  • Optimistic utils resolve flatEntityForeignKeyAggregator / universalFlatEntityForeignKeyAggregator at runtime by looking up inverseOneToManyProperty in ALL_ONE_TO_MANY_METADATA_RELATIONS

Checklist

Before moving to Step 2:

  • Metadata name added to ALL_METADATA_NAME

  • TypeORM entity created (extends SyncableEntity )

  • isCustom column added

  • Flat entity type defined

  • Flat entity maps type defined (if needed)

  • Editable properties constant defined

  • Universal and flat action types defined

  • Registered in AllFlatEntityTypesByMetadataName

  • Registered in ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME

  • Registered in ALL_ONE_TO_MANY_METADATA_RELATIONS (if entity has one-to-many relations)

  • Registered in ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY

  • Registered in ALL_MANY_TO_ONE_METADATA_RELATIONS

  • TypeScript compiles without errors

Next Step

Once all types and constants are defined, proceed to: Syncable Entity: Cache & Transform (Step 2/6)

For complete workflow, see @creating-syncable-entity rule.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

syncable-entity-cache-and-transform

No summary provided by upstream source.

Repository SourceNeeds Review
General

syncable-entity-testing

No summary provided by upstream source.

Repository SourceNeeds Review
General

syncable-entity-runner-and-actions

No summary provided by upstream source.

Repository SourceNeeds Review
General

syncable-entity-builder-and-validation

No summary provided by upstream source.

Repository SourceNeeds Review