feat(workflow): add universalIdentifier + applicationId to core workflowVersion (#22747)

## workflowVersion core: syncable columns

Adds `universalIdentifier` + `applicationId` (nullable) to
`core.workflowVersion`, plus the FK to `core.application` and the
`(workspaceId, universalIdentifier)` unique index, via a 2.20
add-columns fast command gated with `@WasIntroducedInUpgrade`.

Nullable for now: the already-merged Phase A backfill (#22663) inserts
version rows without these columns, so `applicationId` can't be NOT NULL
yet. Flipping to NOT NULL + `extends SyncableEntity` comes once they're
populated (backfill + dual-write follow-ups).

Schema captured and verified via `migrate:generate` (zero drift).

Independent of the core-workflow PR, but both add 2.20 upgrade commands,
so this one (ts `…480`) must merge **after** the core-workflow PR (ts
`…479`), or it gets re-timestamped on rebase.


<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22747?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-10 10:26:52 +02:00
committed by GitHub
parent 0786f9e793
commit b327ab09a7
6 changed files with 85 additions and 4 deletions
@@ -0,0 +1,49 @@
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', 1783603454480)
export class AddWorkflowVersionSyncableColumnsFastInstanceCommand
implements FastInstanceCommand
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."workflowVersion" ADD COLUMN IF NOT EXISTS "universalIdentifier" uuid NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "core"."workflowVersion" ADD COLUMN IF NOT EXISTS "applicationId" uuid NOT NULL`,
);
await queryRunner.query(
`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_c67a90cc29887078286205457e"
ON "core"."workflowVersion" ("workspaceId", "universalIdentifier")`,
);
await queryRunner.query(
`DO $$ BEGIN
ALTER TABLE "core"."workflowVersion" ADD CONSTRAINT "FK_29f62766c5b109981244b97060d" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE;
EXCEPTION WHEN duplicate_object THEN null; END $$`,
);
await queryRunner.query(
`CREATE INDEX IF NOT EXISTS "IDX_WORKFLOW_VERSION_APPLICATION_ID"
ON "core"."workflowVersion" ("applicationId")`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."workflowVersion" DROP CONSTRAINT IF EXISTS "FK_29f62766c5b109981244b97060d"`,
);
await queryRunner.query(
`DROP INDEX IF EXISTS "core"."IDX_c67a90cc29887078286205457e"`,
);
await queryRunner.query(
`DROP INDEX IF EXISTS "core"."IDX_WORKFLOW_VERSION_APPLICATION_ID"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workflowVersion" DROP COLUMN IF EXISTS "applicationId"`,
);
await queryRunner.query(
`ALTER TABLE "core"."workflowVersion" DROP COLUMN IF EXISTS "universalIdentifier"`,
);
}
}
@@ -0,0 +1,2 @@
export const ADD_WORKFLOW_VERSION_SYNCABLE_COLUMNS_UPGRADE_COMMAND_NAME =
'2.20.0_AddWorkflowVersionSyncableColumnsFastInstanceCommand_1783603454480';
@@ -105,6 +105,7 @@ import { BackfillNameFieldIsSystemSideEffectSlowInstanceCommand } from './2-20/2
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';
import { AddWorkflowVersionSyncableColumnsFastInstanceCommand } from './2-20/2-20-instance-command-fast-1783603454480-add-workflow-version-syncable-columns';
export const INSTANCE_COMMANDS = [
AddViewFieldGroupIdIndexOnViewFieldFastInstanceCommand,
@@ -212,4 +213,5 @@ export const INSTANCE_COMMANDS = [
RenameIsFeaturedToIsVettedOnApplicationRegistrationFastInstanceCommand,
AddIsSystemSideEffectToSearchFieldMetadataFastInstanceCommand,
CreateWorkflowCoreTableFastInstanceCommand,
AddWorkflowVersionSyncableColumnsFastInstanceCommand,
];