From 860d540773bcf0e106ba2b46e1c13106a8a99ad0 Mon Sep 17 00:00:00 2001 From: Sonarly Claude Code Date: Sun, 22 Mar 2026 12:47:12 +0000 Subject: [PATCH] fix: use workspace custom application for logo upload during onboarding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://sonarly.com/issue/17298?type=bug Uploading a workspace logo on the initial workspace creation page fails because the upload code requires the Twenty Standard Application, which is only created during workspace activation (after clicking "Continue"). Fix: Added `findWorkspaceCustomFlatApplicationOrThrow` to `ApplicationService` — a method that looks up only the workspace's custom application from the cache, without requiring the Twenty Standard Application to exist. This is safe because the custom application is created during sign-up (`sign-in-up.service.ts`), so it exists for workspaces in any activation state including `PENDING_CREATION`. Changed all three call sites in `FileCorePictureService` (`uploadCorePicture`, `deleteCorePicture`, `copyWorkspaceMemberProfilePicture`) to use the new method instead of `findWorkspaceTwentyStandardAndCustomApplicationOrThrow`. All three only use `workspaceCustomFlatApplication.universalIdentifier` — they never needed the Twenty Standard Application lookup that was causing the failure during onboarding. This allows users to upload a workspace logo on the initial setup page before workspace activation, fixing the reported bug. --- .../application/application.service.ts | 35 +++++++++++++++++++ .../services/file-core-picture.service.ts | 18 ++++------ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/packages/twenty-server/src/engine/core-modules/application/application.service.ts b/packages/twenty-server/src/engine/core-modules/application/application.service.ts index 7c63d32bf1e..3aa15129905 100644 --- a/packages/twenty-server/src/engine/core-modules/application/application.service.ts +++ b/packages/twenty-server/src/engine/core-modules/application/application.service.ts @@ -48,6 +48,41 @@ export class ApplicationService { return application.defaultRoleId; } + async findWorkspaceCustomFlatApplicationOrThrow({ + workspaceId, + }: { + workspaceId: string; + }) { + const workspace = await this.workspaceRepository.findOne({ + where: { id: workspaceId }, + withDeleted: true, + }); + + if (!isDefined(workspace)) { + throw new ApplicationException( + `Could not find workspace ${workspaceId}`, + ApplicationExceptionCode.APPLICATION_NOT_FOUND, + ); + } + + const { flatApplicationMaps } = + await this.workspaceCacheService.getOrRecompute(workspace.id, [ + 'flatApplicationMaps', + ]); + + const workspaceCustomFlatApplication = + flatApplicationMaps.byId[workspace.workspaceCustomApplicationId]; + + if (!isDefined(workspaceCustomFlatApplication)) { + throw new ApplicationException( + `Could not find workspace custom application for workspace ${workspaceId}`, + ApplicationExceptionCode.APPLICATION_NOT_FOUND, + ); + } + + return { workspaceCustomFlatApplication }; + } + async findWorkspaceTwentyStandardAndCustomApplicationOrThrow({ workspace: workspaceInput, workspaceId, diff --git a/packages/twenty-server/src/engine/core-modules/file/file-core-picture/services/file-core-picture.service.ts b/packages/twenty-server/src/engine/core-modules/file/file-core-picture/services/file-core-picture.service.ts index 808076ab826..722b0d1f7e0 100644 --- a/packages/twenty-server/src/engine/core-modules/file/file-core-picture/services/file-core-picture.service.ts +++ b/packages/twenty-server/src/engine/core-modules/file/file-core-picture/services/file-core-picture.service.ts @@ -60,7 +60,7 @@ export class FileCorePictureService { const universalIdentifier = applicationUniversalIdentifier ?? ( - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + await this.applicationService.findWorkspaceCustomFlatApplicationOrThrow( { workspaceId }, ) ).workspaceCustomFlatApplication.universalIdentifier; @@ -170,11 +170,9 @@ export class FileCorePictureService { }); const { workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { - workspaceId, - }, - ); + await this.applicationService.findWorkspaceCustomFlatApplicationOrThrow({ + workspaceId, + }); await this.fileStorageService.delete({ workspaceId, @@ -287,11 +285,9 @@ export class FileCorePictureService { }); const { workspaceCustomFlatApplication: sourceApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { - workspaceId: sourceWorkspaceId, - }, - ); + await this.applicationService.findWorkspaceCustomFlatApplicationOrThrow({ + workspaceId: sourceWorkspaceId, + }); const fileStream = await this.fileStorageService.readFile({ workspaceId: sourceWorkspaceId,