Help us improve
Share bugs, ideas, or general feedback.
From backend-overture
This skill provides backend TypeScript development rules including functions-over-classes design, NestJS/TypeORM patterns, layered error handling, streaming, and memory management. Automatically loaded when implementing backend TypeScript services, APIs, or when "NestJS", "backend TypeScript", "API service", "TypeORM", or "server-side TypeScript" are mentioned.
npx claudepluginhub tundraray/overture --plugin backend-overtureHow this skill is triggered — by the user, by Claude, or both
Slash command
/backend-overture:typescript-rules-backendThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- **Functions Over Classes**: Prefer pure functions and function composition. Use classes only when the framework requires it (NestJS controllers/services, TypeORM entities)
Provides expert Node.js backend patterns for Express, NestJS, Fastify APIs including project structures, async error handlers, custom error classes, and global error handling.
Applies opinionated NestJS conventions for backends: modules, dependency injection, controllers/services, DTOs with class-validator, guards/interceptors/pipes, JWT auth, TypeORM/Prisma. Use for REST/GraphQL APIs.
Enforces NestJS best practices for modular architecture, dependency injection scoping, exception filters, class-validator DTO validation, and Drizzle ORM integration. Use when designing modules, providers, filters, DTOs, or ORM in NestJS apps.
Share bugs, ideas, or general feedback.
Absolute Rule: any type is completely prohibited. It disables type checking and becomes a source of runtime errors.
any Type Alternatives (Priority Order)
unknown Type + Type Guards: Use for validating external input (API request bodies, environment variables, message queue payloads)Type Guard Implementation Pattern
function isCreateUserDto(value: unknown): value is CreateUserDto {
return typeof value === 'object' && value !== null && 'email' in value && 'name' in value
}
Modern Type Features
satisfies Operator: const config = { port: 3000 } satisfies AppConfig — Preserves inferenceconst Assertion: const ROLES = ['admin', 'user', 'viewer'] as const — Immutable and type-safetype UserId = string & { __brand: 'UserId' } — Distinguish domain identifierstype EventName = \on${Capitalize}`` — Express string patterns with typesType Safety in Backend Implementation
unknown, validate with Zod/class-validator before processingunknown, validate at startup — fail fast on missing required valuesunknown, validate with schema before processingType Safety in Data Flow
unknown) → Validation (Zod/class-validator) → DTO (Type Guaranteed) → ServiceType Complexity Management
Function Design
// ✅ Object parameter
function createUser({ name, email, role }: CreateUserParams): Promise<User> {}
NestJS Patterns (when using NestJS)
// ✅ Thin controller — delegates to service
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
create(@Body() dto: CreateUserDto): Promise<UserResponseDto> {
return this.userService.create(dto)
}
}
TypeORM Patterns (when using TypeORM)
synchronize: true in productionDependency Injection
Asynchronous Processing
async/awaitPromise.all() for independent operations, Promise.allSettled() when partial failure is acceptableEnvironment Variables
process.env directly in business logic — always go through config layer// ✅ Centralized, validated config
const config = {
port: parseInt(process.env.PORT || '3000', 10),
dbUrl: requiredEnv('DATABASE_URL'),
redisUrl: process.env.REDIS_URL || 'redis://localhost:6379',
} satisfies AppConfig
function requiredEnv(key: string): string {
const value = process.env[key]
if (!value) throw new Error(`Missing required environment variable: ${key}`)
return value
}
Security
Format Rules
PascalCase, variables/functions in camelCase@/, @app/, etc.)Clean Code Principles
console.log()Absolute Rule: Error suppression prohibited. All errors must have log output and appropriate handling.
Layered Error Handling (Backend)
Three distinct layers, each with specific responsibilities:
API Layer (Controllers/Middleware)
Service Layer (Business Logic)
Repository Layer (Data Access)
// ✅ Layered error handling
// Repository layer
async findById(id: string): Promise<User> {
const user = await this.repository.findOne({ where: { id } })
if (!user) throw new NotFoundError(`User not found: ${id}`)
return user
}
// Service layer
async updateUser(id: string, dto: UpdateUserDto): Promise<User> {
const user = await this.userRepository.findById(id) // Throws NotFoundError
Object.assign(user, dto)
return this.userRepository.save(user)
}
// Controller layer (NestJS exception filter handles mapping)
@Put(':id')
async update(@Param('id') id: string, @Body() dto: UpdateUserDto): Promise<UserResponseDto> {
return this.userService.updateUser(id, dto)
}
Fail-Fast Principle: Fail quickly on errors to prevent continued processing in invalid states
// ✅ Required: Explicit failure
catch (error) {
logger.error('Processing failed', { error, context })
throw error
}
Custom Error Classes
export class AppError extends Error {
constructor(message: string, public readonly code: string, public readonly statusCode = 500) {
super(message)
this.name = this.constructor.name
}
}
// Purpose-specific: ValidationError(400), NotFoundError(404), ConflictError(409), ApiError(502)
Structured Logging
console.logStream Processing
pipeline() over .pipe() for proper error handling and cleanupimport { pipeline } from 'stream/promises'
// ✅ Stream large file processing
await pipeline(
createReadStream('input.csv'),
new CsvParser(),
new TransformStream(),
createWriteStream('output.json'),
)
Memory Leak Prevention
onModuleDestroy)WeakMap/WeakRef for caches that should not prevent garbage collectionBasic Policy
Implementation Procedure: Understand Current State → Gradual Changes → Behavior Verification → Final Validation
Priority: Duplicate Code Removal > Large Function Division > Complex Conditional Branch Simplification > Type Safety Improvement