원클릭으로
add-graphql-type
Add a new GraphQL ObjectType, InputType, or Enum to the project following its code-first (NestJS + Mercurius) conventions.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Add a new GraphQL ObjectType, InputType, or Enum to the project following its code-first (NestJS + Mercurius) conventions.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Create an End-to-End (E2E) test for a REST controller or GraphQL resolver using Fastify injection.
Add a new BullMQ job queue to the project — processor, producer injection, module registration, Bull Board integration, and unit tests.
Write unit tests for an existing NestJS service, resolver, or controller in the project following its Vitest + NestJS Testing conventions.
Run the full code quality pipeline (TypeScript + Biome + Knip), fix all issues, and clean up comments in changed code.
Create a git commit with all unstaged changes. Use this skill whenever the user asks to commit, make a commit, save changes to git, or says something like "commit this", "commit all changes". Always runs npm run check before committing and fixes any errors found.
Use this workflow to implement ANY new feature following Test-Driven Development strictly.
| name | add-graphql-type |
| description | Add a new GraphQL ObjectType, InputType, or Enum to the project following its code-first (NestJS + Mercurius) conventions. |
The user wants to add a new GraphQL type to the project. They may be adding an @ObjectType, @InputType, an enum, or a combination.
@nestjs/mercuriusautoSchemaFile: true)/altairGraphQLJSON from graphql-type-json is registered globally as JSONpubSub.publish/subscribe with Redis emitterImportant: GraphQL types are hand-written and separate from Prisma-generated types. They do NOT auto-sync. When a Prisma model changes, update the corresponding GraphQL type manually.
Types live in a types/ subdirectory inside the module:
src/modules/<module>/types/
<name>.object-type.ts
<name>.input.ts
<name>.enum.ts
@ObjectType — response typeimport { Field, Int, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class <Name> {
@Field(() => Int, { nullable: false })
id!: number;
@Field(() => Date, { nullable: false })
createdAt!: Date;
@Field(() => Date, { nullable: false })
updatedAt!: Date;
@Field(() => String, { nullable: false })
someField!: string;
@Field(() => String, { nullable: true })
optionalField!: string | null;
}
Field type mapping:
| TypeScript | GraphQL decorator |
|---|---|
number (Int) | () => Int |
number (Float) | () => Float |
string | () => String |
boolean | () => Boolean |
Date | () => Date |
T[] | () => [T] |
| arbitrary JSON | () => GraphQLJSON (import from graphql-type-json) |
@InputType — mutation argument (with Zod validation)import { Field, InputType } from '@nestjs/graphql';
import { createZodDto } from 'nestjs-zod';
import { z } from 'zod';
const <Name>Schema = z.object({
requiredField: z.string().min(1),
optionalUrl: z.url().optional(),
optionalString: z.string().optional(),
});
class <Name>ZodDto extends createZodDto(<Name>Schema) {}
@InputType()
export class <Name>Input extends <Name>ZodDto {
@Field(() => String, { nullable: false })
declare requiredField: string;
@Field(() => String, { nullable: true })
declare optionalUrl?: string;
}
Critical: Use declare (not assignment) when re-declaring Zod DTO properties. This is required to avoid overriding the Zod class instance properties.
import { registerEnumType } from '@nestjs/graphql';
export enum <EnumName> {
VALUE_ONE = 'VALUE_ONE',
VALUE_TWO = 'VALUE_TWO',
}
registerEnumType(<EnumName>, {
name: '<EnumName>',
description: undefined,
});
Use the enum in @ObjectType fields:
import { <EnumName> } from './types/<name>.enum';
// in @ObjectType:
@Field(() => [<EnumName>], { nullable: true })
roles!: Array<keyof typeof <EnumName>>;
After creating the type, use it in a resolver:
import { Query, Resolver, Mutation, Args } from '@nestjs/graphql';
import { <Name> } from './types/<name>.object-type';
import { <Name>Input } from './types/<name>.input';
@Resolver(() => <Name>)
export class <Name>Resolver {
@Query(() => <Name>, { name: '<queryName>' })
async get<Name>(): Promise<<Name>> { ... }
@Mutation(() => <Name>)
async update<Name>(
@Args('input') input: <Name>Input,
): Promise<<Name>> { ... }
}
import { Subscription, Context } from '@nestjs/graphql';
import { PubSub } from 'mercurius';
const EVENTS = {
<NAME>_UPDATED: '<name>Updated',
};
@Subscription(() => <Name>, {
name: EVENTS.<NAME>_UPDATED,
filter: (payload, _variables, context) => {
// return true to deliver to this subscriber
return payload.<name>Updated.id === context.req?.user?.id;
},
})
<name>Updated(@Context('pubsub') pubSub: PubSub) {
return pubSub.subscribe(EVENTS.<NAME>_UPDATED);
}
// Publishing (in a mutation):
pubSub.publish({
topic: EVENTS.<NAME>_UPDATED,
payload: { <name>Updated: result },
});
types/ directorynpm run check to verify the types, linting, and unused exports