Secure, modular NestJS backend for authentication, RBAC, billing accounts, and locked fund transfers. The project follows SOLID principles, uses TypeORM migrations, stores JWT access and refresh tokens in HTTP-only cookies, and exposes OpenAPI documentation through Swagger.
- NestJS modular architecture with separation across auth, users, accounts, transactions, roles, and webhooks
- PostgreSQL persistence with TypeORM entities, explicit migrations, and
synchronize: false - JWT access and refresh tokens delivered through HTTP-only cookies
- Global
RolesGuard,AccessTokenGuard, andActiveUserGuard - Pessimistic row locking for transfers to prevent concurrent balance corruption
- Reusable pagination DTO for transaction listing
- Async webhook delivery after completed transfers
- Bootstrap seeding for default roles and an admin user
- Swagger/OpenAPI 3.0 docs with decorated DTOs
- Docker multi-stage image and
docker-composeorchestration
src
├── app.module.ts
├── common
│ ├── constants
│ ├── decorators
│ ├── dto
│ ├── filters
│ ├── guards
│ ├── interfaces
│ └── utils
├── config
├── infrastructure
│ └── database
│ ├── migrations
│ └── seed
└── modules
├── accounts
├── auth
├── roles
├── transactions
├── users
└── webhooks
- Create environment variables.
cp .env.example .env- Install dependencies.
npm install- Run migrations.
npm run migration:run- Start the app in development mode.
npm run start:dev- Open Swagger.
http://localhost/docs
- Prepare the environment file.
cp .env.example .env- Build and start the stack.
docker compose up --buildThe app container runs compiled migrations on startup before launching the API.
This behavior is controlled by AUTO_RUN_MIGRATIONS=true.
With the reverse proxy enabled in docker-compose.yml, the API is available through nginx at:
http://localhost
Swagger is available at:
http://localhost/docs
Using nginx as a reverse proxy keeps the public entry point stable and aligns the stack with common scalability and security practices.
npm run build
npm run lint
npm run lint:fix
npm run format
npm run format:check
npm run migration:create
npm run migration:generate
npm run migration:run
npm run migration:revert
npm run seed- Roles:
Admin,Client - Admin email:
admin@example.com - Admin password:
Admin12345! - Admin initial balance:
1000.00
Override these values in .env for real environments.
POST /api/auth/registerregisters a client user and creates a billing accountPOST /api/auth/loginissues access and refresh cookiesPOST /api/auth/refreshrotates the cookie pair using the refresh tokenPOST /api/auth/logoutclears auth cookiesGET /api/users/mereturns the current userPATCH /api/users/:id/activeallows admins to activate or deactivate a userGET /api/accounts/mereturns the authenticated user's billing accountPOST /api/transactions/transfertransfers funds with pessimistic lockingGET /api/transactionsreturns paginated transactions for admins
Transfers are implemented with:
- a persisted pending transaction row
- a database transaction on the balance update path
- deterministic account locking order
pessimistic_writelocks on both account rows- rollback on failure plus status transition to
Canceled
Balances are stored as bigint minor units in PostgreSQL and exposed as two-decimal strings in API responses to avoid floating-point errors.