Technical Stack • Features • Documentation • Quick start • Requirements • Docker help • E2E tests • Miscellaneous •
- Nest.js
- Prisma + Postgresql
- Redis (based on ioredis)
- Elasticsearch
- Winston + Logstash
- Passport.js, JWT, express-session + connect-redis
- Nest-access-control (attribute-based access control)
- Archiver (creating .zip archives)
- Pdfkit
- Nodemailer
- Zod / Class-validator
- Swagger
- Eslint & Prettier
- Docker
- Following to clean (onion) architecture
- UML diagram class (auth)
- Account system based on JWT tokens (with Passport.js):
- Signup (with email confirmation), Login, RefreshJwt, CreateRtSession, Logout
- Mantaining of multi sessions for one user (based on refresh tokens) + self cleaning of expired sessions (cron job)
- Several user roles with appropriate permissions (ABAC)
- Account system based on sessions (with Passport.js):
- Login, Logout
- Redis as storage for keeping active sessions
- Manual decorators for login and accessing protected endpoints (based on Passport.js)
- Operations for Certificate report (generate .pdf, get (as .pdf / .zip))
- Winston logging:
- Based on logstash transport implementation (ELK)
- Based on file transport implementation
- Based on only log-level transport implementation
- End-to-end logging (via Async Local Storage and traceId)
- Dto validation/transformation + Swagger:
- Based on Zod
- Based on Class-validator
- Save environment variables
- Customizable bootstrapping of application (
app.module.ts
) - Intergration tests:
- For Redis, context, promise modules
- E2E tests:
- For auth usecases (jwt, sessions)
- For certificate usecases
- For cache module
- Redis based cache system (cache wrapper module, cache bucket + invalidating, manual auto-caching decorator)
- Custom reliable Eslint & Prettier configs
- Seed, creating and restoring backup scripts for database
- Dockerization of the application
- Gathering metrics & analytics (Clickhouse(?), Prometheus, Grafana)
- Stress testing RPS/TRPS (with Ddosify)
- CI/CD gitlab
-
docs/explanation-architecture.md
- explanation of clean architecture (a version of which we follow in this application). -
docs/elk/*
- ELK explanation + guide how to watch logs. -
docs/references/*
- Clean and hexagonal architecture schemas. -
docs/abstract-sertificate.simplified-class-diagram.png
- simplified class diagram for abstract sertificate usecase (in accord to clean architecture). -
docs/auth.class-diagram.pdf
- class diagram for auth (login usecase).
- Clone this repository:
git clone [email protected]:js/architecture-patterns/backend-nestjs-update.git
- Install dependencies:
cd backend-nestjs-update && pnpm i
- Run docker containers:
docker-compose -f docker-compose.local.yml up
-
It requires Node.js >= 18.0.0.
In order to check current Node.js version:
node -v
In order to change Node.js version use nvm:
nvm install 18 && nvm use 18
-
It requires pnpm package manager.
In order to install it use:
npm install -g pnpm
Run all containers:
npm run docker:start
Stop all containers:
npm run docker:stop
Restart all containers:
npm run docker:restart
Rebuild application (our API) image + container (f.e after changing node_modules
/ .env files
):
npm run docker:rebuild-app
Remove all containers (for our project):
npm run docker:clean:containers
Remove all images which aren't used by any existing container (dangling):
npm run docker:clean:dangling-images
Remove all volumes which aren't used by any existing container (dangling):
npm run docker:clean:dangling-volumes
Remove all dangling images & volumes, containers (for our project) and application docker image (our API):
npm run docker:clean:full
Usually you run application (with entire infrastructure) via:
npm run docker:start
Then, in order to switch from dev database to test one and restart application container with testing env variables
(without running Nest.js server itself):
npm run app:restart-in-test-mode
In order to make previous step and run e2e tests:
npm run test:e2e:restart
In order to re-run E2E tests (being inside testing infrastructure):
npm run test:e2e
Then, in order to come back to dev mode and continue developement:
npm run app:restart-in-dev-mode
or
npm run docker:restart
- Since we use a lot of types in DI (instead of real attaching of implemenation) it can be extremely inconvenient to look for real implementation of injected interface in constructor (being within a class itself).
In order to solve this problem:
- Select the desired method which depends on type (f.e
this.authJwtRepository.findUserByEmail(email)
, whereauthJwtRepository
isIAuthJwtRepository<PrismaClient>
). - Click
Go to implementation (CTRL + F12)
.
- Select the desired method which depends on type (f.e