# Documentation 🤟

## Description :writing\_hand:&#x20;

TeanJS is a starter that provides you all the keys to be able to start writing your code as quickly as possible :rocket:&#x20;

## Built with :hammer:&#x20;

* [***NestJS 6***](https://nestjs.com/) - *The server framework used*
* [***ng-universal***](https://github.com/nestjs/ng-universal) ***-** Nestjs module to work with Angular universal (SSR)*
* [***Angular 8***](https://angular.io/) *- The client framework used*
* [***TypeORM***](https://github.com/typeorm/typeorm) *(in association with* [***@nestjs-typeorm***](https://github.com/nestjs/typeorm)*) - Database management*
* [***P*****assport**](http://www.passportjs.org/) *(in association with* [***@nestjs-p*****assport**](https://github.com/nestjs/passport) and [**@nestjs-jwt**](https://github.com/nestjs/jwt)*) - Authentication management*
* [***Jest***](https://jestjs.io/) *- A test framework for the client/server units tests*
* [***Jasmine*** ](https://jasmine.github.io/)*- A test framework for client side E2E*

## Prerequisites :robot:&#x20;

To be able to start the project right a way, the only thing you will have to do is update the server environments of your database in the file ***./server/environments/local/database.ts.***&#x20;

Then, your next action will be to run the following command `npm run migration:run`. This will result in the creation of your first ***users*** table base on the migration file located in the migrations directory ***./server/migrations***.

## Features

Often, when you start a new project, you will have a look on the existing start. But the major problem is that there is too many features that you don't need or not enough. So you have to deal with something you don't really want.

That's why, the amount of features in that starter stay limited (to avoid forcing you to use something you don't want) but enough to be ready to code.

### Server

For start, let see the modules available

{% tabs %}
{% tab title="Users" %}
The ***Users*** module provide you some basic features such as

* Create a new user
* Find a user by ***Id***

![UserController](https://3385411079-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LmR4APTy5yk7r7XwnPc%2F-LnYlwVqBn6L8DhShg1W%2F-LnYnKNzyoUSCM4O-q30%2FuserController.svg?alt=media\&token=431d8d5e-828d-41b4-a289-bcaf2aca3cd6)

To achieve that, you have in your possession a ***users.service.ts*** file that encapsulate the logic to manage the users.

You will find also a ***user.entity.ts*** that describe your users and along it, a custom ***user.repository.ts*** (will see that later) and a ***user.subscriber-entity.ts*** that separate the entity behavior logic from the entity itself. The subscriber as one purpose which is to ***hash/Salt*** the user password during the creation process.
{% endtab %}

{% tab title="Authentication" %}
The ***Authentication*** module provide you a uniq feature

* Login into your api

![AuthController](https://3385411079-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LmR4APTy5yk7r7XwnPc%2F-LnYlwVqBn6L8DhShg1W%2F-LnYnUO01ts3txNc8IvJ%2FAuthController.svg?alt=media\&token=2afc24e3-6627-4565-85c4-c1c0b0c97f3f)

It's a simple module which enforce the login through a ***email/password*** credentials which will be validated by the ***localStrategy***. Then, after the credentials validation, a ***token*** will be set in a cookie a return to the client.

To enforce the security, the ***JwtStrategy*** will protect all the routes that needs to be protected. So, the ***auth.service.ts*** will have only two goal, ***validateUser*** and ***login*** which create a token and return it.
{% endtab %}
{% endtabs %}

Beside these modules, the ***common*** directory comes with some useful features

{% tabs %}
{% tab title="Decorators" %}

## EntityNotFoundExceptionHandler

These decorator only wrap a method that use TypeORM to make some action. If that action result in an error of type ***EntityNotFound*** it will catch it and redirect that error as an ***EntityNotFoundException*** which will be handle by a custom filter. It's an example that show how to handle error and unified them to get a common error output. &#x20;

![EntityNotFoundExceptionHandler example](https://3385411079-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LmR4APTy5yk7r7XwnPc%2F-LnYe6ecAcRMHh3woqF7%2F-LnYkI0qAnf9jbpURG9R%2FEntityNotFoundExceptionHandleExample.svg?alt=media\&token=f4a3d86e-9047-40a9-a8ed-d4eb09e7a5dd)

## LoggedInUser

When a user has been logged in your api, you will have it ready on your ***Request*** object. This decorator is made to be able to grab it into your controller method as an argument.

![LoggedInUser example](https://3385411079-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LmR4APTy5yk7r7XwnPc%2F-LnYe6ecAcRMHh3woqF7%2F-LnYl7YPgBWtoWrSfF7N%2FLogedInUserDecoratorExample.svg?alt=media\&token=558c7418-e9fa-4302-a89f-32c1b85f3c72)

It's the perfect example of usage of customDecorator in NestJS.
{% endtab %}

{% tab title="Exceptions" %}
As describe in the decorator tab, we have a ***EntityNotFoundExceptionHandler*** which handle and throw ~~a~~ ***EntityNotFoundException***. The purpose of that exception is to be filtered in a custom filter (see next tab).

![Custom exception](https://3385411079-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LmR4APTy5yk7r7XwnPc%2F-LnYlwVqBn6L8DhShg1W%2F-LnYmB8c1XfYd_RM4qIf%2FEntityNotFoundException.svg?alt=media\&token=99fb97a6-7e69-4362-aa20-1bbd558def15)
{% endtab %}

{% tab title="Filters" %}

## BadRequestExceptionFilter

These filter is in charge to handle ***badRequestException*** and unified the output as well as the log

![BadRequestionExceptionFilter](https://3385411079-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LmR4APTy5yk7r7XwnPc%2F-LnYlwVqBn6L8DhShg1W%2F-LnYmjprm1rEsQblXdjH%2FbadExceptionFilter.svg?alt=media\&token=97192db1-664f-440b-9c38-54083d7e912a)

## EntityNotFoundExceptionFilter

This filter has the same role as the previous one, but for the ***EntityNotFoundException**.* of course the output is unified and is the same as the previous filter.

![EntityNotFoundExceptionFilter](https://3385411079-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LmR4APTy5yk7r7XwnPc%2F-LnYlwVqBn6L8DhShg1W%2F-LnYn9wfetrBC0oWT4XN%2FEntityNotFoundExceptionHandler.svg?alt=media\&token=242cff34-481f-47fc-9893-0d5453309d93)
{% endtab %}

{% tab title="TypeORM" %}
This common utilities will bring two features.

First it will add the ***SoftDeletable*** concept to the table. To achieve that, you will be able to extends the ***SoftDeletableEntity*** that will add the ***deletedAt*** column to your entity.

![SoftDeletableEntity](https://3385411079-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LmR4APTy5yk7r7XwnPc%2F-LnYlwVqBn6L8DhShg1W%2F-LnYoMqMQPVaoaxxtZ4v%2FSoftDeletableEntity.svg?alt=media\&token=b1e4b2e8-cb8a-4a60-8081-3dc216c22e1c)

But since it's not a feature of TypeORM, the ***user.respository.ts*** (located in the users module) extends the ***TransactionalSoftDeletableRepository*** which extends it self the ***TransactionalRepository*** (that we will see later).

The only purpose of th&#x65;***TransactionalSoftDeletableRepository*** is to bring two more methods which are

* softDelete
* softRemove

These methods act the same as ***delete and remove*** except that they will update the entities by updating the ***deletedAt*** column of our ***softDeletableEntity***. Also, the usual method to find an entity will take in count by default, to only find the entity non deleted. To include the deleted entities, you can pass the ***force*** parameter in the options.

![Find deleted entities](https://3385411079-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LmR4APTy5yk7r7XwnPc%2F-LnYqcoA_dAZzgV4l5vr%2F-LnYr05AsQphvYH0uuzA%2FfindDeletedEntities.svg?alt=media\&token=d39faa44-3221-45d4-81b2-7731c4883ef7)

But why a ***TransactionalRepository*** ?

Because when it comes to use transaction, you often have to pass the transaction to another method else where. Except that it's a manager in typeORM. In other words, th&#x65;***TransactionalRepository*** only override the usual method of typeORM but let you be able to pass or not the ***EntityManager*** in charge of your transaction. That way, you will not be afraid anymore to use transaction and pass them through your layers.
{% endtab %}
{% endtabs %}

## Environments :gear:&#x20;

### Server&#x20;

All the environments for the server are stored in the ***./server/environments***. In that directory there is the root files used in the application (e. g. to setup the database connection) and the ***local*** directory where you will be able to set the default values of all the environment configurations. That way, you can have a generic configuration file that will use the ***env*** variables if possible or the default values provided by the files situated in the ***local*** directory.

{% hint style="danger" %}
In the ***.gitignore*** file, there is the following statement: ***# /server/environments/local/***

Please remove the ***#*** to avoid pushing your password and other sensitive environment configurations anywhere. ***You must never push your ./server/environments/local directory at any point.***
{% endhint %}

## ***Scripts*** :satellite\_orbital:

&#x20;Here is a non exhaustive list of the main commands available:

| Scripts                                     | Descriptions                                              |
| ------------------------------------------- | --------------------------------------------------------- |
| `npm run lint`                              | To lint and format code (used in pre-commit hook as well) |
| `npm run test:unit:server`                  | Run the server side unit tests                            |
| `npm run test:e2e:server`                   | Run the server side e2e tests                             |
| `npm run test:server`                       | Run all the server side tests                             |
| `npm run test:unit:client`                  | Run the client side unit tests                            |
| `npm run test:e2e:client`                   | Run the client side unit tests                            |
| `npm run test:client`                       | Run all the client side tests                             |
| `npm run migration:create {migration name}` | Create a new migration file ***(./server/migrations)***   |
| `npm run migration:run`                     | Apply migrations                                          |
| `npm run migration:revert`                  | Revert migrations                                         |
| `npm run build:client`                      | Build client side                                         |
| `npm run build:server`                      | Build server side                                         |
| `npm run build:ssr`                         | Build client and server                                   |
| `npm run start:client`                      | Start client only                                         |
| `npm run start:prod`                        | Start all the project using SSR                           |
| `npm run start:dev`                         | Start SSR using ng-universal ***LiveReloadCompiler***     |
