{"id":13614249,"url":"https://github.com/shy2net/nestjs-angular-starter","last_synced_at":"2025-04-13T18:32:36.330Z","repository":{"id":44718399,"uuid":"296597791","full_name":"shy2net/nestjs-angular-starter","owner":"shy2net","description":"A starter template\\boilerplate to work with NodeJS (typescript), Angular (with SSR), and shared models.","archived":false,"fork":false,"pushed_at":"2024-08-16T07:45:19.000Z","size":1364,"stargazers_count":31,"open_issues_count":0,"forks_count":17,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-11-07T22:42:14.824Z","etag":null,"topics":["angular","boilerplate","nestjs","template","typescript"],"latest_commit_sha":null,"homepage":"https://nemex-studios.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shy2net.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-18T11:10:36.000Z","updated_at":"2024-11-05T08:10:44.000Z","dependencies_parsed_at":"2024-07-26T13:26:46.229Z","dependency_job_id":"8080218c-fc5e-46b9-ac7e-9eb11b537809","html_url":"https://github.com/shy2net/nestjs-angular-starter","commit_stats":null,"previous_names":[],"tags_count":0,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shy2net%2Fnestjs-angular-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shy2net%2Fnestjs-angular-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shy2net%2Fnestjs-angular-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shy2net%2Fnestjs-angular-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shy2net","download_url":"https://codeload.github.com/shy2net/nestjs-angular-starter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248760580,"owners_count":21157382,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","boilerplate","nestjs","template","typescript"],"created_at":"2024-08-01T20:00:58.841Z","updated_at":"2025-04-13T18:32:35.418Z","avatar_url":"https://github.com/shy2net.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","Angular"],"sub_categories":[],"readme":"- [Remarks](#remarks)\n- [Introduction](#introduction)\n  - [Prerequisites](#prerequisites)\n    - [All environments](#all-environments)\n    - [On Windows](#on-windows)\n    - [On Linux](#on-linux)\n- [Starting with this template](#starting-with-this-template)\n- [Template architecture](#template-architecture)\n  - [Angular 17](#angular-17)\n    - [Angular services \\\u0026 providers](#angular-services--providers)\n    - [Angular components](#angular-components)\n    - [Angular Universal (Server-Side-Rendering)](#angular-universal-server-side-rendering)\n  - [NodeJS](#nodejs)\n    - [Server entry-point (main.ts)](#server-entry-point-maints)\n    - [NestJS App Module](#nestjs-app-module)\n    - [How the API works](#how-the-api-works)\n      - [Working with API params](#working-with-api-params)\n    - [Database](#database)\n    - [Logging](#logging)\n    - [SSL (https support)](#ssl-https-support)\n    - [Authentication and roles](#authentication-and-roles)\n      - [Social Authentication](#social-authentication)\n    - [Environment configurations](#environment-configurations)\n      - [Use the configurations](#use-the-configurations)\n    - [Testing (Unit Tests\\\\API Tests)](#testing-unit-testsapi-tests)\n        - [Test database](#test-database)\n        - [Running the tests](#running-the-tests)\n  - [Sharing code (models, interfaces, etc)](#sharing-code-models-interfaces-etc)\n  - [Form validations](#form-validations)\n- [Running on production](#running-on-production)\n  - [The easiest way to run on production - Docker\\\\Docker-Compose](#the-easiest-way-to-run-on-production---dockerdocker-compose)\n    - [Docker-compose](#docker-compose)\n    - [Nginx as reverse proxy](#nginx-as-reverse-proxy)\n    - [Docker image build](#docker-image-build)\n  - [Building and compiling the code manually](#building-and-compiling-the-code-manually)\n    - [The build script (build.sh)](#the-build-script-buildsh)\n  - [Separating client and server](#separating-client-and-server)\n    - [Server as standalone](#server-as-standalone)\n    - [Angular as standalone](#angular-as-standalone)\n  - [Deploying our app on a new server using Ansible](#deploying-our-app-on-a-new-server-using-ansible)\n    - [Configuring Ansible for the first time](#configuring-ansible-for-the-first-time)\n    - [Deploying our infrastructure](#deploying-our-infrastructure)\n  - [Built in CI\\\\CD (Github Actions)](#built-in-cicd-github-actions)\n    - [Server preparations for CD to work](#server-preparations-for-cd-to-work)\n    - [Secrets required for the CD process](#secrets-required-for-the-cd-process)\n\n\n# Remarks\n\n\u003e This is the new starter template, which is based on the deprecated [\"nodejs-angular-starter\"](https://github.com/shy2net/nodejs-angular-starter) which is built on [TS.ed](https://tsed.io/). The reason the old library was deprecated is because NestJS is more documented and popular library, which has very much the same approach as Angular.\n\n\u003e This template is based on the exact same code for Angular, and most of the original template node code was reused and refactored to suit NestJS approach.\n\n\u003e This library still uses the same config approach and database approach as the old one. The reason for this, is that in my opinion, NestJS approach for mongo database and environment configuration makes the development more complicated then it should.\n\n# Introduction\n\nThis starter template\\boilerplate comes with NodeJS (typescript) and Angular 17. It shares models between Angular\nand NodeJS. Both of the NodeJS and and Angular 17 can run on the same webserver as the NodeJS exposes all of the\ndefault routes to Angular and all of the known routes to the api.\n\nTechnologies used in this template:\n\n- Angular 17 (with SSR) - including unit tests (based on Jasmine + Karma)\n- NodeJS express typescript (with SSL support) based on [NestJS](https://nestjs.com/) - for easier express setup using decorators\n- Mocha\\Chai for backend testing + API tests\n- Environment based configurations\n- Mongoose (with basic user model)\n- Logging (using [NestJS Logger](https://docs.nestjs.com/techniques/logger))\n- Bootstrap v4 and SCSS by default\n- [JWT](https://jwt.io/) and token authentication built-in (including user roles)\n- Social Authentication (Google and Facebook)\n- Form validations using ([class-validator](https://www.npmjs.com/package/class-validator)), shared between server and client\n- Docker support based on alpine and node 12\n- Support for Ansible to deploy our app easier\n- Nginx support as a reverse proxy (with SSL certificates)\n- Complete CI\\CD process based on Github Actions\n\n## Prerequisites\n\nIn order to start with this template you have to set up the environment you are working on to suit the needs.\n\n### All environments\n\nBecause this template uses mongo-db by default, if you want to run it easily out-of-the-box you must install docker,\nthen run the following command:\n\n```bash\ndocker-compose up -d db # Loads up an instance of mongo-db locally with root\\root (user\\pass) and 'admin' database\n```\n\nThis will create a simple mongo database with a username\\password of 'root' and database named 'admin'.\nThe mongo-db instance will create a volume mounted at: `~/web_mongo` (inside your user home directory)\nOptionally, you can connect to your own mongo-db instance by configuring it (read the config section for more).\n\n### On Windows\n\nMake sure to install [git bash](https://git-scm.com/downloads), this allows you to run `bash` commands which are essential for the build process. You can use any other bash for windows, as long as it can run the scripts this template relays on (`./install_all.sh, copy-essentials.sh, build.sh`).\n\n**Make sure to add bash to your system 'PATH'.**\n\n### On Linux\n\nAfter cloning this repository, make sure to run the following command:\n ```bash\n chmod +x ./scripts/*\n ```\n\nThis will give permission to run all required scripts to work with this template.\n\n# Starting with this template\n\nTo work with this template **locally (debug mode)**, follow these commands:\n\n    npm i -g @angular/cli # Install angular globally (some scripts depend on ng to be globally installed)\n    npm run install:all # Install all dependencies required for both NodeJS and Angular\n    npm run start:dev # Run the NodeJS on debug mode\n    npm run angular # Run Angular\n\nWe don't run the `npm start` command as it is reserved only for the compiled code to run on a production server.\n\nIn order to compile and build this template for your **production server** run the following:\n\n    npm run install:all # Install all dependencies required for both NodeJS and Angular\n    npm run build # Run the build.sh script to compile and NodeJS and Angular for production\n    npm start\n\nThese list of commands will install, compile and run the output NodeJS.\n\n# Template architecture\n\nThe template comes with a ready to go server and client integration, authentication and basic styling.\n\n## Angular 17\n\nAngular 17 comes with the following features:\n\n- Bootstrap v4 with header and sticky footer.\n- Built in SSR bundled with the api server.\n- Built in toasty (ngx-toastr) which automatically pops up on HTTP errors obtained from the server API.\n- Built in ngx-loading-bar (Youtube styled) when moving between routes.\n- Built in auth-guard and authentication, saved on session cookie.\n- Built in social authentication (Google and Facebook) - **Google and Facebook continually update their APIs, you might need to perform additional steps in order to make this template work with them**.\n- Build in form validations using class-validator (https://github.com/typestack/class-validator) implemented using the `FormValidatorDirective`.\n\nThe code of Angular 17 is stored under the `angular-src` directory.\n\n### Angular services \u0026 providers\n\nThis template comes with multiple services and proviers which can be used accross the template.\n\n- `ApiService` - This service wraps the access to the server api. It should contain a 'mirror' of the functions that the server has.\n- `AuthService` - This service exposes all of the authentication mechanisem and handles all of the login, including login to the api, obtaining the token and saving the token to a cookie for next refresh.\n- `AuthGuardService` - An auth guard which used the `AuthService` to guard routes. It also comes with role checking by specifing the `typescript { roles: ['roleName'] }` data for your route.\n- `AppHttpInterceptor` - This provider acts as an interceptor for all of the http requests ongoing. It adds the authentication token if provided by the `AuthService` to each request. Then it passes the request to the `RequestsService` to handle.\n- `RequestsService` - This service handles all of the requests passing through using the `AppHttpInterceptor`. It shows an error toast if an error had occured in one of the requests.\n- `AppService` - Holds information about the current user and app related data.\n- `SocialLoginService` - This service is responsible for the whole social authentication (Google and Facebook), it uses `angularx-social-login` module to do so. This service can be found under `social-login` module which initializes all of the providers (which are the 3rd party social sites).\n\n### Angular components\n\n- `AppComponent` - The app component is the bootstrap component of this template. It contain the HTML of the app (such the header, router-oulet and footer). It contains logic to listen to routing changes and showing or hiding the slim loading bar (Youtube styled routing progress bar).\n\n- `HeaderComponent` - The header part of the template. It shows a simple header based on bootstrap which is suitable for mobile as well.\n- `FooterComponent` - A simple sticky footer that always appear at the bottom of the page.\n- `LoginComponent` - A simple login with username and password which authenticates against the server.\n- `UserPageComponent` - A simple page that shows information about the currently logged in user with option of logging out.\n- `SocialLoginButton` - A simple container of social login buttons which also performs the social authentication itself.\n\n### Angular Universal (Server-Side-Rendering)\n\nBy default this template comes ready with Angular Universal which allows search engines to crawl your website better.\nIt does this on the NodeJS side after running the `npm run build` command which bundles the angular code and create an angular universal express ready file called `out/src/dist/server.js` which our NodeJS simply imports and initializes in the `src/app.ts` file.\n\nin the `src/misc/angular-mounter.ts` you have these two methods:\n\n```typescript\n/**\n * Mounts angular using Server-Side-Rendering (Recommended for SEO)\n */\nexport function mountAngularSSR(expressApp: express.Application): void {\n  // The dist folder of compiled angular\n  const DIST_FOLDER = path.join(process.cwd(), 'dist/angular');\n\n  // The compiled server file (angular-src/server.ts) path\n  // eslint-disable-next-line @typescript-eslint/no-var-requires\n  const ngApp = require(path.join(DIST_FOLDER, 'server/main'));\n\n  // Init the ng-app using SSR\n  ngApp.init(expressApp, path.join(DIST_FOLDER, '/browser'));\n}\n\n/**\n * Mounts angular as is with no SSR.\n */\nexport function mountAngular(expressApp: express.Application): void {\n  const DIST_FOLDER = path.join(process.cwd(), 'dist/angular/browser');\n  // Point static path to Angular 2 distribution\n  expressApp.use(express.static(DIST_FOLDER));\n\n  // Deliver the Angular 2 distribution\n  expressApp.get('*', function(req, res) {\n    res.sendFile(path.join(DIST_FOLDER, 'index.html'));\n  });\n}\n```\n\nBy default the mountAngular or mountAngularSSR is called in the init method of `src/main.ts`, in order\nto disable or enable SSR, change the related config called `ANGULAR \u003e USE_SSR` into true to enable SSR.\n\n## NodeJS\n\nComes with built in typescript support and compilation.\n\nIt comes with the following features:\n\n- [NestJS](https://nestjs.com/) - Easier express with typescript using decorators\n- Authentication (including route-guards and token generation)\n- Angular routes support (redirect to index.html of compiled Angular code), this means you can run you Angular app and API on the same container!\n- Configuration according to environment (using [config npm package](https://www.npmjs.com/package/config)).\n- Logging (using built-in NestJS logger).\n- Social Authentication, which basically gets an access token from the client that logged into a service and then creates a user associated with it.\n- Unit testing using Mocha\\Chai.\n\nThe code of NodeJS is stored under the `src` directory.\nOutput directory of the compiled typescript will be available in the `dist` directory.\n\n### Server entry-point (main.ts)\n\nBy default, NestJS creates a file called `src/main.ts`, this file is responsible of initializing the NestJS app.\n\nFirst, lets take a look at the file:\n\n```typescript\nasync function bootstrap() {\n  // Create the app and allow cors and HTTPS support (if configured)\n  const app = await NestFactory.create(AppModule, {\n    cors: config.CORS_OPTIONS,\n    // Will work only if SSH is configured on the related environment config, if not, normal HTTP will be used\n    httpsOptions: getHttpsOptionsFromConfig(),\n  });\n\n  // Use '/api' for general prefix\n  app.setGlobalPrefix('api');\n\n  // Allow validation and transform of params\n  app.useGlobalPipes(\n    new ValidationPipe({\n      transform: true,\n    }),\n  );\n\n  // If we are running on production, mount angular\n  if (config.ANGULAR.MOUNT) {\n    const expressApp = app\n      .getHttpAdapter()\n      .getInstance() as express.Application;\n\n    if (config.ANGULAR.USE_SSR) mountAngularSSR(expressApp);\n    else mountAngular(expressApp);\n  }\n\n  // Start listening\n  await app.listen(process.env.PORT || 3000);\n}\n\nbootstrap();\n```\n\nThe following code, does these 4 things:\n\n- Create the Nest app itself, with CORS support and HTTPS support, HTTPS will only work if environment configured 'SSL_CERTIFICATE' config correctly. CORS will use the configurations specified in the environment config called 'CORS_OPTIONS'.\n- Set the global prefix to `/api` to allow all requests to be transferred thorough there\n- Mount validation pipe, to force forms to be validated using the `class-validator` package, [read about it here](https://docs.nestjs.com/techniques/validation#validation).\n- Mount Angular (if required) to deliver the web interface, we will read about it later\n\nAfter all of this is setup and ready, we can start listening to requests.\n\n### NestJS App Module\n\nThe `src/app.module.ts` is the root level module which NestJS uses.\n\nThe file looks like this:\n\n```typescript\n@Module({\n  imports: [\n    DatabaseModule.register({ uri: config.DB_URI }),\n    AuthModule,\n    SocialAuthModule.register({\n      socialAuthServices: config.SOCIAL_CREDENTIALS as SocialAuthServices,\n    }),\n    ConfigManagerModule,\n  ],\n  controllers: [ApiController],\n  providers: [],\n})\nexport class AppModule {}\n```\n\nThis module imports the following modules:\n\n- `DatabaseModule` - Responsible of connecting to our mongo based database. It handles the connection on load, and relies on mongoose. This means you can use your mongoose schemas as usual.\n\n- `AuthModule` - Responsible of authenticating requests to endpoints, it is based on `passport-local` and uses `JWT` strategy with the `Bearer` authentication header in order\nto authenticate each user.\n\n- `SocialAuthModule` - Responsible of communicating 3rd party oauth-2 providers using passport, for example: `passport-google-token` and `passport-facebook-token`.\n\n- `ConfigManagerModule` - Responsible of managing and loading environment related configurations, and helps injecting the configurations to other services.\n\n\n### How the API works\n\nI would first recommend you to read the [introduction of NestJS](https://docs.nestjs.com/). As it will explain really the architecture and will help you make your express app easier to write, maintain and faster for development.\n\nWe will use the terms 'Module', 'Service' and other NestJS related stuff, so please make sure to\nread about them before diving into this README. To sum it up, if you have experience with Angular,\nNestJS is basically the same (just for server side).\n\nWithin this template, NodeJS comes with 2 working examples of a working api called `test` and `saySomething`,\nwhich can be viewed under `src/controllers/api.controller`.\n\nThe way this template is built makes the whole code a-lot more readable, and easier for testing.\n\napi.controller.ts:\n\n```typescript\n  @Get('/test') // This tells express to route on /api/test\n  test(): TestResponse {\n    return { status: 'ok' };\n  }\n```\n\nWhen navigating to route: `http://localhost:3000/api/test`, it will return a simple JSON which returns:\n\n```json\n{\n  \"status\": \"ok\"\n}\n```\n\nYou can test this api easily by running the express server:\n\u003e npm run start:dev\n\nNow simply access your server in this url:\n\u003e [http://localhost:3000/api/test](http://localhost:3000/api/test)\n\n#### Working with API params\n\nLet's review the working example of saySomething:\n\napi.controller.ts:\n\n```typescript\n  @Get('/say-something') // Route on /api/say-something\n  saySomething(@Query('whatToSay') whatToSay: string): { said: string } { // Setting the @QueryParams decorator tells express to extract the request.query['whatToSay'] into the whatToSay param.\n    return { said: whatToSay };\n  }\n```\n\nNow simple open up your browser to the api url with a 'whatToSay' param:\n\n\u003e [http://localhost:3000/api/say-something?what=Hello](http://localhost:3000/api/say-something?what=Hello)\n\nAnd you will get this output:\n\n```json\n{\n  \"said\": \"Hello\"\n}\n```\n\n### Database\n\nThis template uses mongo as the database, specifically mongoose as the api for communication with mongo. Currently, It has only one model called UserProfileModel which you can find in the `src/database/models` directory.\nYou can view the database code at the `src/database` directory, which basically is responsible for the communication to the database. It creates and exposes a NestJS `DatabaseModule`, which is responsible of handling the connection and database models.\n\nIn order to configure the database connection string, please review the `Environment configurations` part of this readme.\n\nHow do we use it? easy! lets take a look at how the `AuthService` accesses the database\nto get a user from an email:\n\n```typescript\n  getUserFromDB(\n    email: string,\n  ): DocumentQuery\u003cIUserProfileDbModel, IUserProfileDbModel, unknown\u003e {\n    /*\n    Here we are using the normal schemas of mongoose, no magic is happening!\n    Because we have already established the connection by importing the DatabaseModule,\n    We can simply use the `findOne` method as we are used to on mongoose.\n    */\n    return UserProfileDbModel.findOne({ email });\n  }\n```\n\nLet's take a look at the UserProfile schema (`src/database/models/user-profile.db.model.ts`):\n\n```typescript\nexport const UserProfileSchema = new Schema({\n  email: {\n    unique: true,\n    type: String,\n    required: true,\n    trim: true,\n    minlength: 4,\n  },\n  firstName: {\n    type: String,\n  },\n  lastName: {\n    type: String,\n  },\n  password: {\n    type: String,\n    required: true,\n    minlength: 6,\n  },\n  roles: [String],\n});\n```\n\nRemarks: NestJS has it's own mongoose database module, which in my opinion is a lot more \"complicated\" as you should inject the schemas every-time with a service. I prefer using mongoose the old fashioned way, which led me to design my own database module, this allows using the normal schemas, and makes the usage of the models straight-forward as it should be.\n\nIf you still prefer the original mongoose database, you can simply remove this module and use theirs [https://docs.nestjs.com/techniques/mongodb](https://docs.nestjs.com/techniques/mongodb)\n\n\n### Logging\n\nThis template comes ready with [NestJS Logger](https://docs.nestjs.com/techniques/logger). It is recommended to read on how to use the logger on the NestJS website.\n\n\n### SSL (https support)\n\nThis template comes with SSL support right out of the box. The only things you need to configure in your configuration\nfile is the SSL_CERTIFICATE:\n\n```typescript\n  // ...Some code...\n  SSL_CERTIFICATE: {\n    KEY: string;\n    CERT: string;\n    CA: string;\n  };\n  // ...Some code...\n```\n\nLet's say we want to configure the production to enable HTTPS, simply open up the `src/config/production.json` file and configure it as followed:\n\n```typescript\n{\n  // ...Some JSON props...\n  \"DB_URI\": \"production-mongo-uri\",\n  \"CLIENT_URL\": \"http://yourwebsite.com\",\n  // You must create a certificate in order to enable SSL (you can use https://letsencrypt.org/ for a free certificate)\n  \"SSL\": {\n    \"CA_PATH\": \"path/to/chain.pem\",\n    \"PRIVATE_KEY_PATH\": \"path/to/privkey.pem\",\n    \"CERTIFICATE_PATH\": \"path/to/cert.pem\"\n  }\n  // ...Some JSON props...\n}\n```\n\nNow when your server loads up, it will call this method in the `src/misc/utils.ts` file:\n\n```typescript\n/**\n * Returns the HTTPS options, if supported by the environment.\n */\nexport function getHttpsOptionsFromConfig(): HttpsOptions {\n  const readFileIfExists = (filePath: string): Buffer =\u003e {\n    if (filePath) return fs.readFileSync(filePath);\n  };\n\n  const sslConfig = config.SSL_CERTIFICATE;\n\n  return (\n    // If there are any SSL configurations\n    sslConfig \u0026\u0026\n    Object.keys(sslConfig).length \u003e 0 \u0026\u0026 {\n      key: readFileIfExists(config.SSL_CERTIFICATE.KEY),\n      cert: readFileIfExists(config.SSL_CERTIFICATE.CERT),\n      ca: readFileIfExists(config.SSL_CERTIFICATE.CA),\n    }\n  );\n}\n```\n\n### Authentication and roles\n\nThis template comes prepacked with JWT authentication and associated route-guards to authenticate users.\nin the `src/auth` directory you will be able to see how the authentication is implemented.\nIt is basically based on `passport-local` with `JWT` strategy.\n\nWhen a login occurs, the user is being authenticated against a hashed password using bcrypt, if the passwords match, a token is being generated containing the user data within.\n\nWhen accessing guarded routes (using the UserAuthGuard in the `src/auth/user-auth-guard.ts` file), the token will be decrypted and checked to see if it's valid. If so, the request will pass and a `req.user` property will be filled with currently logged on user.\n\nFor example, let's take a look at a guarded route, such as the `/api/profile`.\n\nIn the `auth.controller.ts` you can see the following code:\n\n```typescript\n  @UseGuards(UserAuthGuard)\n  @Get('/profile')\n  getProfile(@RequestUser() user: UserProfile): UserProfile {\n    return user;\n  }\n```\n\nThe `UseGuards(UserAuthGuard)` decorator will check if the user is authorized to login.\n\nSimple isn't it? The token is being delivered in the Authorization header in the format of `Authorization: Bearer ${Token}`.\n\nWhat about user roles? Each user profile has an array of `roles` which holds strings that contains the roles relevant for the user. For example, if you add the role `admin` to your user you should be able to access the `/api/admin` endpoint as it is guarded using the `UserAuthGuard`.\n\nLet's see how it is implemented.\n\n`src/controllers/api.controller.ts`:\n\n```typescript\n  @UseGuards(UserAuthGuard)\n  @Roles('admin')\n  @Get('/admin')\n  admin(): string {\n    return `You are an admin!`;\n  }\n```\n\n#### Social Authentication\n\nThe procedure of social authentication takes place in the client side, after the client obtains an access token from the 3rd party (Google, Facebook), that access token\nwill be delieverd to the `social-login/provider` (replace provider with the 3rd party name), which will create a user from the token provided by accessing that specific\n3rd party social network user profile information and map the user data into a data applicable for our website.\n\nThe authentication is implemented via the `passport` npm package with packages like `passport-facebook-token` and `passport-google-token`.\nIf A user with the provided email exists, it is returned with a new access token which is only relevant for our app (just like normal authentication).\n\nTake a look at the `src/social-auth` implementation to see how the access token is being used.\n\n### Environment configurations\n\nThis template is using the npm `config` package load configurations. You can read more about it here:\nhttps://www.npmjs.com/package/config\n\nAll of the configurations are located at the `src/config` directory. The way it loads the configuration is by first loading the `default.json` files and then load the associated environment configuration (by default `development.json`).\n\nIn order to change the environment you must specify the `NODE_ENV` environment variable.\n\nFor example, if you run on production specify:\n`NODE_ENV = production`.\n\nThere is a special configurations for the `test` environment as it starts up a test server on a different\nport and different credentials.\n\n#### Use the configurations\n\nYou have two options:\n\n1. Simply default import `src/config.ts`, which exports all of the configurations:\n\n```typescript\nimport config from './config';\n\nconsole.log(`Hello your databse URI is: ${config.DB_URI});\n```\n\n2. You can use the 'NestJS' way by injecting the `ConfigService`:\n\n```typescript\nimport { ConfigService } from '../config-manager/config.service.ts';\n\n@Injectable()\nexport class MyDatabseService {\n  constructor(private configService: ConfigService) {}\n\n  connect() {\n    this.database.connect(configService.getConfig().DB_URI);\n  }\n}\n\n```\n\n\n### Testing (Unit Tests\\API Tests)\n\nThis template comes with Mocha\\Chai integrated.\n\nThere are tests for all of the following:\n\n- API tests\n- Tests for services and guards\n- General tests\n\nEach file that has a test has a corresponding `.spec` file with the same name.\nFor example, for the api tests:\n\n`/src/controllers/api.controller.spec.ts` - you can find all api tests.\n\n\n##### Test database\n\nWhen the unit tests are running, they relay on a database connection, especially\nthe API tests, as these tests write mock data to the database before running the tests.\n\nIn order to solve this, the `DatabaseTestService` was created which uses the `mongodb-memory-server`\nto create the connection for each test suite.\n\nThis basically allows all of the tests to run in parallel without opening a real database.\n\n##### Running the tests\n\nIn order to run the backend tests, simply enter the following command:\n\n```bash\nnpm test\n```\n\nAll configurations will be taken from the `/src/config/test.json` file.\n\n## Sharing code (models, interfaces, etc)\n\nYou can use the `shared` directory in order for NodeJS and Angular to share the same code to be used on both sides\nwithout the need of re-writing the models for each.\n\nThe already existing models are:\n\n- ActionResponse - a simple response to a user action performed on the api. The server will send this response, and the client will read it.\n- UserProfile - a simple user profile model to used for authentication.\n\n## Form validations\n\nThis template comes with [class-validator](https://www.npmjs.com/package/class-validator) built in. Which makes it a-lot more easier to write form validations.\nAs this template shares code between Angular and NodeJS, validations will happen across both platforms.\n\nLet's look at the `UserProfile` model for example:\n```typescript\nimport { UserProfile } from './user-profile';\nimport { IsEmail, MinLength } from 'class-validator';\n\nexport class UserProfileModel implements UserProfile {\n  @IsEmail()\n  email: string;\n\n  @MinLength(1)\n  firstName: string;\n  @MinLength(1)\n  lastName: string;\n  @MinLength(6)\n  password: string;\n\n  roles?: string[];\n}\n```\n\nThe decorators you see like `@IsEmail`, `@MinLength` are class-validator decorators and allows us to easily force fields to pass certain validations.\n\nFor example, when registering a user validations takes place in this way:\n- Angular - checks that all fields are valid using the `FormValidatorDirective`, each field on your form will automatically show if it is valid or invalid\n  according to the validation set on it.\n\n  The `FormValidatorDirective` is a directive set on a form which simply checks each input and according to it's name assigns the validations relative to it.\n  Take a look at this example:\n\n\n  `angular-src/src/app/components/register/register.component.html`:\n\n  ```html\n    ...\n    \u003cform #form=\"ngForm\" class=\"col-12 form\" [appFormValidator]=\"userProfile\" [appFormValidatorForce]=\"true\"\u003e\n        \u003cdiv class=\"container\"\u003e\n          \u003cdiv class=\"row\"\u003e\n            \u003cdiv class=\"col-md-6\"\u003e\n              \u003cdiv class=\"form-group\"\u003e\n                \u003clabel for=\"email\"\u003eEmail\u003c/label\u003e\n                \u003cinput type=\"text\" class=\"form-control\" name=\"email\" [(ngModel)]=\"userProfile.email\" id=\"email\"\n                  aria-describedby=\"helpId\" placeholder=\"mail@gmail.com\"\u003e\n              \u003c/div\u003e\n\n              \u003cdiv class=\"form-group\"\u003e\n                \u003clabel for=\"password\"\u003ePassword\u003c/label\u003e\n                \u003cinput type=\"text\" class=\"form-control\" name=\"password\" [(ngModel)]=\"userProfile.password\" id=\"password\"\n                  aria-describedby=\"helpId\" placeholder=\"Password\"\u003e\n              \u003c/div\u003e\n\n            \u003c/div\u003e\n      ...\n  ```\n\n  See the `appFormValidator` directive? it associated with the `userProfile` object, which is an instance of `UserProfileModel`. This allows you to easily\n  Forces validations on forms and errors to the user.\n\n\n- NodeJS - on the server side validations are taken place in this way:\n  `/src/auth/auth.controller.ts`:\n\n  ```typescript\n  @Post('/register')\n  register(@Body() registerForm: RegisterForm): Promise\u003cUserProfile\u003e {\n    // Hash the user password and create it afterwards\n    return registerForm.getHashedPassword().then(hashedPassword =\u003e {\n      return UserProfileDbModel.create({\n        ...registerForm,\n        password: hashedPassword,\n      });\n    });\n  }\n  ```\n\n  The validation of class-validator will take place automatically using the class-validator, you can read about it here:\n  [https://docs.nestjs.com/techniques/validation#validation](https://docs.nestjs.com/techniques/validation#validation).\n\n# Running on production\n\n## The easiest way to run on production - Docker\\Docker-Compose\n\nThis template comes ready with Dockerfile based on node:12.18.1-alpine3.11 docker image.\n\nIt also comes with a ready out of the box docker-compose.yml file which can be used\nto start-up the database and the web interface as easy as a command.\n\n\n### Docker-compose\n\nYou can fire-up the database and the web interface using the following command:\n\n```bash\n# This will build web docker image automatically if it does not exist\ndocker-compose up -d\n```\n\nYou can also build the web image manually like this:\n\n```bash\ndocker-compose build web\n```\n\nThe environment variable for communication using docker-compose is already included in the `.env` file.\nThis `.env` file contains the DB_URI of the database which the web will be able to to access.\n\n\n### Nginx as reverse proxy\n\nIn order for the usual ports (443 and 80) to work we are using Nginx as a reverse proxy.\n\nNginx will startup as a docker microservice (listed under the docker-compose) listening to port 443 and 80. All traffic will be redirected from port 80 to HTTPS (port 443) using Nginx. Nginx will act as a reverse proxy pointing to our web service.\n\nMake sure to edit the `nginx.conf` file to the correct domain urls, also update the `certs` directory with the correct SSL certificates (can be freely generated using `certbot` utility).\n\n### Docker image build\n\nIn order to build the docker image without docker-compose, you can simply run the following command:\n\n```bash\n  docker build -t my-docker-image:0.0.0 .\n```\n\nAnd in order to run your docker on port 8080 simply run the following command:\n\n```bash\ndocker run -p 8080:3000 -itd my-docker-image:0.0.0\n```\n\nOr you can simply use docker compose:\n\n```bash\ndocker-compose up\n```\n\nThis will run your container on port 3000.\n\nIn order to run this code on production, you must first compile it.\nThere a few things to take into consideration:\n\n## Building and compiling the code manually\n\nThis template comes with Angular and NodeJS bundled together and can\nbe up and running together on the same NodeJS server. This takes place using the `build.sh` bash script\nthat knows how to compile them together and bundle them.\n\nHow does it work? Well it simply compiles each one separately and then copies the angular-src output dist directory\ninto the NodeJS src directory and delievers them in the `src/server.ts` like this:\n\n```typescript\n// Point static path to Angular 2 distribution\nthis.express.use(express.static(path.join(__dirname, 'dist')));\n\n// Deliver the Angular 2 distribution\nthis.express.get('*', function(req, res) {\n  res.sendFile(path.join(__dirname, 'dist/index.html'));\n});\n```\n\n**Take into consideration that it will not work on debug mode.**\n\nWhen building your image for production it should contain the following commands:\n\n```bash\nnpm run build # Call the build.sh script to start the build (it also installs the deps required if they do not exist)\n```\n\nAnd to run this code simple:\n\n```bash\nnpm start\n```\n\n### The build script (build.sh)\n\nThe build script called `build.sh` is a shell script provided with the template which by default will compile the typescript\nNodeJS server side and Angular into one. This means when you run the server after the build you will have both on the same\nnode container.\n\nMake sure to include the `NODE_ENV` environment variable (or else the build will be set to `development` environment) before calling this\nscript. The build will compile and copy all of the required configurations for the specified environment, and will generate the Angular\ncode according to that environment.\n\nBy default, when building to production, Server Side Rendering (SSR) is set to build as well:\n\n```bash\n# TODO: Remove this 'if' statment until the 'fi' if you don't want SSR at all\nif [ $ENV == \"production\" ]; then\n    echo \"Building Angular app for SSR...\"\n    ./node_modules/.bin/ng run angular-src:server:production\n    check_errcode \"Failed to build Angular app for SSR! aborting script!\"\nelse\n    echo \"Skipping build for SSR as environment is NOT production\"\nfi\n```\n\nYou can remove this set of code if you don't want it to take place at all.\n\n\n## Separating client and server\n\n### Server as standalone\n\nIn order to run the server as standalone, simply compile it:\n\n```bash\nnpm run build:nest\n```\n\nThe output will be projected into the `dist` directory.\n\n### Angular as standalone\n\nIn order to run angular as a standalone, simply compile it:\n\n```bash\nnpm run build:angular\n```\n\nThe output will be projected into the `angular-src/dist` directory.\n\n## Deploying our app on a new server using Ansible\n\nAnsible is a utility that allows us to deploy our server easily, it will install the required\ndependencies (such as docker, docker-compose), clone our project and start the app.\n\nThe built-in Ansible playbook provided currently only supports CentOS\\Redhat.\n\n### Configuring Ansible for the first time\n\nBefore we can start working with Ansible, we need to make sure the following:\n\n- First make sure you have Ansible installed on your computer and that the command `ansible` is available.\n- Create a server running either Centos\\Redhat, save the IP of the server.\n- Edit the `ansible/inventory` file with the updated IP address of our server.\n- Open up the `ansible/ansible.cfg` and make sure it points to the correct SSH key. If you are using username\\password please read the official Ansible docs on how to configure that.\n- Edit the `ansible/main.yml` file to point to the correct Github repository.\n\n### Deploying our infrastructure\n\nNow that everything is configured and ready, simply run the following command:\n\n```bash\n# Run the main playbook\nansible-playbook main.yml\n```\n\n## Built in CI\\CD (Github Actions)\n\nThis template comes pre-packed with tests that automatically run after opening a pull request. Also automatic deployment to your custom server is also taken care of when pushing code to the master branch. You can find the `.github/workflows` directory and see these two files:\n\n- `nodejs.yml` - This file contains the workflow related to the CI process, it runs tests on the frontend and backend on any new pull request.\n\n- `deploy.yml` - This file contain the workflow related to the CD process, it build the docker image, tags it according to the current version, saves it, and then copies it to the dedicated server using SCP. Then, it finally loads the new image to the target server and starts the server again.\n\n\n### Server preparations for CD to work\n\nIt is recommended to using Ansible, it will do all of the setup required for the CD process to work later-on. Ansible will setup docker, docker-compose, users and permissions required for login.\n\nIf you still prefer doing it manually, first make sure you have the following:\n\n1. Your app cloned and sits at the `~/app` directory.\n2. Docker and Docker-Compose are installed and working correctly.\n3. Permissions are granted for the user which will be connected via SSH. It IS NOT recommended for user `root` to be the one deploying our app. If you are using the Ansible playbook in the project, it will automatically create the `deployment` user for you.\n4. The generated user should be part of the `docker` group in order to run `docker-compose` commands.\n\n### Secrets required for the CD process\n\nIn order for the CD process to actually work you have to add the following secrets to the repository:\n\n- SSH_HOST - the hostname\\ip address of the target host to deploy the application into.\n- SSH_KEY - the private key file used for authentication with the server.\n- SSH_USERNAME - The username being used for the target server.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshy2net%2Fnestjs-angular-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshy2net%2Fnestjs-angular-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshy2net%2Fnestjs-angular-starter/lists"}