From d1fd3a1e94fdeb7d1c5a87e5a3f4a392cb372a37 Mon Sep 17 00:00:00 2001 From: Jeongho Nam Date: Tue, 7 Apr 2026 19:19:59 +0900 Subject: [PATCH 1/4] feat(agent): automated agent healing process. --- .../prompts/REALIZE_OPERATION_CORRECT.md | 6 + .../agent/prompts/REALIZE_OPERATION_WRITE.md | 45 +++++++- .../prompts/REALIZE_TRANSFORMER_CORRECT.md | 36 +++++- .../prompts/REALIZE_TRANSFORMER_WRITE.md | 12 ++ .../utils/AutoBeJsonSchemaFactory.ts | 16 +++ .../utils/AutoBeJsonSchemaValidator.ts | 103 +++++++++++------- 6 files changed, 172 insertions(+), 46 deletions(-) diff --git a/packages/agent/prompts/REALIZE_OPERATION_CORRECT.md b/packages/agent/prompts/REALIZE_OPERATION_CORRECT.md index bba020e269c..4c3c77a4685 100644 --- a/packages/agent/prompts/REALIZE_OPERATION_CORRECT.md +++ b/packages/agent/prompts/REALIZE_OPERATION_CORRECT.md @@ -183,6 +183,7 @@ When TS2353 says `'X' does not exist in type 'YSelect'`: - Table name `shopping_categories` vs property name `category` - FK column `shopping_seller_id` vs relation `seller` - DTO name `orderItems` vs property name `items` + - Abbreviated FK `organization_id` vs actual column `hrm_platform_organization_id` 4. After finding the correct name, update BOTH the `select` clause AND any `transform`/return code that references the relation ### 4.6. Unwrapping Transformer.select() with `.select` @@ -302,6 +303,9 @@ export async function method__path(props: {...}): Promise { | Table name in query | Use relation property name | Check Prisma schema | | `.select().select` | Remove trailing `.select` | - | | `Prisma.DbNull` on non-Json column | Use plain `null` | `Prisma.DbNull` only for `Json?` | +| `{ equals: null }` in where | Use direct `null` | `where: { field: null }` | +| Lowercase `not`/`and`/`or` | Uppercase `NOT`/`AND`/`OR` | Prisma logical operators are UPPERCASE | +| Abbreviated FK name | Use full name from schema | `hrm_platform_organization_id`, not `organization_id` | | Type validation code | **DELETE IT** | No alternative | ## 7. Final Checklist @@ -321,6 +325,8 @@ export async function method__path(props: {...}): Promise { ### Prisma Operations - [ ] Used relation property names (NOT table names or FK columns) +- [ ] FK column names exact from schema (never abbreviated) +- [ ] `where` filters: direct `null`, uppercase `NOT`/`AND`/`OR` - [ ] `satisfies Prisma.{table}FindManyArgs` on inline nested selects - [ ] Transformer.select() assigned directly (NOT `.select().select`) - [ ] Select includes all accessed fields (relations, scalars, FK columns) diff --git a/packages/agent/prompts/REALIZE_OPERATION_WRITE.md b/packages/agent/prompts/REALIZE_OPERATION_WRITE.md index 88c47285722..453c1f57a43 100644 --- a/packages/agent/prompts/REALIZE_OPERATION_WRITE.md +++ b/packages/agent/prompts/REALIZE_OPERATION_WRITE.md @@ -458,9 +458,10 @@ const customerId = props.customer.id; // From ActorPayload **Before writing ANY query**: 1. READ the database schema thoroughly -2. VERIFY each field name (case-sensitive) +2. VERIFY each field name character-for-character (case-sensitive) 3. VERIFY relation property names from schema -4. NEVER fabricate, imagine, or guess +4. Copy FK column names exactly — never abbreviate (e.g., `hrm_platform_organization_id`, NOT `organization_id`) +5. NEVER fabricate, imagine, or guess **Key Hints from DTO Schema** — each DTO property has JSDoc annotations: - `@x-autobe-database-schema`: The DB table this DTO maps to @@ -576,7 +577,39 @@ await MyGlobal.prisma.categories.updateMany({ `Prisma.DbNull` is reserved exclusively for JSON-type columns (`Json?`). For all other nullable types, plain `null` is the correct value. -### 8.6. Data Transformation Rules +### 8.6. Prisma Where Filter Syntax + +Prisma `where` clauses have strict syntax. These are the most common mistakes: + +```typescript +// ❌ WRONG - { equals: null } for nullable filter +where: { deleted_at: { equals: null } } + +// ✅ CORRECT - Direct null comparison +where: { deleted_at: null } + +// ❌ WRONG - Lowercase `not` (TS2353) +where: { not: { status: "deleted" } } + +// ✅ CORRECT - Uppercase `NOT` for logical operators +where: { NOT: { status: "deleted" } } + +// ❌ WRONG - Nested relation filter with scalar value +where: { department: props.departmentId } + +// ✅ CORRECT - Relation filter uses object with `id` +where: { department: { id: props.departmentId } } + +// ❌ WRONG - Nullable relation filter without handling +where: { parent_department: { id: parentId } } // Fails when null + +// ✅ CORRECT - Nullable relation: use FK column directly +where: { parent_department_id: parentId ?? null } +``` + +**Prisma logical operators are UPPERCASE**: `AND`, `OR`, `NOT` — never `and`, `or`, `not`. + +### 8.7. Data Transformation Rules | Transformation | Pattern | |----------------|---------| @@ -636,7 +669,7 @@ return { }; ``` -### 8.7. DELETE Operation: Cascade Deletion +### 8.8. DELETE Operation: Cascade Deletion All tables use `onDelete: Cascade` in their foreign key relations. When deleting a record, simply delete the target row — the database automatically cascades to all dependent rows. @@ -658,7 +691,7 @@ await MyGlobal.prisma.shopping_sales.delete({ }); ``` -### 8.8. Manual CREATE Example +### 8.9. Manual CREATE Example ```typescript export async function postShoppingSaleReview(props: { @@ -856,9 +889,11 @@ throw new HttpException("Forbidden", HttpStatus.FORBIDDEN); ### Manual Code (when no Collector/Transformer) - [ ] Verified ALL field/relation names against database schema +- [ ] FK column names copied exactly — never abbreviated (e.g., `hrm_platform_organization_id`) - [ ] Used relation property names (NOT table names or FK columns) - [ ] Used `connect` syntax for relations (NOT direct FK assignment) - [ ] `satisfies Prisma.{table}FindManyArgs` on inline nested selects +- [ ] `where` filters: direct `null` (not `{ equals: null }`), uppercase `NOT`/`AND`/`OR` - [ ] Converted dates with `.toISOString()` - [ ] Handled null→undefined for optional fields - [ ] Handled null→null for nullable fields diff --git a/packages/agent/prompts/REALIZE_TRANSFORMER_CORRECT.md b/packages/agent/prompts/REALIZE_TRANSFORMER_CORRECT.md index 3393c7943ce..38e9a60108f 100644 --- a/packages/agent/prompts/REALIZE_TRANSFORMER_CORRECT.md +++ b/packages/agent/prompts/REALIZE_TRANSFORMER_CORRECT.md @@ -256,9 +256,30 @@ export function select() { **Key rule**: Every property accessed on `input` in `transform()` MUST have a corresponding entry in `select()`. -### 5.6. FK Column Names Use `snake_case` from the Schema +### 5.6. Computed Fields Selected as Columns (TS2353) -Foreign key columns always use the exact `snake_case` name defined in the Prisma schema. The relation property name (often camelCase) is a separate concept — combining them produces a name that exists nowhere: +When TS2353 says a field doesn't exist and it looks like an aggregation (e.g., `total_hours`, `average_rating`, `total_count`), it's likely a computed field that is NOT a database column. + +```typescript +// ❌ ERROR: 'total_billable_hours' does not exist in type Select +select: { total_billable_hours: true } + +// ✅ FIX: Select the source relation, compute in transform() +select: { + timelogs: { select: { hours: true, billable: true } } + satisfies Prisma.hrm_platform_timelogsFindManyArgs, +} +// transform(): +totalBillableHours: input.timelogs + .filter(t => t.billable) + .reduce((sum, t) => sum + t.hours, 0), +``` + +**Diagnosis**: If a field name sounds like an aggregation (`*_count`, `total_*`, `average_*`), it's computed from a relation — select the relation instead. + +### 5.7. FK Column Names: Exact `snake_case` from Schema (Never Abbreviate) + +Foreign key columns always use the FULL exact `snake_case` name defined in the Prisma schema. The relation property name (often camelCase) is a separate concept — combining or abbreviating them produces a name that exists nowhere: ```typescript // Prisma schema: @@ -270,11 +291,17 @@ select: { parentComment_id: true } // ✅ CORRECT: exact column name from schema select: { parent_comment_id: true } + +// ❌ ERROR: 'organization_id' — abbreviated FK name +select: { organization_id: true } + +// ✅ CORRECT: full FK name from schema +select: { hrm_platform_organization_id: true } ``` **Compiler name suggestions are authoritative.** When the compiler says `Did you mean 'Y'?`, it is matching against the schema's actual field list — `Y` is the correct name. Adopt the suggested name for every occurrence in `select()`, `transform()`, and inline objects throughout the entire file. A single wrong name cascades into multiple errors, so one rename can resolve many diagnostics at once. -### 5.7. Typia Tag Type Mismatch +### 5.8. Typia Tag Type Mismatch ```typescript // ❌ ERROR: Type 'number & Type<"int32">' is not assignable to type 'Minimum<0>' @@ -296,7 +323,8 @@ count: input._count.reviews satisfies number as number, ### Naming - [ ] Relation property names from Prisma model (NOT table names) -- [ ] FK columns use exact `snake_case` from schema +- [ ] FK columns use exact full `snake_case` from schema (never abbreviated) +- [ ] Computed fields derived from relations in `transform()`, not selected as columns - [ ] Transformer.select() assigned directly (NOT `.select().select`) ### Neighbor Reuse diff --git a/packages/agent/prompts/REALIZE_TRANSFORMER_WRITE.md b/packages/agent/prompts/REALIZE_TRANSFORMER_WRITE.md index d77adae38da..44a94703de4 100644 --- a/packages/agent/prompts/REALIZE_TRANSFORMER_WRITE.md +++ b/packages/agent/prompts/REALIZE_TRANSFORMER_WRITE.md @@ -240,6 +240,7 @@ select: { **Rules**: 1. If you need a relation not listed in the table, the DTO field is likely a computed field (see Section 8) 2. FK columns (e.g., `reddit_clone_member_id`) are scalar fields, NOT relations — select them with `true`, not `{ select: {...} }` +3. FK column names use the FULL name from the schema — never abbreviate (e.g., `hrm_platform_organization_id`, NOT `organization_id`) ### 6.3. Mandatory Neighbor Transformer Reuse @@ -418,6 +419,17 @@ Cross-check: every `transformMappings` entry must have a corresponding line in t When a DTO field doesn't exist as a database column, select the underlying relation and compute in `transform()`. Every aggregation is backed by a real relation — select that relation, then derive the value. +**NEVER select a computed field directly** — it does not exist as a column: + +```typescript +// ❌ WRONG (TS2353) - total_hours is NOT a column, it's computed from timelogs +select: { total_hours: true } + +// ✅ CORRECT - select the source relation, compute in transform() +select: { timelogs: { select: { hours: true } } } +// transform(): total_hours = input.timelogs.reduce((sum, t) => sum + t.hours, 0) +``` + ```typescript // DTO: reviewCount, averageRating (NOT in DB) // Underlying relation: reviews (hasMany) diff --git a/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaFactory.ts b/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaFactory.ts index 162e5597dae..22f3af6918a 100644 --- a/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaFactory.ts +++ b/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaFactory.ts @@ -50,6 +50,22 @@ export namespace AutoBeJsonSchemaFactory { if (value.properties.limit === undefined) value.properties.limit = pageRequest.properties.limit; } + + // Rewrite every $ref pointing to a bogus .IPagination variant + // (e.g. IEcommerceMall.IPagination) → IPage.IPagination. + for (const value of Object.values(schemas)) + AutoBeOpenApiTypeChecker.skim({ + schema: value, + accessor: "", + closure: (next) => { + if ( + AutoBeOpenApiTypeChecker.isReference(next) && + next.$ref.endsWith(".IPagination") && + next.$ref !== "#/components/schemas/IPage.IPagination" + ) + next.$ref = "#/components/schemas/IPage.IPagination"; + }, + }); }; export const fixAuthorizationSchemas = ( diff --git a/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts b/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts index 0b2e1611bd9..5b36e24d835 100644 --- a/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts +++ b/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts @@ -52,7 +52,8 @@ export namespace AutoBeJsonSchemaValidator { validateReferenceId(props); validatePropertyNames(props); validateNumericRanges(props); - // validateEmptyProperties(props); + validatePaginationVariant(props); + validateEmptyProperties(props); vo(props.typeName, props.schema); AutoBeOpenApiTypeChecker.skim({ @@ -724,40 +725,68 @@ export namespace AutoBeJsonSchemaValidator { }); }; - // const validateEmptyProperties = (props: IProps): void => { - // if (AutoBeOpenApiTypeChecker.isObject(props.schema) === false) return; - // if (Object.keys(props.schema.properties).length !== 0) return; - // if ( - // isObjectType({ - // operations: props.operations, - // typeName: props.typeName, - // }) === false - // ) - // return; - - // props.errors.push({ - // path: `${props.path}.properties`, - // expected: "At least 1 property in properties", - // value: props.schema.properties, - // description: StringUtil.trim` - // Schema ${JSON.stringify(props.typeName)} has zero properties but is used - // as a request body or response body in API operations. - - // Empty properties will cause TypeScript compilation errors (TS2339) in the - // downstream Realize stage because implementation code will try to access - // properties that don't exist on the type. - - // You MUST define at least one property in the schema. Load the database - // schema and add the appropriate properties based on the DTO type: - // - ICreate: User-provided business fields (exclude id, timestamps, actor FKs) - // - IUpdate: All mutable business fields (all optional) - // - ISummary: Essential display fields for list views - // - IEntity (root): All public fields including relations - // - IRequest: Pagination and filter parameters - // - IJoin/ILogin: Credentials and session context fields - - // Note that, this is not a recommendation, but an instruction you must follow. - // `, - // }); - // }; + const validatePaginationVariant = (props: IProps): void => { + // Reject .IPagination variants on entity types (only IPage.IPagination is valid) + if ( + props.typeName.endsWith(".IPagination") && + props.typeName !== "IPage.IPagination" + ) + props.errors.push({ + path: props.path, + expected: `No .IPagination variant — only "IPage.IPagination" is valid`, + value: props.typeName, + description: StringUtil.trim` + You have defined a type ${JSON.stringify(props.typeName)} with an + ".IPagination" suffix, but ".IPagination" is NOT a valid DTO variant. + + The only valid pagination metadata type is "IPage.IPagination", which is + a system preset containing { current, limit, records, pages }. + + Valid DTO variants are: .ISummary, .ICreate, .IUpdate, .IRequest, + .IInvert, .IJoin, .ILogin, .IAuthorized. + + Remove this type entirely. If you need pagination support, the system + automatically wraps your entity ISummary types in IPage wrappers. + + Note that, this is not a recommendation, but an instruction you must follow. + `, + }); + }; + + const validateEmptyProperties = (props: IProps): void => { + if (AutoBeOpenApiTypeChecker.isObject(props.schema) === false) return; + if (Object.keys(props.schema.properties).length !== 0) return; + if ( + isObjectType({ + operations: props.operations, + typeName: props.typeName, + }) === false + ) + return; + + props.errors.push({ + path: `${props.path}.properties`, + expected: "At least 1 property in properties", + value: props.schema.properties, + description: StringUtil.trim` + Schema ${JSON.stringify(props.typeName)} has zero properties but is used + as a request body or response body in API operations. + + Empty properties will cause TypeScript compilation errors (TS2339) in the + downstream Realize stage because implementation code will try to access + properties that don't exist on the type. + + You MUST define at least one property in the schema. Load the database + schema and add the appropriate properties based on the DTO type: + - ICreate: User-provided business fields (exclude id, timestamps, actor FKs) + - IUpdate: All mutable business fields (all optional) + - ISummary: Essential display fields for list views + - IEntity (root): All public fields including relations + - IRequest: Pagination and filter parameters + - IJoin/ILogin: Credentials and session context fields + + Note that, this is not a recommendation, but an instruction you must follow. + `, + }); + }; } From 80c8326c149c6afcc3c9bc945341b60d091b8b1b Mon Sep 17 00:00:00 2001 From: Jeongho Nam Date: Tue, 7 Apr 2026 19:41:58 +0900 Subject: [PATCH 2/4] check zero peropties --- ...InterfaceSchemaPropertyReviseProgrammer.ts | 22 +++++++++++++++++++ .../utils/AutoBeJsonSchemaFactory.ts | 8 +++++++ 2 files changed, 30 insertions(+) diff --git a/packages/agent/src/orchestrate/interface/programmers/AutoBeInterfaceSchemaPropertyReviseProgrammer.ts b/packages/agent/src/orchestrate/interface/programmers/AutoBeInterfaceSchemaPropertyReviseProgrammer.ts index 4528840a0a1..04b35ec4b09 100644 --- a/packages/agent/src/orchestrate/interface/programmers/AutoBeInterfaceSchemaPropertyReviseProgrammer.ts +++ b/packages/agent/src/orchestrate/interface/programmers/AutoBeInterfaceSchemaPropertyReviseProgrammer.ts @@ -59,6 +59,28 @@ export namespace AutoBeInterfaceSchemaPropertyReviseProgrammer { `, }); + // check that at least one property survives after revisions + if ( + props.revises.length > 0 && + props.revises.every((r) => r.type === "erase") + ) + props.errors.push({ + path: `${props.path}.revises`, + expected: "At least one non-erase revision to retain a property", + value: props.revises.map((r) => r.type), + description: StringUtil.trim` + All revisions are "erase", which would leave the schema with zero + properties. An object type used as a DTO must have at least one + property — otherwise the downstream Realize stage will fail with + TypeScript compilation errors (TS2339). + + Keep at least one property by using "depict", "create", or "update" + instead of "erase" for the essential fields. + + Note that, this is not a recommendation, but an instruction you must follow. + `, + }); + if (props.model === null) return; // check all DB schema properties are revised diff --git a/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaFactory.ts b/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaFactory.ts index 22f3af6918a..b5ebe6aedf8 100644 --- a/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaFactory.ts +++ b/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaFactory.ts @@ -66,6 +66,14 @@ export namespace AutoBeJsonSchemaFactory { next.$ref = "#/components/schemas/IPage.IPagination"; }, }); + + // Delete the bogus schemas themselves so the LLM never sees them + // in subsequent iterations. Covers both entity variants + // (IEcommerceMall.IPagination) and their page wrappers + // (IPageIEcommerceMall.IPagination). + for (const key of Object.keys(schemas)) + if (key.endsWith(".IPagination") && key !== "IPage.IPagination") + delete schemas[key]; }; export const fixAuthorizationSchemas = ( From d783c405a25d178b3763eabee429ffa225494cc4 Mon Sep 17 00:00:00 2001 From: Jeongho Nam Date: Tue, 7 Apr 2026 22:16:09 +0900 Subject: [PATCH 3/4] turn off zero property checking due to gpt-5.4-mini --- .../utils/AutoBeJsonSchemaValidator.ts | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts b/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts index 5b36e24d835..6f97c6bdea1 100644 --- a/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts +++ b/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts @@ -53,7 +53,7 @@ export namespace AutoBeJsonSchemaValidator { validatePropertyNames(props); validateNumericRanges(props); validatePaginationVariant(props); - validateEmptyProperties(props); + // validateEmptyProperties(props); vo(props.typeName, props.schema); AutoBeOpenApiTypeChecker.skim({ @@ -753,40 +753,40 @@ export namespace AutoBeJsonSchemaValidator { }); }; - const validateEmptyProperties = (props: IProps): void => { - if (AutoBeOpenApiTypeChecker.isObject(props.schema) === false) return; - if (Object.keys(props.schema.properties).length !== 0) return; - if ( - isObjectType({ - operations: props.operations, - typeName: props.typeName, - }) === false - ) - return; - - props.errors.push({ - path: `${props.path}.properties`, - expected: "At least 1 property in properties", - value: props.schema.properties, - description: StringUtil.trim` - Schema ${JSON.stringify(props.typeName)} has zero properties but is used - as a request body or response body in API operations. - - Empty properties will cause TypeScript compilation errors (TS2339) in the - downstream Realize stage because implementation code will try to access - properties that don't exist on the type. - - You MUST define at least one property in the schema. Load the database - schema and add the appropriate properties based on the DTO type: - - ICreate: User-provided business fields (exclude id, timestamps, actor FKs) - - IUpdate: All mutable business fields (all optional) - - ISummary: Essential display fields for list views - - IEntity (root): All public fields including relations - - IRequest: Pagination and filter parameters - - IJoin/ILogin: Credentials and session context fields - - Note that, this is not a recommendation, but an instruction you must follow. - `, - }); - }; + // const validateEmptyProperties = (props: IProps): void => { + // if (AutoBeOpenApiTypeChecker.isObject(props.schema) === false) return; + // if (Object.keys(props.schema.properties).length !== 0) return; + // if ( + // isObjectType({ + // operations: props.operations, + // typeName: props.typeName, + // }) === false + // ) + // return; + + // props.errors.push({ + // path: `${props.path}.properties`, + // expected: "At least 1 property in properties", + // value: props.schema.properties, + // description: StringUtil.trim` + // Schema ${JSON.stringify(props.typeName)} has zero properties but is used + // as a request body or response body in API operations. + + // Empty properties will cause TypeScript compilation errors (TS2339) in the + // downstream Realize stage because implementation code will try to access + // properties that don't exist on the type. + + // You MUST define at least one property in the schema. Load the database + // schema and add the appropriate properties based on the DTO type: + // - ICreate: User-provided business fields (exclude id, timestamps, actor FKs) + // - IUpdate: All mutable business fields (all optional) + // - ISummary: Essential display fields for list views + // - IEntity (root): All public fields including relations + // - IRequest: Pagination and filter parameters + // - IJoin/ILogin: Credentials and session context fields + + // Note that, this is not a recommendation, but an instruction you must follow. + // `, + // }); + // }; } From c2194fbd20ae07fa8b4a3f00dc8c273ffc2558ec Mon Sep 17 00:00:00 2001 From: Jeongho Nam Date: Tue, 7 Apr 2026 22:34:14 +0900 Subject: [PATCH 4/4] Update packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts b/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts index 6f97c6bdea1..cc94f20697f 100644 --- a/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts +++ b/packages/agent/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts @@ -742,7 +742,7 @@ export namespace AutoBeJsonSchemaValidator { The only valid pagination metadata type is "IPage.IPagination", which is a system preset containing { current, limit, records, pages }. - Valid DTO variants are: .ISummary, .ICreate, .IUpdate, .IRequest, + Common DTO variants include: .ISummary, .ICreate, .IUpdate, .IRequest, .IInvert, .IJoin, .ILogin, .IAuthorized. Remove this type entirely. If you need pagination support, the system