From d23511ea5e5af2987b3fff60c343b27e4f353443 Mon Sep 17 00:00:00 2001
From: Abdul Rahman <81605929+abdulrahmancodes@users.noreply.github.com>
Date: Fri, 10 Jul 2026 16:59:58 +0530
Subject: [PATCH] remove nestjs-query from user and workspace resolvers
(#22766)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## What
Migrates the `user` and `workspace` core modules off
`@ptc-org/nestjs-query`. Both used `NestjsQueryGraphQLModule` only as
scaffolding — all CRUD was disabled and the real GraphQL API is already
served by the hand-written `UserResolver` / `WorkspaceResolver`.
---------
Co-authored-by: Weiko
---
.../user/services/user.service.ts | 11 ++-
.../user/user.auto-resolver-opts.ts | 41 ----------
.../engine/core-modules/user/user.entity.ts | 3 +-
.../engine/core-modules/user/user.module.ts | 18 +----
.../workspace/services/workspace.service.ts | 7 +-
.../workspace/workspace.auto-resolver-opts.ts | 43 ----------
.../workspace/workspace.entity.ts | 3 +-
.../workspace/workspace.module.ts | 78 ++++++++-----------
.../workspace/workspace.resolver.ts | 2 +-
9 files changed, 45 insertions(+), 161 deletions(-)
delete mode 100644 packages/twenty-server/src/engine/core-modules/user/user.auto-resolver-opts.ts
delete mode 100644 packages/twenty-server/src/engine/core-modules/workspace/workspace.auto-resolver-opts.ts
diff --git a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts
index 69d2406d29..a111e102ea 100644
--- a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts
+++ b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts
@@ -3,7 +3,6 @@ import { InjectRepository } from '@nestjs/typeorm';
import assert from 'assert';
import { msg } from '@lingui/core/macro';
-import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
import { isNonEmptyString } from '@sniptt/guards';
import { SOURCE_LOCALE } from 'twenty-shared/translations';
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
@@ -52,7 +51,7 @@ import { STANDARD_ROLE } from 'src/engine/workspace-manager/twenty-standard-appl
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
// oxlint-disable-next-line twenty/inject-workspace-repository
-export class UserService extends TypeOrmQueryService {
+export class UserService {
constructor(
@InjectRepository(UserEntity)
private readonly userRepository: Repository,
@@ -70,9 +69,7 @@ export class UserService extends TypeOrmQueryService {
private readonly coreEntityCacheService: CoreEntityCacheService,
private readonly workspaceMemberTranspiler: WorkspaceMemberTranspiler,
private readonly twentyConfigService: TwentyConfigService,
- ) {
- super(userRepository);
- }
+ ) {}
async refreshWorkspaceIfPendingOrOngoingCreation<
TWorkspace extends Pick,
@@ -86,7 +83,9 @@ export class UserService extends TypeOrmQueryService {
return workspace;
}
- const freshWorkspace = await this.workspaceService.findById(workspace.id);
+ const freshWorkspace = await this.workspaceService.findOneWorkspaceById(
+ workspace.id,
+ );
return freshWorkspace ?? workspace;
}
diff --git a/packages/twenty-server/src/engine/core-modules/user/user.auto-resolver-opts.ts b/packages/twenty-server/src/engine/core-modules/user/user.auto-resolver-opts.ts
deleted file mode 100644
index 2542a7c328..0000000000
--- a/packages/twenty-server/src/engine/core-modules/user/user.auto-resolver-opts.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import {
- type AutoResolverOpts,
- PagingStrategies,
- type ReadResolverOpts,
-} from '@ptc-org/nestjs-query-graphql';
-
-import { UserEntity } from 'src/engine/core-modules/user/user.entity';
-import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
-
-export const userAutoResolverOpts: AutoResolverOpts<
- // oxlint-disable-next-line typescript/no-explicit-any
- any,
- // oxlint-disable-next-line typescript/no-explicit-any
- any,
- unknown,
- unknown,
- // oxlint-disable-next-line typescript/no-explicit-any
- ReadResolverOpts,
- PagingStrategies
->[] = [
- {
- EntityClass: UserEntity,
- DTOClass: UserEntity,
- enableTotalCount: true,
- pagingStrategy: PagingStrategies.CURSOR,
- read: {
- many: { disabled: true },
- one: { disabled: true },
- },
- create: {
- many: { disabled: true },
- one: { disabled: true },
- },
- update: {
- many: { disabled: true },
- one: { disabled: true },
- },
- delete: { many: { disabled: true }, one: { disabled: true } },
- guards: [WorkspaceAuthGuard],
- },
-];
diff --git a/packages/twenty-server/src/engine/core-modules/user/user.entity.ts b/packages/twenty-server/src/engine/core-modules/user/user.entity.ts
index 718ca98758..897fd2ac46 100644
--- a/packages/twenty-server/src/engine/core-modules/user/user.entity.ts
+++ b/packages/twenty-server/src/engine/core-modules/user/user.entity.ts
@@ -1,6 +1,5 @@
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
-import { IDField } from '@ptc-org/nestjs-query-graphql';
import { APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
import {
BeforeInsert,
@@ -36,7 +35,7 @@ registerEnumType(OnboardingStatus, {
where: '"deletedAt" IS NULL',
})
export class UserEntity {
- @IDField(() => UUIDScalarType)
+ @Field(() => UUIDScalarType)
@PrimaryGeneratedColumn('uuid')
id: string;
diff --git a/packages/twenty-server/src/engine/core-modules/user/user.module.ts b/packages/twenty-server/src/engine/core-modules/user/user.module.ts
index 08768da2a0..6961440b04 100644
--- a/packages/twenty-server/src/engine/core-modules/user/user.module.ts
+++ b/packages/twenty-server/src/engine/core-modules/user/user.module.ts
@@ -1,9 +1,6 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
-import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql';
-import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
-
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { CoreEntityCacheModule } from 'src/engine/core-entity-cache/core-entity-cache.module';
import { WorkspaceDomainsModule } from 'src/engine/core-modules/domain/workspace-domains/workspace-domains.module';
@@ -23,26 +20,17 @@ import { UserEntity } from 'src/engine/core-modules/user/user.entity';
import { UserResolver } from 'src/engine/core-modules/user/user.resolver';
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
import { ConnectedAccountMetadataModule } from 'src/engine/metadata-modules/connected-account/connected-account-metadata.module';
-import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
-import { userAutoResolverOpts } from './user.auto-resolver-opts';
-
import { UserService } from './services/user.service';
@Module({
imports: [
- NestjsQueryGraphQLModule.forFeature({
- imports: [
- NestjsQueryTypeOrmModule.forFeature([UserEntity]),
- TypeORMModule,
- FileModule,
- ],
- resolvers: userAutoResolverOpts,
- }),
- NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity]),
+ TypeOrmModule.forFeature([UserEntity]),
+ TypeORMModule,
+ FileModule,
WorkspaceModule,
OnboardingModule,
TypeOrmModule.forFeature([KeyValuePairEntity, UserWorkspaceEntity]),
diff --git a/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts b/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts
index 980154c48c..aa3f03aba4 100644
--- a/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts
+++ b/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts
@@ -4,7 +4,6 @@ import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import assert from 'assert';
import { msg } from '@lingui/core/macro';
-import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
import { PermissionFlagType } from 'twenty-shared/constants';
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
@@ -83,7 +82,7 @@ const WORKSPACE_ACTIVATION_STALE_LOCK_TIMEOUT_MS = 5 * 60 * 1000;
@Injectable()
// oxlint-disable-next-line twenty/inject-workspace-repository
-export class WorkspaceService extends TypeOrmQueryService {
+export class WorkspaceService {
protected readonly logger = new Logger(WorkspaceService.name);
private readonly WORKSPACE_FIELD_PERMISSIONS: Record<
@@ -149,9 +148,7 @@ export class WorkspaceService extends TypeOrmQueryService {
private readonly upgradeMigrationService: UpgradeMigrationService,
private readonly upgradeSequenceReaderService: UpgradeSequenceReaderService,
private readonly sdkClientGenerationService: SdkClientGenerationService,
- ) {
- super(workspaceRepository);
- }
+ ) {}
async updateWorkspaceById({
payload,
diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.auto-resolver-opts.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.auto-resolver-opts.ts
deleted file mode 100644
index 9b0bad2cac..0000000000
--- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.auto-resolver-opts.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import {
- type AutoResolverOpts,
- PagingStrategies,
- type ReadResolverOpts,
-} from '@ptc-org/nestjs-query-graphql';
-
-import { UpdateWorkspaceInput } from 'src/engine/core-modules/workspace/dtos/update-workspace-input';
-import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
-import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
-
-export const workspaceAutoResolverOpts: AutoResolverOpts<
- // oxlint-disable-next-line typescript/no-explicit-any
- any,
- // oxlint-disable-next-line typescript/no-explicit-any
- any,
- unknown,
- unknown,
- // oxlint-disable-next-line typescript/no-explicit-any
- ReadResolverOpts,
- PagingStrategies
->[] = [
- {
- EntityClass: WorkspaceEntity,
- DTOClass: WorkspaceEntity,
- UpdateDTOClass: UpdateWorkspaceInput,
- enableTotalCount: true,
- pagingStrategy: PagingStrategies.CURSOR,
- read: {
- many: { disabled: true },
- one: { disabled: true },
- },
- create: {
- many: { disabled: true },
- one: { disabled: true },
- },
- update: {
- one: { disabled: true },
- many: { disabled: true },
- },
- delete: { many: { disabled: true }, one: { disabled: true } },
- guards: [WorkspaceAuthGuard],
- },
-];
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 4093c2041c..829298caa1 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
@@ -1,6 +1,5 @@
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
-import { IDField } from '@ptc-org/nestjs-query-graphql';
import { type Application } from 'cloudflare/resources/zero-trust/access/applications/applications';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import {
@@ -70,7 +69,7 @@ registerEnumType(WorkspaceDiscoverability, {
@ObjectType('Workspace')
export class WorkspaceEntity {
// Fields
- @IDField(() => UUIDScalarType)
+ @Field(() => UUIDScalarType)
@PrimaryGeneratedColumn('uuid')
id: string;
diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.module.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.module.ts
index b06ddfb685..b8365fc978 100644
--- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.module.ts
+++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.module.ts
@@ -1,9 +1,6 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
-import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql';
-import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
-
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
import { PreInstalledAppsModule } from 'src/engine/core-modules/application/pre-installed-apps/pre-installed-apps.module';
@@ -19,7 +16,6 @@ import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-
import { FileModule } from 'src/engine/core-modules/file/file.module';
import { MetricsModule } from 'src/engine/core-modules/metrics/metrics.module';
import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module';
-import { PublicDomainEntity } from 'src/engine/core-modules/public-domain/public-domain.entity';
import { SdkClientModule } from 'src/engine/core-modules/sdk-client/sdk-client.module';
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
@@ -31,7 +27,6 @@ import { CoreEntityCacheModule } from 'src/engine/core-entity-cache/core-entity-
import { WorkspaceEntityCacheProviderService } from 'src/engine/core-modules/workspace/services/workspace-entity-cache-provider.service';
import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service';
import { WorkspaceGaugeService } from 'src/engine/core-modules/workspace/workspace-gauge.service';
-import { workspaceAutoResolverOpts } from 'src/engine/core-modules/workspace/workspace.auto-resolver-opts';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { WorkspaceResolver } from 'src/engine/core-modules/workspace/workspace.resolver';
import { BillingDisabledGuard } from 'src/engine/guards/billing-disabled.guard';
@@ -50,49 +45,40 @@ import { StandardObjectsPrefillModule } from 'src/engine/workspace-manager/stand
@Module({
imports: [
TypeORMModule,
- TypeOrmModule.forFeature([BillingSubscriptionEntity, WorkspaceEntity]),
+ TypeOrmModule.forFeature([
+ BillingSubscriptionEntity,
+ WorkspaceEntity,
+ UserEntity,
+ UserWorkspaceEntity,
+ ]),
MetricsModule,
StandardObjectsPrefillModule,
- NestjsQueryGraphQLModule.forFeature({
- imports: [
- BillingModule,
- FileModule,
- TokenModule,
- NestjsQueryTypeOrmModule.forFeature([
- UserEntity,
- WorkspaceEntity,
- UserWorkspaceEntity,
- PublicDomainEntity,
- ]),
- ObjectMetadataModule,
- UserWorkspaceModule,
- WorkspaceManagerModule,
- FeatureFlagModule,
- OnboardingModule,
- WorkspaceDataSourceModule,
- TypeORMModule,
- PermissionsModule,
- WorkspaceCacheStorageModule,
- RoleModule,
- AiAgentModule,
- DnsManagerModule,
- WorkspaceDomainsModule,
- SubdomainManagerModule,
- CustomDomainManagerModule,
- ViewModule,
- WorkspaceManyOrAllFlatEntityMapsCacheModule,
- ApplicationModule,
- PreInstalledAppsModule,
- EnterpriseModule,
- StandardObjectsPrefillModule,
- WorkspaceMigrationModule,
- CoreEntityCacheModule,
- UpgradeModule,
- SdkClientModule,
- ],
- services: [WorkspaceService],
- resolvers: workspaceAutoResolverOpts,
- }),
+ BillingModule,
+ FileModule,
+ TokenModule,
+ ObjectMetadataModule,
+ UserWorkspaceModule,
+ WorkspaceManagerModule,
+ FeatureFlagModule,
+ OnboardingModule,
+ WorkspaceDataSourceModule,
+ PermissionsModule,
+ WorkspaceCacheStorageModule,
+ RoleModule,
+ AiAgentModule,
+ DnsManagerModule,
+ WorkspaceDomainsModule,
+ SubdomainManagerModule,
+ CustomDomainManagerModule,
+ ViewModule,
+ WorkspaceManyOrAllFlatEntityMapsCacheModule,
+ ApplicationModule,
+ PreInstalledAppsModule,
+ EnterpriseModule,
+ WorkspaceMigrationModule,
+ CoreEntityCacheModule,
+ UpgradeModule,
+ SdkClientModule,
],
exports: [WorkspaceService, CheckCustomDomainValidRecordsCronCommand],
providers: [
diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts
index 121e663f97..872a4287b6 100644
--- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts
+++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts
@@ -105,7 +105,7 @@ export class WorkspaceResolver {
@Query(() => WorkspaceEntity)
@UseGuards(WorkspaceAuthGuard, NoPermissionGuard)
async currentWorkspace(@AuthWorkspace() { id }: WorkspaceEntity) {
- const workspace = await this.workspaceService.findById(id);
+ const workspace = await this.workspaceService.findOneWorkspaceById(id);
assert(workspace, 'Workspace not found');