40 lines
1.7 KiB
Plaintext
40 lines
1.7 KiB
Plaintext
---
|
|
description: ERP backend core stack, security, and API conventions
|
|
alwaysApply: true
|
|
---
|
|
|
|
# ERP Backend — Core Conventions
|
|
|
|
Stack: Node.js 20+ · Express (CommonJS) · PostgreSQL 15+ · Prisma · Joi · Winston
|
|
|
|
## Non-negotiables
|
|
|
|
- CommonJS only (`require` / `module.exports`) — no ESM
|
|
- Validate all env vars on boot via `src/config/env.js`; refuse to start if invalid
|
|
- Never commit `.env`; only `.env.example`
|
|
- All protected routes: `authenticate` → `authorize(module, action)` → `validate(schema)` → controller
|
|
- Soft delete: filter `deleted_at: null`; set `deleted_at = now()` instead of hard DELETE
|
|
- Every mutation calls `auditLog({ tableName, recordId, action, oldValue, newValue, userId, requestId })`
|
|
- Controllers return `ApiResponse`; throw `ApiError` for failures — no Prisma or business logic in controllers
|
|
- Serialize `BigInt` as strings in JSON (`BigInt.prototype.toJSON`)
|
|
|
|
## Response envelope
|
|
|
|
```json
|
|
{ "success": true, "message": "...", "data": {}, "meta": { "page": 1, "limit": 20, "total": 57 } }
|
|
```
|
|
|
|
## Security
|
|
|
|
- JWT access (15m) in Bearer header; refresh tokens hashed (SHA-256) in DB, rotated on refresh
|
|
- bcrypt passwords; account lockout after failed attempts
|
|
- AES-256-GCM + HMAC blind index for PII (mobile, bank accounts) — encrypt in service layer
|
|
- Rate limit `/api` globally; stricter limit on auth routes
|
|
- File uploads: MIME allow-list, random filenames, serve via authenticated RBAC endpoint only
|
|
|
|
## API
|
|
|
|
- Routes under `/api/v1/`; pagination `?page=1&limit=20` (no upper cap on limit); dates ISO 8601 UTC
|
|
- RBAC actions: `view`, `create`, `edit`, `delete`, `approve`, `export`
|
|
- Reference: `BACKEND_SETUP.md`, task checklist: `BACKEND_TASKS.md`
|