一键导入
tpl-backend-nestjs-typescript
Template do pack (backend/07-nestjs-typescript.md). Orienta o agente em APIs, servicos e arquitetura backend alinhado a esse contexto.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Template do pack (backend/07-nestjs-typescript.md). Orienta o agente em APIs, servicos e arquitetura backend alinhado a esse contexto.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Generate custom favicons from logos, text, or brand colours. Produces favicon.svg, favicon.ico, apple-touch-icon.png, icon-192/512.png, and web manifest. Use whenever the user wants a favicon, mentions replacing a CMS default favicon, converting a logo into a favicon, creating branded initials icons, or troubleshooting favicon not displaying / iOS black square / missing manifest.
"Get a second opinion from leading AI models on code, architecture, strategy, prompting, or anything. Queries models via OpenRouter, Gemini, or OpenAI APIs. Supports single opinion, multi-model consensus, and devil's advocate patterns. Use whenever the user says 'brains trust', 'second opinion', 'ask gemini', 'ask gpt', 'peer review', 'consult another model', 'challenge this', or 'devil's advocate'."
Run an independent code review using the OpenAI Codex CLI in headless mode. Gets a second opinion from a different model family (GPT-5/o3) on recent changes, a PR, a commit, or the whole app — covering bugs, regressions, security, data consistency, UX/state bugs, performance risks, and testing gaps. Saves a severity-prioritised report to .jez/reviews/. Triggers: 'codex review', 'review with codex', 'second opinion on this code', 'independent code review', 'what does codex think', 'get codex to review'.
Deep research and discovery before building something new. Explores local projects for reusable code, researches competitors, reads forums and reviews, analyses plugin ecosystems, investigates technical options, and produces a comprehensive research brief. Three depths: focused (30 min), wide (1-2 hours), deep (3-6 hours). Triggers: 'research this', 'deep research', 'discovery', 'explore the space', 'what should I build', 'competitive analysis', 'before I start building', 'research before coding'.
Plan and execute entire application builds. Generates phased delivery roadmaps, then executes them autonomously — phase by phase, committing at milestones, deploying, testing, and continuing until done or stuck. Modes: plan (generate roadmap), start (begin executing), resume (continue from where you left off), status (show progress). Triggers: 'roadmap', 'plan the build', 'start building', 'resume the build', 'keep going', 'build the whole thing', 'execute the roadmap', 'what phase are we on'.
Walk through a live web app AS a real user to find usability + behavioural bugs that static reviews miss. REQUIRES proof of interaction (typing, clicking, sending, observing) before any verdict — a sweep that didn't interact terminates with verdict 'Incomplete'. Walks threads, exercises every element, runs the multi-pane stress matrix, visual polish sweep, component perfection checklist, automated a11y (axe-core), pragmatic performance budget (LCP/CLS/INP), scenario battery (11 scenarios), and stress recipes including the real-flavour data battery. Hard gates: console errors/warnings = 0, network 5xx = 0, layout collapse = 0, axe Critical/Serious = 0, perf budget green. Audit-the-audit meta-check rejects rushed reports. Each finding has reproduction steps, evidence path, and suspected code location. Trigger with 'ux audit', 'walkthrough', 'qa sweep', 'audit the app', 'dogfood this', 'check all pages', 'find what's broken', 'stress the UI'.
| name | tpl-backend-nestjs-typescript |
| description | Template do pack (backend/07-nestjs-typescript.md). Orienta o agente em APIs, servicos e arquitetura backend alinhado a esse contexto. |
| metadata | {"version":"1.0.0","source_template":"backend/07-nestjs-typescript.md","generated_by":"install_pack_templates_as_claude_skills"} |
Skill gerado a partir do pack templates-claude-code. Arquivo de origem: backend/07-nestjs-typescript.md. Use como baseline e adapte ao projeto antes de mudancas grandes.
| Technology | Version | Purpose |
|---|---|---|
| Node.js | 22.x | Runtime |
| TypeScript | 5.4+ | Language |
| NestJS | 10.x | Framework |
| PostgreSQL | 16 | Primary database |
| Prisma | 5.x | ORM + migrations |
| Passport | 0.7+ | Auth strategies |
| passport-jwt | 4.x | JWT strategy |
| @nestjs/jwt | 10.x | JWT module |
| class-validator | 0.14+ | DTO validation |
| class-transformer | 0.5+ | Request transformation |
| Jest | 29.x | Unit tests |
| Supertest | 7.x | e2e tests |
| @nestjs/testing | 10.x | Test module utilities |
src/
├── app.module.ts # Root module — imports feature modules
├── main.ts # Bootstrap: create app, pipes, guards, listen
├── modules/
│ ├── auth/
│ │ ├── auth.module.ts
│ │ ├── auth.controller.ts
│ │ ├── auth.service.ts
│ │ ├── strategies/
│ │ │ ├── jwt.strategy.ts
│ │ │ └── jwt-refresh.strategy.ts
│ │ ├── guards/
│ │ │ ├── jwt-auth.guard.ts
│ │ │ └── roles.guard.ts
│ │ └── decorators/
│ │ ├── current-user.decorator.ts
│ │ └── roles.decorator.ts
│ └── users/
│ ├── users.module.ts
│ ├── users.controller.ts
│ ├── users.service.ts
│ ├── users.repository.ts # Wraps Prisma for users domain
│ ├── dto/
│ │ ├── create-user.dto.ts
│ │ ├── update-user.dto.ts
│ │ └── user-response.dto.ts
│ └── interceptors/
│ └── user-transform.interceptor.ts
├── common/
│ ├── decorators/
│ ├── filters/
│ │ └── http-exception.filter.ts
│ ├── interceptors/
│ │ └── transform.interceptor.ts # Wraps responses in { data, meta } envelope
│ └── pipes/
│ └── parse-uuid.pipe.ts
├── database/
│ └── prisma.service.ts # Injectable Prisma client
└── config/
└── configuration.ts # Typed config with @nestjs/config
test/
├── app.e2e-spec.ts
└── jest-e2e.json
AppModule in testsmain.ts (not per-controller)class-transformer plainToInstance used in interceptors to strip sensitive fieldsCreate a new module when the domain:
Do NOT create a module for:
common/@nestjs/config// src/modules/posts/posts.module.ts
import { Module } from '@nestjs/common'
import { PostsController } from './posts.controller'
import { PostsService } from './posts.service'
import { PostsRepository } from './posts.repository'
import { DatabaseModule } from '../../database/database.module'
@Module({
imports: [DatabaseModule], // Only import what this module needs
controllers: [PostsController],
providers: [PostsService, PostsRepository],
exports: [PostsService], // Only export if other modules need this service
})
export class PostsModule {}
Guards run BEFORE interceptors and pipes. Use @UseGuards on controller or route level; global guards registered in main.ts.
// src/modules/auth/guards/jwt-auth.guard.ts
import { Injectable, ExecutionContext, UnauthorizedException } from '@nestjs/common'
import { AuthGuard } from '@nestjs/passport'
import { Reflector } from '@nestjs/core'
import { IS_PUBLIC_KEY } from '../decorators/public.decorator'
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
constructor(private reflector: Reflector) {
super()
}
canActivate(context: ExecutionContext) {
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
])
if (isPublic) return true
return super.canActivate(context)
}
}
// src/modules/auth/guards/roles.guard.ts
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<Role[]>('roles', [
context.getHandler(),
context.getClass(),
])
if (!requiredRoles?.length) return true
const { user } = context.switchToHttp().getRequest()
return requiredRoles.includes(user.role)
}
}
// src/modules/auth/decorators/current-user.decorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common'
export const CurrentUser = createParamDecorator(
(_data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest()
return request.user // injected by JwtStrategy.validate()
},
)
// src/modules/auth/decorators/roles.decorator.ts
import { SetMetadata } from '@nestjs/common'
export const Roles = (...roles: string[]) => SetMetadata('roles', roles)
// src/common/decorators/public.decorator.ts
import { SetMetadata } from '@nestjs/common'
export const IS_PUBLIC_KEY = 'isPublic'
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true)
// src/modules/users/users.controller.ts
import { Controller, Get, Patch, Body, HttpCode } from '@nestjs/common'
import { CurrentUser } from '../auth/decorators/current-user.decorator'
import { Roles } from '../auth/decorators/roles.decorator'
import { UpdateUserDto } from './dto/update-user.dto'
import { UsersService } from './users.service'
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get('me')
getMe(@CurrentUser() user: AuthUser) {
return this.usersService.findById(user.id)
}
@Patch('me')
@HttpCode(200)
updateMe(@CurrentUser() user: AuthUser, @Body() dto: UpdateUserDto) {
return this.usersService.update(user.id, dto)
}
@Get()
@Roles('admin')
findAll() {
return this.usersService.findAll()
}
}
// src/modules/users/dto/create-user.dto.ts
import { IsEmail, IsString, MinLength, IsEnum, IsOptional } from 'class-validator'
import { Transform } from 'class-transformer'
export class CreateUserDto {
@IsEmail({}, { message: 'Invalid email format' })
@Transform(({ value }) => value?.toLowerCase().trim())
email: string
@IsString()
@MinLength(2, { message: 'Name must be at least 2 characters' })
name: string
@IsString()
@MinLength(8, { message: 'Password must be at least 8 characters' })
password: string
@IsEnum(['admin', 'user'], { message: 'role must be admin or user' })
@IsOptional()
role?: 'admin' | 'user' = 'user'
}
// src/common/interceptors/transform.interceptor.ts
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common'
import { map, Observable } from 'rxjs'
import { plainToInstance } from 'class-transformer'
export interface Response<T> {
data: T
timestamp: string
}
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
intercept(_context: ExecutionContext, next: CallHandler<T>): Observable<Response<T>> {
return next.handle().pipe(
map(data => ({
data,
timestamp: new Date().toISOString(),
})),
)
}
}
// src/main.ts
import { NestFactory, Reflector } from '@nestjs/core'
import { ValidationPipe, ClassSerializerInterceptor } from '@nestjs/common'
import { AppModule } from './app.module'
import { JwtAuthGuard } from './modules/auth/guards/jwt-auth.guard'
import { RolesGuard } from './modules/auth/guards/roles.guard'
import { TransformInterceptor } from './common/interceptors/transform.interceptor'
import { HttpExceptionFilter } from './common/filters/http-exception.filter'
async function bootstrap() {
const app = await NestFactory.create(AppModule)
const reflector = app.get(Reflector)
app.setGlobalPrefix('api/v1')
app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true }))
app.useGlobalGuards(new JwtAuthGuard(reflector), new RolesGuard(reflector))
app.useGlobalInterceptors(new ClassSerializerInterceptor(reflector), new TransformInterceptor())
app.useGlobalFilters(new HttpExceptionFilter())
await app.listen(process.env.PORT ?? 3000)
}
bootstrap()
| Trigger | Method | Route | Auth | Controller Action |
|---|---|---|---|---|
| Register | POST | /api/v1/auth/register | Public | AuthController.register |
| Login | POST | /api/v1/auth/login | Public | AuthController.login |
| Refresh token | POST | /api/v1/auth/refresh | Refresh JWT | AuthController.refresh |
| Get own profile | GET | /api/v1/users/me | JWT | UsersController.getMe |
| Update profile | PATCH | /api/v1/users/me | JWT | UsersController.updateMe |
| Change password | POST | /api/v1/users/me/password | JWT | UsersController.changePassword |
| List all users | GET | /api/v1/users | JWT + admin role | UsersController.findAll |
| Get user by ID | GET | /api/v1/users/:id | JWT + admin role | UsersController.findOne |
| Delete user | DELETE | /api/v1/users/:id | JWT + admin role | UsersController.remove |
Before opening a PR, verify ALL of the following:
npx tsc --noEmit passes — zero type errorsjest --passWithNoTests passes — unit and e2eValidationPipe({ whitelist: true }) active — unknown properties strippedclass-validator decorators — no manual validation in controllers@Exclude() on sensitive fields (password, hashedToken)@Public() explicitly applied where auth is optionalforwardRef() only as last resortnest build passes without errors@Injectable() without including the class in a module's providers arrayPrismaService directly into controllers — use repositoriesreq.body directly in controllers — always use typed DTOsValidationPipe by omitting @Body() decoratorforwardRef() as a first solution — redesign the dependency instead@Global() module decorator except for DatabaseModule and ConfigModuleError — always throw HttpException subclasses (NotFoundException, etc.)