Nestjs 2muchcoffee
Skill 2muchcoffeecom/nestjs-manifesto/.claude/skills/nestjs-2muchcoffee
The 2muchcoffee NestJS engineering manifesto plus drop-in agent skill files for Claude Code, Cursor, and Codex.
npx -y skills add 2muchcoffeecom/nestjs-manifesto --skill nestjs-2muchcoffeeAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when writing, refactoring, or reviewing NestJS code. Enforces 2muchcoffee engineering standards for backend NestJS work: modular architecture under src/modules, dependency injection, strict typing, thin controllers, DTO validation, REST verb conventions, explicit HTTP status codes, centralized error handling with HttpException, security guards, stateless token auth, pagination and caching, Jest tests for services and endpoints. Refuses to write any types, commit .env files, or bypass module boundaries. Pulls in conventions for project structure, REST API design, security, and testing.
SKILL.md
6.6 KB, as published. Nobody here has run it
NestJS Standards (2muchcoffee Manifesto)
Trigger this skill any time you are writing, refactoring, or reviewing NestJS code. Apply the rules below in the order they appear: architecture decisions first, structural decisions second, code-level decisions last.
Architecture rules
- Modularization first. Every domain is a NestJS module under
src/modules/<feature>/. Think in features, not layers. - Dependency injection everywhere. Never
newup a service or repository inside another service. Inject through the constructor. - Convention over configuration. Follow NestJS defaults unless you can justify the deviation.
- Strict typing.
tsconfig.jsonmust have"strict": true. Refuse to writeany. If the type cannot be inferred, define an explicit type. - Declarative. Prefer NestJS decorators over imperative plumbing.
Project structure
When generating a new module or moving files, the layout must look like this:
src/
├── modules/
│ ├── <feature>/
│ │ ├── <feature>.controller.ts
│ │ ├── <feature>.service.ts
│ │ ├── dto/
│ │ ├── entities/
│ │ └── <feature>.module.ts
│ └── shared/
│ ├── decorators/
│ ├── validators/
│ ├── middlewares/
│ ├── classes/
│ └── shared.module.ts
├── app.module.ts
└── main.ts
SharedModule is the only cross-module export point. Do not import internals from one feature module into another.
Controllers
- Keep controllers thin. They delegate to services.
- Use REST verb decorators:
@Post,@Get,@Put,@Patch,@Delete. - Use explicit
@HttpCodewhen the response is not 200 by default.
Example:
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() dto: CreateUserDto) {
return this.userService.create(dto);
}
@Get()
list(@Query() query: PaginationDto) {
return this.userService.list(query);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id') id: string) {
return this.userService.remove(id);
}
}
DTOs and validation
Every controller input goes through a DTO using class-validator and class-transformer. Apply the global ValidationPipe in main.ts with whitelist: true and forbidNonWhitelisted: true.
export class CreateUserDto {
@IsString()
@Length(2, 100)
name: string;
@IsEmail()
email: string;
}
For enums, define and reuse them. Do not pass magic strings.
export enum UserRole {
ADMIN = 'admin',
USER = 'user',
}
Services
- Business logic lives here.
- Inject repositories and other services through the constructor.
- Use
async/await. Do not chain.then(). - Public methods should have a single responsibility and a clear name.
Error handling
- Throw
HttpExceptionsubclasses (BadRequestException,NotFoundException, etc.) for known errors. - Never throw plain
Errorfrom a controller or service. - Register a global exception filter to shape responses consistently.
- Never include stack traces, internal error messages, or DB error details in production responses.
@Catch(HttpException)
export class GlobalExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
response.status(exception.getStatus()).json({
statusCode: exception.getStatus(),
message: exception.message,
});
}
}
Security
- Always validate inputs. No exception.
- Apply auth guards globally where possible. Use route-level guards for finer scope.
- Use Helmet, an explicit CORS allowlist, and rate limiting on all public endpoints.
- Never commit
.env,.env.local,.env.*, or any file containing real secrets. If you see one in the diff, stop and ask the human. - Generate environment files from
.env.exampleper environment. - If you need a credential to test code, ask for a scoped or fake value. Do not paste real-looking credentials.
Authentication and authorization
- Stateless token auth.
- Separation of authentication (identity) from authorization (permissions).
- Access Token short-lived. Refresh Token long-lived and rotated.
- Centralize the auth check; do not duplicate it in every controller.
consumer.apply(AuthMiddleware).forRoutes('*');
app.useGlobalGuards(rolesGuard);
Performance and scalability
- Paginate every list endpoint. Default
limit20, maxlimit100. - Cache reads with Redis or in-memory caches when the data tolerates it.
- Avoid N+1 queries. Eager-load with
relationsor query builders. - Enable compression in
main.ts.
app.use(compression());
Testing
- Use Jest for unit and e2e.
- Mock dependencies with
@nestjs/testing. - Every public service method gets at least one unit test.
- Every API endpoint gets at least one e2e test that covers the happy path and one error path.
- If you generate code without the required tests, say so explicitly.
describe('UserService', () => {
let service: UserService;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [UserService],
}).compile();
service = module.get<UserService>(UserService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
Hard refusals
Refuse and explain when asked to:
- Use
anyto silence the compiler. - Commit
.envfiles or files containing real-looking secrets. - Disable validation pipes globally without a replacement guard.
- Bypass module boundaries by importing internals from another feature module.
- Add a service-level method without at least one unit test (unless the human has explicitly accepted the trade-off in the same turn).