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:startStop all containers:
npm run docker:stopRestart all containers:
npm run docker:restartRebuild application (our API) image + container (f.e after changing node_modules / .env files):
npm run docker:rebuild-appRemove all containers (for our project):
npm run docker:clean:containersRemove all images which aren't used by any existing container (dangling):
npm run docker:clean:dangling-imagesRemove all volumes which aren't used by any existing container (dangling):
npm run docker:clean:dangling-volumesRemove all dangling images & volumes, containers (for our project) and application docker image (our API):
npm run docker:clean:fullUsually you run application (with entire infrastructure) via:
npm run docker:startThen, 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-modeIn order to make previous step and run e2e tests:
npm run test:e2e:restartIn order to re-run E2E tests (being inside testing infrastructure):
npm run test:e2eThen, in order to come back to dev mode and continue developement:
npm run app:restart-in-dev-modeor
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), whereauthJwtRepositoryisIAuthJwtRepository<PrismaClient>). - Click
Go to implementation (CTRL + F12).
- Select the desired method which depends on type (f.e