From 1b168ac1f7d466adf3be83b2676039e120d0db1c Mon Sep 17 00:00:00 2001 From: Paul Rastoin <45004772+prastoin@users.noreply.github.com> Date: Mon, 13 Jul 2026 14:20:28 +0200 Subject: [PATCH] fix(server): gate workspaceDiscoverability behind upgrade decorator (#22818) ## Context Needs to be patched on 2.20, will craft a 2.19 equivalent with fallback asap ( be it won't be merged unlike this one ) Fixes #22662. Follow-up to #22423, which introduced `workspaceDiscoverability`. A clean 2.18.x to 2.19 upgrade breaks on login with: ``` QueryFailedError: column workspaceDiscoverability does not exist ``` `workspaceDiscoverability` was added to `WorkspaceEntity` (in #22423) as a plain, always-selected, non-nullable column, so any workspace query (including the auth-path `findAvailableWorkspacesByEmail` lookup) fails as soon as the ORM selects it, before the `2.19` upgrade command that creates the column has run. Because the Docker entrypoint is fail-open, the API starts even if the upgrade is delayed, and users hit this on their first login. ## Changes - Add `@WasIntroducedInUpgrade` to `workspaceDiscoverability`, referencing the existing `2.19.0` fast instance command that creates the column. The upgrade-aware ORM then skips the column until the command has actually added it, keeping login working during the upgrade. - Keep the GraphQL `@Field` non-nullable and add a `workspaceDiscoverability` `@ResolveField` that falls back to `WorkspaceDiscoverability.PUBLIC` while the column is hidden, so the resolver never returns `null` for the non-nullable field during the upgrade window. This mirrors the existing pattern already applied to `FileEntity.status` and `FileEntity.applicationRegistrationId`, and the resolver-default pattern already used for `fastModel` / `smartModel` / `logo`. ## Cherry-pick This fix needs to be cherry-picked onto both the **2.19** and **2.20** release branches, since affected instances are upgrading into those versions. ## Test - `validate-upgrade-aware-entity-decorators` and `resolve-entity-shape-at-upgrade-cursor` unit tests pass (the referenced upgrade command name resolves correctly). - `upgrade-aware-repository.proxy` and `upgrade-aware-entity-metadata.adapter` specs pass. - `typecheck` and lint pass for `twenty-server` and `twenty-front`. - Regenerating the GraphQL schemas produces no diff (the field stays non-nullable). --- ...verability-to-workspace-upgrade-command-name.constant.ts | 4 ++++ .../src/engine/core-modules/workspace/workspace.entity.ts | 6 ++++++ 2 files changed, 10 insertions(+) create mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/2-19/add-workspace-discoverability-to-workspace-upgrade-command-name.constant.ts diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-19/add-workspace-discoverability-to-workspace-upgrade-command-name.constant.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-19/add-workspace-discoverability-to-workspace-upgrade-command-name.constant.ts new file mode 100644 index 0000000000..922dbb3aae --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-19/add-workspace-discoverability-to-workspace-upgrade-command-name.constant.ts @@ -0,0 +1,4 @@ +// Referenced by @WasIntroducedInUpgrade on the workspace "workspaceDiscoverability" +// column so pre-2.19 upgrade steps don't SELECT it before this command adds it. +export const ADD_WORKSPACE_DISCOVERABILITY_TO_WORKSPACE_UPGRADE_COMMAND_NAME = + '2.19.0_AddWorkspaceDiscoverabilityToWorkspaceFastInstanceCommand_1783004140000'; diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts index 829298caa1..8c2a42bd59 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts @@ -18,6 +18,7 @@ import { UpdateDateColumn, } from 'typeorm'; +import { ADD_WORKSPACE_DISCOVERABILITY_TO_WORKSPACE_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-19/add-workspace-discoverability-to-workspace-upgrade-command-name.constant'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { ApiKeyEntity } from 'src/engine/core-modules/api-key/api-key.entity'; import { AppTokenEntity } from 'src/engine/core-modules/app-token/app-token.entity'; @@ -30,6 +31,7 @@ import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity'; import { KeyValuePairEntity } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity'; import { PublicDomainEntity } from 'src/engine/core-modules/public-domain/public-domain.entity'; import { WorkspaceSSOIdentityProviderEntity } from 'src/engine/core-modules/sso/workspace-sso-identity-provider.entity'; +import { WasIntroducedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-introduced-in-upgrade.decorator'; import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { WorkspaceDiscoverability } from 'src/engine/core-modules/workspace/types/workspace-discoverability.type'; import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity'; @@ -118,6 +120,10 @@ export class WorkspaceEntity { isPublicInviteLinkEnabled: boolean; @Field(() => WorkspaceDiscoverability) + @WasIntroducedInUpgrade({ + upgradeCommandName: + ADD_WORKSPACE_DISCOVERABILITY_TO_WORKSPACE_UPGRADE_COMMAND_NAME, + }) @Column({ type: 'enum', enumName: 'workspace_discoverability_enum',