-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnode-express-ts.mdc
More file actions
101 lines (83 loc) · 7.27 KB
/
Copy pathnode-express-ts.mdc
File metadata and controls
101 lines (83 loc) · 7.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
---
description: Typed Express handlers, validation middleware, and proper error propagation patterns.
globs: ""
alwaysApply: true
---
## File Structure and Organization
- All route handlers must live in `src/routes/` with one file per resource: `src/routes/users.ts`, `src/routes/products.ts`
- All business logic must live in `src/services/` with one file per domain: `src/services/UserService.ts`, `src/services/ProductService.ts`
- All database queries must live in `src/repositories/` with one file per entity: `src/repositories/UserRepository.ts`
- All middleware must live in `src/middleware/` with descriptive names: `src/middleware/authMiddleware.ts`, `src/middleware/errorHandler.ts`
- All type definitions must live in `src/types/` with one file per domain: `src/types/user.ts`, `src/types/product.ts`
- All validation schemas must live in `src/validation/` with one file per resource: `src/validation/userSchema.ts`
- Never create `index.ts` files that export multiple unrelated things. Each file exports exactly one class or function as default, or a named export group of related items.
- `src/app.ts` must only instantiate Express and attach middleware. Route registration happens in `src/server.ts`.
- `src/server.ts` must only start the HTTP server and register routes. No business logic.
## TypeScript and Type Safety
- Every function parameter must have an explicit type annotation. No implicit `any`.
- Every function must have an explicit return type annotation. No implicit return type inference.
- Never use `as` type assertions outside of test files. Use type guards with `if (x instanceof Y)` or Zod `.parse()` instead.
- All object literals passed to functions must match a named interface. No inline object types.
- `req.body` must be validated with Zod before use. Store validated result in a new variable: `const validated = userSchema.parse(req.body)`.
- `req.query` and `req.params` must be validated with Zod before use.
- Never use `any` type. Use `unknown` and narrow with type guards if needed.
- All Express route handlers must have explicit types: `(req: Request, res: Response, next: NextFunction): void => {}`
## Error Handling
- Every async function must have try/catch. Caught errors must be typed: `catch (err: unknown) { if (err instanceof AppError) ... else if (err instanceof ZodError) ... }`
- Never catch errors and do nothing. Every catch block must either re-throw or call `next(err)`.
- Never return raw error messages to the client. Create `src/errors/AppError.ts` with a class that has `statusCode`, `message`, and `code` properties.
- All errors thrown from services must be instances of `AppError` or a subclass. Never throw plain strings or Error objects.
- Error middleware must be registered last: `app.use(errorHandler)` after all other middleware and routes.
- Error middleware must catch errors with signature `(err: unknown, req: Request, res: Response, next: NextFunction): void => {}` and respond with `{ code: string, message: string }` JSON only.
- Never log full error objects to the client. Log to console/logger in error middleware, respond with sanitized message.
- All Promise rejections must be caught. Use `.catch(next)` on route handlers or wrap in try/catch.
## Express Route Handlers
- Every route handler must call `next(err)` when passing errors to middleware, never `throw` in async handlers without try/catch.
- Route handlers must not be async unless they contain `await`. If async, must have try/catch wrapping all awaits.
- All route handlers must validate input before using it: `const data = userSchema.parse(req.body)`.
- Route handlers must return status codes explicitly: `res.status(201).json(data)`, never `res.json(data)` without status.
- Route handlers must not call database functions directly. Call service layer methods instead.
- Route handlers must not contain business logic. Delegate to services in `src/services/`.
- All route handlers must have JSDoc comments describing parameters and return: `/** POST /users - Create a user. Returns 201 with user object. */`
## Validation and Input Security
- All user input must be validated at the route handler level before passing to services.
- Validation schemas must live in `src/validation/` and be imported into route handlers.
- Use Zod for all validation: `import { z } from 'zod'`.
- Never trust `req.headers`, `req.query`, `req.params`, or `req.body` without validation.
- Validation schemas must explicitly define allowed fields: `z.object({ name: z.string(), age: z.number() }).strict()`.
- Never use `.passthrough()` on Zod schemas. Use `.strict()` to reject unknown fields.
- All string inputs must have `.min()` and `.max()` length constraints in Zod schemas.
- All numeric inputs must have `.min()` and `.max()` value constraints in Zod schemas.
- Email fields must use `.email()` in Zod schemas.
- Never interpolate user input into SQL queries. Use parameterized queries or an ORM.
## Code Style and Naming
- Use `const` exclusively. Never use `let` or `var`.
- All class names must be PascalCase: `UserService`, `ProductRepository`.
- All function names must be camelCase: `getUserById`, `createProduct`.
- All file names must be camelCase except classes which are PascalCase: `userService.ts`, `UserService.ts`.
- All constants must be UPPER_SNAKE_CASE: `MAX_RETRY_ATTEMPTS`, `DEFAULT_TIMEOUT_MS`.
- All private class methods must be prefixed with `#`: `#validateUser()`.
- All private class properties must be prefixed with `#`: `#db`.
- Never use function declarations. Use arrow functions or class methods only.
- All imports must be at the top of the file, grouped: Node modules, then local modules, then types.
## Testing
- All test files must live in `src/__tests__/` with the same directory structure as source: `src/__tests__/services/UserService.test.ts`.
- Test file names must match source file names with `.test.ts` suffix: `UserService.test.ts`.
- All services must have unit tests. Minimum: happy path, error case, validation failure.
- All route handlers must have integration tests. Minimum: 200 response, 400 validation error, 500 error handling.
- Never mock the database in route handler tests. Use a test database or in-memory store.
- All tests must use `describe()` and `it()` blocks with clear names: `describe('UserService', () => { it('should create a user with valid data', () => {}) })`.
- Never use `any` in test files either. Type all test data.
## Forbidden Patterns
- Never use `require()`. Use `import` statements only.
- Never use `console.log()` in production code. Use a logger instance: `logger.info()`, `logger.error()`.
- Never hardcode secrets, API keys, or database URLs. Use environment variables with `process.env.VARIABLE_NAME`.
- Never use `setTimeout()` for delays in production code. Use proper async patterns or job queues.
- Never export multiple unrelated functions from one file. One export per file or a cohesive group.
- Never use default exports for classes or services. Use named exports: `export class UserService {}`.
- Never mutate function parameters. Create new objects instead.
- Never use `Object.any()` or `Object.all()`. Use explicit loops or `.map()`, `.filter()`.
---
> Source: [Codelibrium](https://codelibrium.com) — the marketplace for AI behaviour files.
> Browse multiple rulesets at [codelibrium.com](https://codelibrium.com) or install via CLI:
> `npx codelibrium-cli install <ruleset-name>`