Skip to content

Latest commit

 

History

History
107 lines (88 loc) · 7.28 KB

File metadata and controls

107 lines (88 loc) · 7.28 KB

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 put more than one exported function per file in src/middleware/
  • Never put route definitions in src/index.ts — import and mount them only
  • Test files must live in tests/ mirroring source structure: tests/services/UserService.test.ts

Naming Conventions

  • Route files use lowercase plural: users.ts, products.ts, never User.ts or user-routes.ts
  • Service files use PascalCase with Service suffix: UserService.ts, ProductService.ts, never userService.ts
  • Repository files use PascalCase with Repository suffix: UserRepository.ts, never user-repo.ts
  • Middleware files use camelCase with Middleware suffix: authMiddleware.ts, errorHandler.ts
  • Type files use lowercase: user.ts, product.ts, never User.ts or types.ts
  • Express Router instances must be named router: const router = express.Router()
  • Never use var — use const for all declarations, let only when reassignment is required
  • Function names in services must be verb-first: getUserById(), createUser(), updateUserEmail(), never getUser() or user()

Type Safety and Validation

  • Every Express route handler signature must be: (req: Request, res: Response, next: NextFunction) => Promise<void>
  • req.body must be validated with Zod before any use: const data = userSchema.parse(req.body)
  • req.params must be validated with Zod before any use: const { id } = paramsSchema.parse(req.params)
  • req.query must be validated with Zod before any use: const { page } = querySchema.parse(req.query)
  • Never access req.body, req.params, or req.query without prior Zod validation in the same function
  • Never use any type — use unknown and type guard it, or use a specific type
  • Never use as type assertions outside of test files — use Zod .parse() or type guards instead
  • All function parameters must have explicit types, never rely on inference
  • All function return types must be explicit, never use implicit any returns

Error Handling

  • Create src/types/errors.ts with an AppError class extending Error with statusCode: number and code: string properties
  • All thrown errors must be instances of AppError, never Error or new Error()
  • Every async route handler must have try/catch: try { ... } catch (err) { next(err) }
  • Catch blocks must type-guard errors: catch (err) { if (err instanceof AppError) { ... } else { next(err) } }
  • Error middleware must be the last middleware registered in src/index.ts
  • Error middleware must never send raw err.message to client — send err.code and err.statusCode only
  • Never log full error objects to client responses — log to server console only
  • All database errors must be caught and converted to AppError with appropriate statusCode and code
  • 404 errors must use statusCode: 404 and code: 'NOT_FOUND'
  • Validation errors must use statusCode: 400 and code: 'VALIDATION_ERROR'
  • Authentication errors must use statusCode: 401 and code: 'UNAUTHORIZED'
  • Authorization errors must use statusCode: 403 and code: 'FORBIDDEN'

Security

  • Never hardcode secrets in any file — all secrets must come from environment variables via process.env
  • Create src/config/env.ts that validates all required env vars at startup using Zod
  • Application must fail to start if any required env var is missing
  • Never log process.env or any secret values to console or error responses
  • All user input from req.body, req.params, req.query must be validated before database queries
  • SQL queries must use parameterized queries only — never string concatenation
  • Never return database error messages to clients — wrap in AppError with generic message
  • Authentication tokens must be validated on every protected route using middleware
  • Protected routes must check req.user exists before proceeding — never assume middleware ran

Express Configuration

  • src/index.ts must only contain: app creation, middleware registration, route mounting, error handler, and server start
  • Middleware must be registered in this order: body parser, auth, routes, 404 handler, error handler
  • Use express.json() with explicit size limit: express.json({ limit: '10kb' })
  • Use express.urlencoded() with explicit size limit: express.urlencoded({ limit: '10kb', extended: true })
  • All routes must be mounted with explicit path prefix: app.use('/api/users', userRoutes)
  • Never use app.get(), app.post() directly in src/index.ts — define in route files only
  • 404 handler must be registered before error handler: app.use((req, res) => res.status(404).json({ code: 'NOT_FOUND' }))

Service and Repository Patterns

  • Every Service class must have a constructor that accepts its Repository as a dependency
  • Services must never import database drivers directly — only use Repository methods
  • Repositories must be the only files that import database drivers or query builders
  • Service methods must return typed objects, never raw database rows
  • Service methods must catch database errors and throw AppError instances
  • Repositories must return null for not-found queries, never throw
  • Services must check for null returns and throw AppError with statusCode: 404

Testing

  • Test files must use .test.ts extension: UserService.test.ts, never .spec.ts
  • Every Service class must have a corresponding test file with 100% function coverage
  • Every route handler must have a corresponding integration test
  • Mock all Repository dependencies in Service tests using Jest mocks
  • Mock all Service dependencies in route handler tests
  • Never test database directly in unit tests — use Repository mocks
  • Test error cases explicitly: test that AppError is thrown with correct statusCode and code

Exports and Imports

  • Use named exports only: export const getUserById = () => {}, never export default
  • Import statements must be grouped: Node modules, then local modules, then types
  • Type imports must use import type: import type { User } from '../types/user'
  • Never use wildcard imports: import * as users from './users' — import specific exports only
  • All exports from route files must be the Router instance: export const router
  • All exports from Service files must be the class: export class UserService
  • All exports from Repository files must be the class: export class UserRepository

Source: Codelibrium — the marketplace for AI behaviour files. Browse multiple rulesets at codelibrium.com or install via CLI: npx codelibrium-cli install <ruleset-name>