You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Shared infrastructure (middleware, guards, decorators) lives in its own top-level directory.
Decorator Usage
// ✅ Controllers: declare route prefix and apply Swagger tags
@ApiTags('treasury')
@Controller('treasury')exportclassTreasuryController{// ✅ Route methods: declare HTTP verb, path, and Swagger metadata
@ApiOperation({summary: 'Get treasury balance'})
@ApiResponse({status: 200,description: 'Current balance'})
@Get('balance')getBalance(){ ... }// ✅ Write endpoints protected by guard — use @Public() to opt out
@Post('propose')propose(@Body()dto: ProposeDto){ ... }}
Always annotate controllers and routes with Swagger decorators (@ApiTags, @ApiOperation, @ApiResponse).
Use @Public() to mark endpoints that should bypass the global ApiKeyGuard.
Inject services via constructor, not property injection.
Zod Validation
Define all input schemas with Zod in the service or a dedicated *.schema.ts file.
Parse at the service boundary, not in the controller.
import{z}from'zod';constProposalSchema=z.object({contractId: z.string().min(1),limit: z.number().int().positive().max(100).optional(),});// In the service:constparams=ProposalSchema.parse(raw);
Never trust raw query/body values without parsing them through a Zod schema.
Use z.coerce.number() for numeric query params (they arrive as strings in Express).
Database Query Patterns
Interact with Postgres through the Pool from src/db.ts — never create a new Pool directly inside a service.
Prefer parameterised queries; never interpolate user input into SQL strings.
// ✅ Good: parameterisedconstresult=awaitpool.query('SELECT * FROM events WHERE contract_id = $1 ORDER BY id DESC LIMIT $2',[contractId,limit],);// ❌ Bad: SQL injection riskconstresult=awaitpool.query(`SELECT * FROM events WHERE contract_id = '${contractId}'`,);
Wrap multi-statement operations in a transaction (BEGIN / COMMIT / ROLLBACK).
Keep query logic in the service layer; controllers only validate, delegate, and format responses.
📝 General Rules
No commented-out code in commits.
No console.log in production code (use proper logging).
Write tests for all new functions.
Document public APIs with JSDoc (TS) or /// doc comments (Rust).
Keep functions small — aim for single responsibility.