feat(workflow): add core workflow entity (syncable) + create-table (#22746)

## Core `workflow` entity (syncable)

Part of the app-workflows work. Adds a core `WorkflowEntity extends
SyncableEntity` (`name`, `lastPublishedVersionId`, plus
`universalIdentifier`/`applicationId`/workspace from the base class) and
its 2.20 create-table fast command, gated with
`@WasIntroducedInUpgrade`.

Schema was captured and verified via `migrate:generate` (zero drift,
FK/index hashes correct), then run against a live DB.

Backfill (populate from workspace `workflow` records) and the dual-write
listener land in follow-ups.

Independent of the version-syncable-columns PR, but note: both add 2.20
upgrade commands, so this one (ts `…479`) must merge **before** the
version PR (ts `…480`) to satisfy the append-only guard.


<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22746?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
Thomas Trompette
2026-07-09 18:30:45 +02:00
committed by GitHub
parent 9c405384f3
commit 6210389221
4 changed files with 82 additions and 0 deletions
@@ -0,0 +1,43 @@
import { QueryRunner } from 'typeorm';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface';
@RegisteredInstanceCommand('2.20.0', 1783603454479)
export class CreateWorkflowCoreTableFastInstanceCommand
implements FastInstanceCommand
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE IF NOT EXISTS "core"."workflow" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"name" text,
"lastPublishedVersionId" uuid,
"universalIdentifier" uuid NOT NULL,
"applicationId" uuid NOT NULL,
"workspaceId" uuid NOT NULL,
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
"updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
CONSTRAINT "PK_eb5e4cc1a9ef2e94805b676751b" PRIMARY KEY ("id"),
CONSTRAINT "FK_fbce9a986a577698821a7e301b6" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE,
CONSTRAINT "FK_6819d862ed54fbf00cecaa0da4b" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE
)`,
);
await queryRunner.query(
`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_8ef15993c0e4bb37d1ceb9b87d"
ON "core"."workflow" ("workspaceId", "universalIdentifier")`,
);
await queryRunner.query(
`CREATE INDEX IF NOT EXISTS "IDX_WORKFLOW_WORKSPACE_ID"
ON "core"."workflow" ("workspaceId")`,
);
await queryRunner.query(
`CREATE INDEX IF NOT EXISTS "IDX_WORKFLOW_APPLICATION_ID"
ON "core"."workflow" ("applicationId")`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE IF EXISTS "core"."workflow"`);
}
}
@@ -0,0 +1,2 @@
export const CREATE_WORKFLOW_CORE_TABLE_UPGRADE_COMMAND_NAME =
'2.20.0_CreateWorkflowCoreTableFastInstanceCommand_1783603454479';
@@ -104,6 +104,7 @@ import { CreateWorkflowVersionCoreTableFastInstanceCommand } from './2-20/2-20-i
import { BackfillNameFieldIsSystemSideEffectSlowInstanceCommand } from './2-20/2-20-instance-command-slow-1783529458168-backfill-name-field-is-system-side-effect';
import { RenameIsFeaturedToIsVettedOnApplicationRegistrationFastInstanceCommand } from './2-20/2-20-instance-command-fast-1783527064000-rename-is-featured-to-is-vetted-on-application-registration';
import { AddIsSystemSideEffectToSearchFieldMetadataFastInstanceCommand } from './2-20/2-20-instance-command-fast-1783580127637-add-is-system-side-effect-to-search-field-metadata';
import { CreateWorkflowCoreTableFastInstanceCommand } from './2-20/2-20-instance-command-fast-1783603454479-create-workflow-core-table';
export const INSTANCE_COMMANDS = [
AddViewFieldGroupIdIndexOnViewFieldFastInstanceCommand,
@@ -210,4 +211,5 @@ export const INSTANCE_COMMANDS = [
BackfillNameFieldIsSystemSideEffectSlowInstanceCommand,
RenameIsFeaturedToIsVettedOnApplicationRegistrationFastInstanceCommand,
AddIsSystemSideEffectToSearchFieldMetadataFastInstanceCommand,
CreateWorkflowCoreTableFastInstanceCommand,
];
@@ -0,0 +1,35 @@
import {
Column,
CreateDateColumn,
Entity,
Index,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import { CREATE_WORKFLOW_CORE_TABLE_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-20/create-workflow-core-table-upgrade-command-name.constant';
import { WasIntroducedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-introduced-in-upgrade.decorator';
import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';
@Entity({ name: 'workflow', schema: 'core' })
@WasIntroducedInUpgrade({
upgradeCommandName: CREATE_WORKFLOW_CORE_TABLE_UPGRADE_COMMAND_NAME,
})
@Index('IDX_WORKFLOW_WORKSPACE_ID', ['workspaceId'])
@Index('IDX_WORKFLOW_APPLICATION_ID', ['applicationId'])
export class WorkflowEntity extends SyncableEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ type: 'text', nullable: true })
name: string | null;
@Column({ type: 'uuid', nullable: true })
lastPublishedVersionId: string | null;
@CreateDateColumn({ type: 'timestamptz' })
createdAt: Date;
@UpdateDateColumn({ type: 'timestamptz' })
updatedAt: Date;
}