mcpField
S
syncable-entity-types-and-constants

syncable-entity-types-and-constants

github.com/twentyhq開発60.0k54 回インストール今日更新
リポジトリ

syncable-entity-types-and-constants について

Twenty に同期可能なエンティティを追加するための開発スキルです。型、エンティティ、中央登録を定義し、後続のキャッシュや移行、統合の基礎を作ります。

主な機能

  1. 01メタデータ名の登録
  2. 02TypeORM エンティティの定義
  3. 03フラットエンティティとアクション型
  4. 04編集可能プロパティの設定
  5. 05リレーション定数の登録

活用シーン

  1. 01同期可能なエンティティ実装の開始
  2. 02エンティティのプロパティとリレーションの設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/twentyhq/twenty --skill syncable-entity-types-and-constants

インストール後、Claude Code で/syncable-entity-types-and-constantsを入力して読み込まれたか確認します。

詳細

同期可能エンティティ: 型と定数 (ステップ 1/6)

目的: すべての型、エンティティを定義し、中央の定数に登録します。これは基盤であり、他のすべてはこれらの型が正しいことに依存します。

使用するタイミング: 新しい同期可能エンティティを作成する際の最初のステップです。他のステップより前に完了させる必要があります。


クイックスタート

このステップでは以下を作成します:

  1. メタデータ名の定数 (twenty-shared)
  2. TypeORM エンティティ (SyncableEntity を継承)
  3. フラットエンティティ型
  4. アクション型 (ユニバーサル + フラット)
  5. 中央の定数への登録 (5 つの定数)

ステップ 1: メタデータ名を追加する

ファイル: packages/twenty-shared/src/metadata/all-metadata-name.constant.ts

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

ステップ 2: TypeORM エンティティを作成する

ファイル: 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;
}

重要なルール:

  • SyncableEntity を継承する必要があります (id、universalIdentifier、applicationId などを提供します)
  • isCustom ブール型カラムを持つ必要があります
  • JSON データには @Column({ type: 'jsonb' }) を使用します

ステップ 3: フラットエンティティ型を定義する

ファイル: 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>;

マップファイル (エンティティにインデックス付きルックアップがある場合):

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

ステップ 4: 編集可能なプロパティを定義する

ファイル: 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>;

ルール: 更新可能なプロパティのみを含めます (id、createdAt、universalIdentifier などは除外します)


ステップ 5: アクション型を定義する

ファイル: 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;
};

ステップ 6: 中央の定数に登録する

6a. AllFlatEntityTypesByMetadataName

ファイル: src/engine/metadata-modules/flat-entity/types/all-flat-entity-types-by-metadata-name.type.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

ファイル: 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;

ルール:

  • toCompare: true → 編集可能なプロパティ (変更がチェックされます)
  • toStringify: true → JSONB/オブジェクトプロパティ (JSON シリアライズが必要です)
  • universalProperty → ユニバーサル版にマッピングされます (外部キーおよび SerializedRelation を持つ JSONB 用)
6c. ALL_ONE_TO_MANY_METADATA_RELATIONS

ファイル: src/engine/metadata-modules/flat-entity/constant/all-one-to-many-metadata-relations.constant.ts

この定数は型チェックされます — metadataName、flatEntityForeignKeyAggregator、universalFlatEntityForeignKeyAggregator の値はエンティティ型定義から導出されます。アグリゲーター名は次のパターンに従います: リレーションプロパティ名から末尾の 's' を削除し、Ids または 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

ファイル: src/engine/metadata-modules/flat-entity/constant/all-many-to-one-metadata-foreign-key.constant.ts

低レベルのプリミティブ定数です。外部キーを格納する Id で終わるカラム名である foreignKey のみを含みます。エンティティのプロパティに対して型チェックされます。

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

ファイル: src/engine/metadata-modules/flat-entity/constant/all-many-to-one-metadata-relations.constant.ts

ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY(foreignKey 型および universalForeignKey の導出用)と ALL_ONE_TO_MANY_METADATA_RELATIONS(inverseOneToManyProperty キー制約用)の両方から導出されます。これはユーティリティと楽観的ツール群が利用する主要な定数です。

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;

導出の依存関係グラフ:

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)

ルール:

  • workspace: null、application: null — 常に存在し、常に null(同期対象外のリレーション)
  • inverseOneToManyProperty — ALL_ONE_TO_MANY_METADATA_RELATIONS[targetMetadataName] のキーである必要があります。対象エンティティが逆方向の one-to-many リレーションを公開していない場合は null
  • universalForeignKey — foreignKey から Id サフィックスを UniversalIdentifier に置き換えて導出されます
  • 楽観的ユーティリティは、実行時に ALL_ONE_TO_MANY_METADATA_RELATIONS で inverseOneToManyProperty を参照して flatEntityForeignKeyAggregator / universalFlatEntityForeignKeyAggregator を解決します

チェックリスト

ステップ 2 に進む前に:

  • ALL_METADATA_NAME にメタデータ名を追加した
  • TypeORM エンティティを作成した(SyncableEntity を継承)
  • isCustom カラムを追加した
  • フラットエンティティ型を定義した
  • フラットエンティティマップ型を定義した(必要な場合)
  • 編集可能プロパティの定数を定義した
  • ユニバーサルおよびフラットなアクション型を定義した
  • AllFlatEntityTypesByMetadataName に登録した
  • ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME に登録した
  • ALL_ONE_TO_MANY_METADATA_RELATIONS に登録した(エンティティが one-to-many リレーションを持つ場合)
  • ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY に登録した
  • ALL_MANY_TO_ONE_METADATA_RELATIONS に登録した
  • TypeScript がエラーなくコンパイルされる

次のステップ

すべての型と定数を定義したら、次に進みます: Syncable Entity: キャッシュと変換(ステップ 2/6)

完全なワークフローについては、@creating-syncable-entity ルールを参照してください。

コメント