{"id":24874753,"url":"https://github.com/dirheimerb/express-starter","last_synced_at":"2025-03-27T02:16:03.658Z","repository":{"id":38455103,"uuid":"496492438","full_name":"dirheimerb/express-starter","owner":"dirheimerb","description":null,"archived":false,"fork":false,"pushed_at":"2023-02-04T12:12:17.000Z","size":9698,"stargazers_count":0,"open_issues_count":20,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-01T07:28:59.796Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/dirheimerb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2022-05-26T05:28:07.000Z","updated_at":"2022-05-26T05:28:13.000Z","dependencies_parsed_at":"2023-02-14T19:31:42.804Z","dependency_job_id":null,"html_url":"https://github.com/dirheimerb/express-starter","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":"shanhuiyang/TypeScript-MERN-Starter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirheimerb%2Fexpress-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirheimerb%2Fexpress-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirheimerb%2Fexpress-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirheimerb%2Fexpress-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dirheimerb","download_url":"https://codeload.github.com/dirheimerb/express-starter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245767360,"owners_count":20668826,"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":[],"created_at":"2025-02-01T07:28:19.417Z","updated_at":"2025-03-27T02:16:03.630Z","avatar_url":"https://github.com/dirheimerb.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TypeScript MERN Starter\n\n[![Build Status](https://api.travis-ci.org/shanhuiyang/TypeScript-MERN-Starter.svg?branch=master)](https://travis-ci.org/shanhuiyang/TypeScript-MERN-Starter)\n[![Dependency Status](https://david-dm.org/shanhuiyang/TypeScript-MERN-Starter.svg)](https://david-dm.org/shanhuiyang/TypeScript-MERN-Starter)\n[![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\n**Live Demo:** [https://hd283.net/](https://hd283.net/)\n\n| Supported Clients        | Preview                 |\n| ------------------------ | ----------------------- |\n| Web                      | \u003cimg src=\"./images/demo-desktop-web.png\" alt=\"Web Preview\" width=\"600\"/\u003e  |\n| Web (Mobile)             | \u003cimg src=\"./images/demo-mobile-web-0.png\" alt=\"Mobile Web Preview\" width=\"200\"/\u003e\u003cimg src=\"./images/demo-mobile-web-1.png\" alt=\"Mobile Web Preview\" width=\"200\"/\u003e\u003cimg src=\"./images/demo-mobile-web-2.png\" alt=\"Mobile Web Preview\" width=\"200\"/\u003e |\n| Android                  | \u003cimg src=\"./images/demo-android-0.png\" alt=\"Android Preview\" width=\"200\"/\u003e\u003cimg src=\"./images/demo-android-1.png\" alt=\"Android Preview\" width=\"200\"/\u003e\u003cimg src=\"./images/demo-android-2.png\" alt=\"Android Preview\" width=\"200\"/\u003e   |\n| iOS                      | \u003cimg src=\"./images/demo-ios-0.png\" alt=\"iOS Preview\" width=\"200\"/\u003e\u003cimg src=\"./images/demo-ios-1.png\" alt=\"iOS Preview\" width=\"200\"/\u003e\u003cimg src=\"./images/demo-ios-2.png\" alt=\"iOS Preview\" width=\"200\"/\u003e   |\n\n**This project built a real blog app for all platforms in TypeScript.**\n\nTypeScript is a typed super set of JavaScript.\nIf you are new to TypeScript it is highly recommended to become familiar with it first before proceeding.\nYou can check out its documentation [here](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html).\n\n**MERN** stands for **M**ongoDB, **E**xpress.js, **R**eact/**R**eactNative, and **N**ode.js.\n\nTypeScript has brought the following benefits to MERN:\n\n- **Unified modeling** across web client and server for objects\n- Type safety, and easy refactoring of typed code across web client and server\n- A superior developer experience in a team environment\n\nNot only using TypeScript, but this project is also featured by:\n\n- **Real fullstack**, because you can build node **server**, Mongo DB, multimedia storage, **website** (for both desktop and mobile), **Android** app, and **iOS** app based on this project **in single programming language**.\n- **[RESTful-style](https://www.restapitutorial.com/lessons/whatisrest.html)**. Powered by an embedded [oauth2 server](https://github.com/jaredhanson/oauth2orize) and [passport.js](http://www.passportjs.org/), this project separate client and server clearly. Then the REST server can serve for both website and mobile clients simultaneously.\n- **[React-router 4.0+](https://reacttraining.com/react-router/)**, with it you can easily define client routes and manage them.\n- **[Redux](https://redux.js.org/introduction)**, with it you can easily manage client states. Also **all clients shared the same state machine** implemented by Redux, we reduced a lot of effort when you develop for multi-clients.\n- **Almost ready** for a blog app. We modeled `User` as well as `Article`. This is a **real starter** for who would like to build a blog app or extend it to a community app using MERN.\n- The web client code is created from **[create-react-app](https://facebook.github.io/create-react-app/)**, so now you can get rid of annoying configurations for babel and webpack.\n- The Android/iOS client is created from **[Expo](https://expo.io)**, which is a tool encapsulated a lot of complexity when you develop on ReactNative.\n\n## Table of Content\n\n- [Quick start](#quick-start)\n  - [Before Start](#before-start)\n  - [Clone the repository](#clone-the-repository)\n  - [Install dependencies](#install-dependencies)\n  - [Start your mongoDB server](#start-your-mongodb-server)\n  - [Build and run the project](#build-and-run-the-project)\n  - [Start the mobile apps](#start-the-mobile-apps)\n- [Motivation](#motivation)\n  - [Prior Art](#prior-art)\n  - [Philosophy](#philosophy)\n  - [Work Items](#work-items)\n- [Project structure](#project-structure)\n  - [Dependencies](#dependencies)\n  - [Folder structure](#folder-structure)\n  - [Create React App](#create-react-app)\n    - [Serve static assets of client and index.html in production](#serve-static-assets-of-client-and-indexhtml-in-production)\n    - [Proxy API requests in development](#proxy-api-requests-in-development)\n  - [Unified Modeling](#unified-modeling)\n  - [Embedded OAuth2 server](#embedded-oauth2-server)\n    - [OAuth 2.0 protocol](#oauth-20-protocol)\n    - [Resource server](#resource-server)\n    - [Authorization server](#authorization-server)\n    - [Summary of OAuth2 server](#summary-of-oauth2-server)\n  - [Server routing \u0026 client routing](#server-routing-\u0026-client-routing)\n    - [React-router 4.0+](#react-router-40+)\n    - [Performance perspective](#performance-perspective)\n  - [Styling](#styling)\n- [How to debug](#how-to-debug)\n  - [Available scripts](#available-scripts)\n  - [Debugging website client](#debugging-website-client)\n  - [Debugging mobile client](#debugging-mobile-client)\n  - [Debugging server](#debugging-server)\n  - [Debugging tests](#debugging-tests)\n- [Tests](#tests)\n- [Deploying the app](#deploying-the-app)\n  - [Prerequisite](#prerequisite)\n  - [Create production MongoDB (Option 1: Azure CosmosDB)](#create-production-mongodb--option-1--azure-cosmosdb-)\n    - [Open Azure Cloud Shell](#open-azure-cloud-shell)\n    - [Create a resource group](#create-a-resource-group)\n    - [Create a Cosmos DB account](#create-a-cosmos-db-account)\n    - [Retrieve the database key](#retrieve-the-database-key)\n    - [Configure the connection string in your Node.js application](#configure-the-connection-string-in-your-nodejs-application)\n  - [Create production MongoDB (Option 2: MongoDB Atlas)](#create-production-mongodb--option-2--mongodb-atlas-)\n  - [Create a production blob storage](#create-a-production-blob-storage)\n  - [Test the application in production mode](#test-the-application-in-production-mode)\n  - [Build app into a Docker image](#build-app-into-a-docker-image)\n    - [Configure environment variables for production](#configure-environment-variables-for-production)\n    - [Build app into a local Docker image](#build-app-into-a-local-docker-image)\n    - [Push Docker image to Docker hub](#push-docker-image-to-docker-hub)\n  - [Create an Azure app service using Docker image](#create-an-azure-app-service-using-docker-image)\n    - [Add an Azure app service in Azure portal](#add-an-azure-app-service-in-azure-portal)\n    - [Verify your Azure app service](#verify-your-azure-app-service)\n  - [Map custom domain and bind SSL certificate](#map-custom-domain-and-bind-ssl-certificate)\n  - [Deploy the mobile apps](#deploy-the-mobile-apps)\n  - [Summary of deployment](#summary-of-deployment)\n\n## Quick start\n\n### Before Start\n\nTo build and run this app locally you will need a few things:\n\n- Install [Chrome](https://www.google.com/chrome/)\n- Install [Node.js](https://nodejs.org/en/)\n- Install [MongoDB](https://docs.mongodb.com/manual/installation/)\n- Install [VS Code](https://code.visualstudio.com/)\n- Install [Yarn](https://yarnpkg.com/)\n- Install [Expo Cli](https://expo.io/tools#cli)\n\n### Clone the repository\n\n```bash\ngit clone https://github.com/shanhuiyang/TypeScript-MERN-Starter.git \u003cproject_name\u003e\n```\n\n### Install dependencies\n\n```bash\ncd \u003cproject_name\u003e\nyarn\n```\n\n### Start your mongoDB server\n\n(you'll probably have to start another command prompt)\n\n```bash\nmongod\n```\n\n\u003e **Note!** While you just installed MongoDB (for both on OSX or Windows),\n\u003e it may remind you that you can run MongoDB **as service**,\n\u003e then your MongoDB will always be running even after you restart your computer.\n\n### Build and run the project\n\n```bash\nyarn start\n```\n\nFinally, navigate to [http://localhost:3000](http://localhost:3000) and you should see the blog page being served and rendered locally!\n\n\u003e **Note!** You **cannot** open the localhost website on IE and Edge browser.\n\u003e In contrast, you can open it on Safari, Firefox, and Chrome.\n\u003e However, we will ensure the compatibility of the production app on IE and Edge browser.\n\n### Start the mobile apps\n\nThe command `yarn start` will also start the react-native project using expo-cli.\nSo you can navigate to [http://localhost:19002](http://localhost:19002) and you will see the Expo DevTool page.\nFrom that page you can easily start your app for both Android and iOS by clicking corresponding buttons.\n\nFor more detail of prerequisite please refer to [Installation](https://docs.expo.io/versions/v34.0.0/introduction/installation/) of Expo document.\n\nBriefly speaking, you should prepare for devices you would like to debug on, either emulator/simulator or physical devices.\n\n[TODO] Elaborate this part.\n\n\u003e **Note!** Currently you cannot test Android app on emulator without configure the host url manually.\n\u003e This is because in Android emulator you cannot access `http://localhost` which hosted on the same server/PC/Mac.\n\u003e You can test your app in the same LAN, see next section for detail.\n\n### Optional: Test your app on other device in the same LAN\n\nBy default the request url connect client and service are `http://localhost`, i.e. you can only test client and service in the same server/PC/Mac.\n\nTo test your app in LAN, you can do following before enter command `yarn start`.\n\n1. Get the IP address (either global IP or LAN IP) of your development server. \n2. Modify the constant `HOST_NAME_DEV` in [client/core/src/models/HostUrl.ts](client/core/src/models/HostUrl.ts) with the IP address you got.\n\n### Optional: Test with OTP sending\n\nThis project implement the auth service, as well as account verification by sending OTP to user's registered email account.\n\nBy default the account verification is turned off since SMTP transporter is not configured with account and password.\n\nTo test this part of functionality, you can:\n\n1. add your email account and password to [server/config/smtp-transporter.ts](server/config/smtp-transporter.ts).\n2. change the flag to `true` in [client/core/src/shared/constants.ts](client/core/src/shared/constants.ts).\n\n## Motivation\n\nUp to 2020, React is the most popular front-end framework.\nFor novice web developers, if they would like to build a full-stack project using Javascript, they can intuitively choose the combination of Node.js and React.\n\nTypescript is a success Javascript alternative which can keep the maintainability as the project grows.\nThe most famous Typescript project is [Angular](https://angular.io).\nNowadays React also [support Typescript officially](https://facebook.github.io/create-react-app/docs/adding-typescript).\n\nTherefore, the motivation of this project is building a fullstack web app using Typescript, then we can maintain and extend a web app easily.\n\nOn the other hand, we have seen the template like TypeScript-Node-Starter, TypeScript-React-Starter, and TypeScript-React-Native-Starter.\nWhat if we mixed these 3 projects together?\nHow could Typescript shows its advantage if we use it across client \u0026 server?\nSo this project is intended to explore the capability of Typescript in that circumstance.\n\n### Prior Art\n\n[mern-starter](https://github.com/Hashnode/mern-starter) is a famous project which combine React and Node.js in a single project.\nHowever, it is deprecated after April, 2019.\nThis project is a server rendering solution.\nIt modeled the `Post` object, but did not implement the authentication module.\n\n[TypeScript-Node-Starter](https://github.com/Microsoft/TypeScript-Node-Starter) is an officially built starter project for Node.js by Microsoft.\nThis project is a good starter for Node.js app using Typescript.\nIt is also a server rendering solution, using [pug](https://github.com/pugjs/pug).\n\nIndeed **TypeScript-MERN-Starter** is built on top of TypeScript-Node-Starter.\nHowever, as you can see in **TypeScript-MERN-Starter**, the architecture has been totally changed comparing to TypeScript-Node-Starter.\n\n[oauth2api](https://github.com/PatrickHeneise/oauth2api) is a good example on how to implement OAuth2 strategy in an Node.js app.\nWe almost totally imported this project to **TypeScript-MERN-Starter**.\n\n### Philosophy\n\nWe build this project on following philosophies:\n\n1. **Beginner friendly**. You can start the app without any complex configuration for build and runtime.\n2. **Easy to extend**. You can always focus on your business logic. We chose well-documented 3rd party packages to use, so that you can extend this app easily by following the working patterns of these packages.\n3. **Share the code as much as possible**. For example, usually we prefer the 3rd party package who can be used both in React and ReactNative, such as ReactRouter, ReactIntl, etc. In contrast, we gave up to use ReactNavigation, expo-localization which can only used in ReactNative.\n\n### Work items\n\nWe have already extended this project from MERN to MER**R**N, where the additional R stands for [ReactNative](https://facebook.github.io/react-native/).\n\nIn next period of time (Before end of Feb 2020), we will work on:\n\n- Better documents.\n- Use types as many as possible.\n- ~~Use Promises instead of callbacks.~~\n- ~~Globalization. The text strings should be well managed and easily be extended for multi-languages.~~\n- ~~Better error alert.~~\n- Tests. The core of client (such as actions, reducers), and server (such as routes, controllers) should be well covered by unit tests.\n- Better article UX.\n  - ~~Using the list-detail structure.~~\n  - ~~User can add comments to articles. (website only)~~\n  - ~~Pagination. (website only)~~\n- ~~Rich text editors. Using markdown as the exchanging text format.~~\n  - ~~Unsaved alert if users are going to close the page.~~\n- ~~Notification (website only)~~\n  - ~~Comment received for article authors.~~\n- ~~Improving the authentication. (website only)~~\n  - ~~Email verification for signing up.~~\n  - ~~Password modification.~~\n  - ~~Forget password.~~\n- ~~User-friend time display.~~\n- Incoming issues.\n\n## Project structure\n\nIn this part, we will not only summarize the folder structure, but also introduce how each of the project gradients works.\n\nBriefly speak, we nested 3 projects in the repo, to get the biggest reusability of code.\n\n![Big picture](./images/big-picture.png)\n\nTherefore, we fused server, website (for both desktop and mobile), and Android \u0026 iOS projects together in this repo.\n\nThe basic working flow of the app could be illustrated in the following diagram.\n\n![Data flow](./images/data-flow.png)\n\nPlease note that we did not invent any framework, what we did is taking the advantages of many popular frameworks from React ecosystem, and organize it logically.\n\n### Dependencies\n\n![Dependencies](./images/dependencies.png)\n\nHere is a index for **documents** what the project depends on:\n\n- [Create React App](https://create-react-app.dev/docs/getting-started)\n- [Expo](https://docs.expo.io/versions/latest/)\n- [Express](https://expressjs.com/en/guide/routing.html)\n- [Jest](https://jestjs.io/docs/en/getting-started)\n- [MongoDB](https://docs.mongodb.com/manual/)\n- [Mongoose](https://mongoosejs.com/docs/guide.html)\n- [NativeBase](https://docs.nativebase.io/)\n- [Node](https://nodejs.org/en/docs/)\n- [PassportJS](http://www.passportjs.org/docs/)\n- [React](https://facebook.github.io/react/docs/getting-started.html)\n- [ReactNative](https://facebook.github.io/react-native/docs/getting-started)\n- [ReactRouter](https://reacttraining.com/react-router/web/guides/quick-start)\n- [Redux](https://redux.js.org/introduction/getting-started)\n- [Semantic-UI React](https://react.semantic-ui.com/)\n- [Typescript](https://www.typescriptlang.org/docs/home.html)\n\n### Folder structure\n\n```\n.                                // a complete nodeJS/Express project\n├── .vscode                      // VS Code specific settings\n|\n├── client                       // a complete Expo/ReactNative project: all of the client code\n|   |\n|   ├── core                     // a complete create-react-app project: all of the website code\n|   |   ├── build                // output from your TypeScript build for website\n|   |   ├── node_modules         // all of your npm dependencies for website code\n|   |   ├── public               // static assets that will be used to build website\n|   |   ├── src                  // non-view layer code for both clients, and view layer code of the website\n|   |   |   ├── actions          // Redux actions implementations, shared for both website and mobile apps\n|   |   |   ├── models           // type definitions, may be used for both server and clients\n|   |   |   ├── reducers         // Redux reducers implementations, shared for both website and mobile apps\n|   |   |   ├── shared           // common utilities for client, shared for both website and mobile apps\n|   |   |   ├── website          // all view layer code of the website\n|   |   |   ├── index.tsx        // entry point of the website\n|   |   |   ├── serviceWorker.ts // create-react-app generated file, which is used for debug\n|   |   |   └── setupProxy.js    // bypasses all REST API calls to nodejs server while debugging\n|   |   ├── package.json         // contains npm dependencies and build scripts for website\n|   |   └── tsconfig.json        // config settings for compiling website\n|   |\n|   ├── assets                   // images used by expo/react-native project\n|   ├── src                      // all view layer code of the mobile apps\n|   ├── app.json                 // Expo configuration for mobile apps\n|   ├── App.tsx                  // entry point of the Expo/ReactNative project\n|   ├── package.json             // contains npm dependencies and build scripts for mobile apps\n|   └── tsconfig.json            // config settings for compiling mobile apps\n|\n├── dist                         // output from your TypeScript build for node server\n├── images                       // README.md referenced images\n├── node_modules                 // npm dependencies for server side\n├── server                       // all of the source code for server\n|   ├── config                   // authorizations and emailer configurations\n|   ├── controllers              // controllers respond to various http requests\n|   ├── models                   // server specific type definitions, and DB schemas\n|   ├── repository               // cloud or local file storage interfaces\n|   ├── routes                   // server routing configurations\n|   ├── translations             // international strings used by server only\n|   ├── util                     // utility functions\n|   ├── app.ts                   // server initialization code\n|   └── server.ts                // entry point of server\n├── .dockerignore                // defines which files or folders cannot be included for docker build\n├── .env.development             // defines environment variables while NODE_ENV is development\n├── .env.production              // defines environment variables while NODE_ENV is production\n├── .travis.yml                  // to configure Travis CI build\n├── package.json                 // npm dependencies and build scripts for the whole project\n├── start-client.js              // script used to invoke build/start scripts in website project\n├── start-mobile.js              // script used to invoke build/start scripts in mobile apps project\n├── tsconfig.json                // config settings for compiling server code written in TypeScript\n├── tslint.json                  // config settings for TSLint code style checking for server\n└── yarn.lock                    // in which Yarnpkg stores versions of each dependency\n```\n\n### Create React App\n\nThe _client/core_ folder includes a complete React app which was initialized by [Create React App](https://facebook.github.io/create-react-app/).\nCreate React App is a great tool for beginner since it is:\n\n1. **Less to Learn**. You don't need to learn and configure many build tools. Instant reloads help you focus on development. When it's time to deploy, your bundles are optimized automatically.\n2. **Only One Dependency**. Your app only needs one build dependency. Under the hood, it uses Webpack, Babel, ESLint, and **tsc (Typescript compiler)** to power on your app. Then you can get rid of the complicated configurations for them.\n\n#### Serve static assets of client and index.html in production\n\nIn production build environment, `react-scripts`, the tool for use with `Create React App` will compile all of your (Typescript) source code and resources into bundles and assets in [client/core/build](client/core/build) folder.\n\nFor all routes except those for REST APIs, the Node.js server can response [client/core/build/static/index.html](client/core/build/static/index.html).\n\nThat is to say, our server routes all REST APIs, and leave all other possible routes to client.\nServer will never make up the client app, it will not decide how would the client should look like.\nThis is **the first key point to make the RESTful architecture possible**.\n\n#### Proxy API requests in development\n\nHowever, in development environment, things become totally different.\nWhen you run the command `yarn start` in _client/core_ folder, `react-scripts` will boot a local debug server for you.\nThis server is implemented in [client/core/src/serviceWorker.ts](client/core/src/serviceWorker.ts).\nIt makes the hot-reload and other functions for a better development experience.\n\nThen you have 2 servers when you are developing and debugging.\nOne is the Node.js server developed by yourself, another is the serviceWorker booted by Create React App.\nThe former serves REST APIs for you, the later serves React app for you.\n\nHow could we make these 2 servers work together harmoniously?\n\nSuggested by the [document of Create React App](https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development), we can configure the serviceWorker proxy REST API requests to the Node.js server.\nConveniently, this also avoids [CORS issues](https://stackoverflow.com/questions/21854516/understanding-ajax-cors-and-security-considerations).\n[The article presented by _Anthony Accomazzo_](https://www.fullstackreact.com/articles/using-create-react-app-with-a-server/#the-rub-) clearly illustrated how this mechanism works.\n\nWe can summarize how we applied this strategy as below:\n\n1. Assign port 3000 to the serviceWorker, and assign port 3001 to the Node.js server.\n2. When we are running `yarn start` in project root path, these 2 servers will be started concurrently.\n3. All client requests are going to the port 3000, i.e. the serviceWorker.\n4. In the file [client/core/src/setupProxy.js](client/core/src/setupProxy.js), we configure that uri starts with `/api`, `/auth`, and `/oauth` should be proxied to port 3001., i.e. the Node.js server will handle these requests forwarded by the serviceWorker.\n\n### Unified Modeling\n\nA big advantage of Node.js is that it can be used as a single programming language for both front and back end.\nHowever, since JavaScript is a loosely typed or a dynamic language, variables in JavaScript are not directly associated with any particular value type, and any variable can be assigned (and re-assigned) values of all types.\nTherefore, sometimes when you look at a function call, you may have no idea what kind of object the argument passes.\nInformation is lost when you and your teammates are communicating using the Javascript code.\n\nTypescript provided a good solution for large scale project of Javascript because of its type system.\nWe took advantages of this type system to model the objects which can be used in both client and server at the same time.\n\nLet's take a close examine.\nIn [client/core/src/models/UnifiedModel.d.ts](client/core/src/models/UnifiedModel.d.ts), we defined a interface named UnifiedModel.\nThis interface represent an abstract type that would be used in client, service, and **MongoDB**.\nIt contains fields generated by MongoDB such as timestamps of create/update, and MongoDB ids.\nThese fields should be read-only in client side Typescript code.\n\nSuppose we are going to define a type named User, which contains the profile and password of a website user who can login, post an article, and view his/her profile.\nWe will do following:\n\n1. Add a interface named `User` in [client/core/src/models/User.ts](client/core/src/models/User.ts), and extends it from `UnifiedModel`.\n2. Fill the `User` with fields you desire such as name and address, etc.\n3. In [server/models/User/UserDocument.d.ts](server/models/User/UserDocument.d.ts), define a interface named `UserDocument`, which extends `User` and `mongoose.Document` simultaneously. This interface represent a document which can be create, read, update and delete from MongoDB.\n4. Add the `userSchema` and necessary middleware according to the requirements of `mongoose` in [server/models/User/UserCollection.ts](server/models/User/UserCollection.ts).\n\n\u003e **Note!** The reason why we defined the common interface under [client/core](client/core) folder but not a root level [models](models) folder under project root is because of the restriction from Create React App and Expo. \n\u003e These tools cannot read the type definition out of it's workspace, i.e. the [client/core](client/core) and [client](client) folder.\n\u003e So we have to put our common models in [client/core](client/core) folder first.\n\u003e Then the Node and Expo project can both access the models.\n\nIn summary, `User` is the common type used on both sides of an API request.\nIn client, the React app can render an `User` object, post an `User` object to, and receive an `User` object from server.\nIn server, the Node.js app can CRUD `User` objects from and to MongoDB.\nWhen you are going to add a field in your `User` definition, you may have to change both sides implementation related to `User`.\nIf you forget to make necessary change on both sides, VS Code will kindly remind you when you are building the project.\n\nYou would feel inconvenient that after you defined the `User` interface like this,\n\n```Typescript\nexport default interface User extends UnifiedModel {\n    email: string;\n    password?: string;\n    name: string;\n    gender: Gender;\n    avatarUrl: string;\n    address?: string;\n    website?: string;\n}\n```\n\nyou still have to define `userSchema` for `Mongoose` like following,\n\n```Typescript\nexport const userSchema: Schema = new mongoose.Schema({\n    email: { type: String, unique: true },\n    password: String,\n    name: String,\n    gender: String,\n    avatarUrl: String,\n    address: String,\n    website: String\n}, { timestamps: true });\n```\n\n**Yes, it is duplicated works you need to take care about**.\nNow you have to make sure these 2 definitions consistent after you change one of them.\nThere is a known library named [typegoose](https://github.com/szokodiakos/typegoose) which is addressing the duplicated definitions problem.\nHowever since it defines the model using class extended from a `Typegoose` class which contains much more required fields than we want, we cannot use that type definition in client side.\nWe are looking forward its evolving so that we can resolve this issue in future.\n\n### Embedded OAuth2 server\n\nTo protect REST API against unauthorized request, we used [Passport](http://www.passportjs.org/docs/) in this project.\nPassport is an authentication middleware for Express.\nIt is designed to serve authenticating requests.\nSuppose you are going to create an article in the web app, the server protected such requests like this:\n\n```Typescript\narticle.route(\"/create\").post(\n    passport.authenticate(\"bearer\", { session: false }),\n    controllers.create\n);\n```\n\nThe purpose of this statement is straightforward. It means that when a POST request with url `api/article/create` is coming, do the following in order.\n\n1. Authorize the request with Bearer strategy, just see if it has a valid Bearer token. If yes, go to step 2; if no, return a `401 Unauthorized` error.\n2. Handle the request using controller of article creating.\n\nTherefore when you confirm that an REST API should be protected, just insert a single line in its route configuration like this:\n\n```Typescript\npassport.authenticate(\"bearer\", { session: false }),\n```\n\nLet's take a look at what we did in this project to make life easier.\n\n#### OAuth 2.0 protocol\n\nOAuth 2.0 (formally specified by [RFC 6749](https://tools.ietf.org/html/rfc6749)) provides an authorization framework which allows users to authorize access to third-party applications.\nWhen authorized, the application is issued a token to use as an authentication credential.\nThis has two primary security benefits:\n\n1. The application does not need to store the user's username and password.\n2. The token can have a restricted scope (for example: read-only access).\n\nThese benefits are particularly important for ensuring the security of web applications, making OAuth 2.0 the predominant standard for API authentication.\n\nOAuth 2.0 defines four roles:\n\n1. **resource owner**.\nAn entity capable of granting access to a protected resource.\nUsually the resource owner is a person, it is referred to as an application end-user.\n2. **resource server**.\nThe server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens.\n3. **client**.\nAn application making protected resource requests on behalf of the resource owner and with its authorization.  Client usually is an application executes in your browser, on a desktop, or mobile devices.\n4. **authorization server**.\nThe server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization.\n\nIn this project, **resource owner** is our end user.\nWe implemented other 3 roles in Typescript.\nThe client React app takes the role of **client**.\nThe Node.js server takes the role of **resource server** and **authorization server**.\n\n#### Resource server\n\nAs a **resource server**, the Node.js server owns articles written by user.\nAlso it can ask **authorization server** to authenticate the request send by **client**.\nIf **authorization server** says this is authorized request, **resource server** will start its own jobs such as updating an article.\n\n| Folder Path                        | Description                                                           |\n| ---------------------------------- | --------------------------------------------------------------------- |\n| server/config/passport-consumer.ts | We name it suffixed with consumer because it's the access token's consumer. In this file the **resource server** announces that it will ask **authorization server** for authorizing with [OAuth2 strategy](https://github.com/jaredhanson/passport-oauth2). |\n| server/config/oauth2orize-strategy.ts| In this file we add an adapter to the [OAuth2 strategy](https://github.com/jaredhanson/passport-oauth2). This adapter is used to transform the user profile object from **authorization server** to **resource server** . |\n| server/routes/auth.ts              | Defines routes start with `/auth/oauth2`, these routes configures **resource server** on how to interact with **authorization server**. You can add 3rd party authentication routes here like `/auth/facebook`, `/auth/twitter`, etc. All the routes for role of **resource server** should start with `/auth` |\n| server/controller/article.ts       | CRUD operations of article. In this file the **resource server** does its own jobs. |\n| server/controller/auth.ts          | Defines route controllers for `/auth/oauth2/callback`. This controller handles the callback from **authorization server**. In this callback the **resource server** can save the user information in its own DB, and forward the user information as well as access token to the **client**. You can add more callback controllers here for other 3rd party **authorization server**, such as Facebook. Then the routes for the callback should be like `/auth/facebook/callback`. |\n\n\u003e **Note!** In our DB the collection named `User` is owned by **authorization server** exclusively.\n\u003e In the callback controller of **resource server** the user account is not saved into the/an `User` collection.\n\u003e If you would like to import a 3rd party token provider such as Facebook, you need to create a collection like `User` in MongoDB, which is owned by the **resource server**.\n\u003e Then the callback controller should store user info into that `User` collection.\n\u003e Also the added `User` collection will not contain password or other credential info of account.\n\n#### Authorization server\n\nAs an **authorization server**, the Node.js server owns user accounts and profiles.\nIt can respond authorization requests coming from **resource server**, i.e. verify the access token, then send back an corresponding `User` object to the **resource server** if the token is valid.\n\n| Folder Path                        | Description                                                           |\n| ---------------------------------- | --------------------------------------------------------------------- |\n| server/config/passport-provider.ts | We name it suffixed with provider because it's the access token's provider. In this file the **authorization server** handles sign-in requests by `LocalStrategy`, and handles authorization requests by `BearerStrategy`. |\n| server/config/oauth2orize-server.ts| [oauth2orize](https://github.com/jaredhanson/oauth2orize) is an authorization server toolkit for Node.js. In this file we imported oauth2orize and defined how should the OAuth2Server work in each of the authorization phases. |\n| server/routes/oauth2.ts            | Defines routes start with `/oauth2`, these routes configures **authorization server** on how to handle authorize, login, sign up, and profile updating, etc. |\n| server/controller/oauth2.ts        | Defines route handlers on how to handle authorize, login, sign up, and profile updating, etc. It works with the OAuth2Server defined in [server/config/oauth2orize-server.ts](server/config/oauth2orize-server.ts), and executes DB operations in `User` collection. |\n\n#### Summary of OAuth2 server\n\nFor developers who would like to use the authorizing mechanism in this project, he/she just need to know how to protect his/her REST API.\nThis authorizing mechanism is **the second key point to make the RESTful architecture possible**.\n\nFor developers who would like to go deeper, we can summarize for them that:\n\n1. The Node.js server in this project not only take the role of **resource server**, but also take the role of **authorization server**.\n2. All requests to **resource server** are routed to path start with `/auth` or `/api`; all requests to **authorization server** are routed to path start with `/oauth2`.\n3. If one would like to import 3rd party token provider or **authorization server**, he/she should make changes in the **resource server** part.\n4. You can improve the OAuth2 **authorization server** implementation by adding *expiration time* or *scope* in the `AccessToken` collection. Also necessary code changes should be made in **authorization server** part.\n\n### Server routing \u0026 client routing\n\nIn section [Create React App](##create-react-app) we have mentioned how the Node.js server serves React app and REST APIs.\nBriefly speaking, the Node.js server complete this task in a very simple way.\n\n1. If the url of request starts with `/api`, `/auth`, or `/oauth2`, handle it using its own route handlers.\n2. For all other request url, return the [client/core/build/static/index.html](client/core/build/static/index.html).\n\n#### React-router 4.0+\n\nThe client powered by [react-router 4.0+](https://reacttraining.com/react-router/) handles all routes except those were handled by Node.js server.\nIn the file [client/core/src/App.tsx](client/core/src/App.tsx), react-router 4.0+ shows how this works can be done elegantly.\n\n```Typescript\nexport default class App extends React.Component\u003cProps, States\u003e {\n    render(): React.ReactElement\u003cany\u003e {\n        const notFoundError: Error = {\n            name: \"404 Not Found\",\n            message: `not found for ${window.location.href} `\n        };\n        return (\n            \u003cdiv\u003e\n                \u003cRoute render={ (props) =\u003e \u003cHeader {...props} /\u003e } /\u003e\n                \u003cSwitch\u003e\n                    \u003cRoute exact path=\"/\" render={ (props) =\u003e \u003cHome {...props} /\u003e } /\u003e\n                    \u003cRoute path=\"/login\" render={ (props) =\u003e \u003cLogIn {...props} /\u003e } /\u003e\n                    \u003cRoute path=\"/signup\" render={ (props) =\u003e \u003cSignUp {...props} /\u003e } /\u003e\n                    \u003cRoute path=\"/consent\" render={ (props) =\u003e \u003cConsent {...props} /\u003e } /\u003e\n                    \u003cRoute path=\"/profile\" render={ (props) =\u003e \u003cProfile {...props} /\u003e } /\u003e\n                    {/* add more routes here */}\n                    \u003cRoute render={ (props) =\u003e \u003cErrorPage {...props} error={notFoundError} /\u003e } /\u003e\n                \u003c/Switch\u003e\n                \u003cFooter /\u003e\n            \u003c/div\u003e\n        );\n    }\n}\n```\n\n`\u003cRoute\u003e`s in the `\u003cSwitch\u003e` can only be rendered the first matched one.\nIf none of the `\u003cRoute\u003e`s matched, `\u003cErrorPage error={notFoundError}\u003e` will be rendered.\nPlease refer to the [document](https://reacttraining.com/react-router/core/guides/quick-start) for more usages of react-router 4.0+.\n\n#### Performance perspective\n\nThis RESTful architecture brings significant performance improvement from several aspects:\n\n1. The Node.js server reduces its response payload.\n2. The Node.js server gets rid of the work on constructing html pages.\n3. Since the file [client/core/build/static/index.html](client/core/build/static/index.html) would not change unless you re-deploy you app, it's easily be cached among Internet.\n4. The React app handles navigation locally, users feel no latency when they navigate back and forth in the browser.\n\n### Styling\n\nIn this project, there is no separated file like [client/core/public/css/main.css](client/core/public/css/main.css).\nWe are using [Semantic-UI React](https://react.semantic-ui.com/) because it has following advantages.\n\n1. React style. It's components match the mental model React has given us for composing UI great. Most of the time you are shaping your UI using props instead of classes or inline styles.\n2. It provides many useful components which are suitable to compose a blog app. [Feed](https://react.semantic-ui.com/views/feed/), [Rating](https://react.semantic-ui.com/modules/rating/), and [Comment](https://react.semantic-ui.com/views/comment/) are fancy examples.\n3. [Good support for react-router](https://react.semantic-ui.com/#augmentation).\n4. As its name hinted, using Semantic-UI React you can build your virtual DOM easy-to-read and compact.\n\nOn the other hand, you can easily change the styles of React app by import [other 3rd party libraries](https://hackernoon.com/23-best-react-ui-component-libraries-and-frameworks-250a81b2ac42) and replace existing raw components.\nPlease refer to [official document](https://reactjs.org/docs/faq-styling.html) for more solutions on this problem.\n\nFor the ReactNative project, we are using [NativeBase](https://docs.nativebase.io/) as a UI library, which takes similar role as Semantic-UI for React project.\n\n## How to debug\n\nIn this project, you can debug your server and client **at the same time**.\nYou can debug the server in VS Code, meanwhile you can debug the client in [Chrome](https://www.google.com/chrome/).\n\n\u003e **Note!** If you are going to debug your app in local area networks (LAN),\n\u003e please change the `HOST_NAME_DEV` in file [client/core/src/models/HostUrl.ts](client/core/src/models/HostUrl.ts) from `localhost` to your host IP,\n\u003e e.g. `192.168.1.13`.\n\u003e **Debugging your app on mobile devices** usually requires debugging in LAN.\n\n### Available scripts\n\nWe use [Yarn](https://yarnpkg.com/) as the package manager of this project.\nYou can use `npm` if you prefer.\nYou can run following commands using `yarn \u003ccommand\u003e`.\n\n| Yarn Script | Description |\n| ------------------------- | -------------------------------------------------------------------------------------------------- |\n| **`install`**             | Install all dependencies defined in `package.json` and `client/core/package.json`.                                |\n| `install-server`          | Install all dependencies defined in `package.json`.                  |\n| `install-client`          | Install all dependencies defined in `client/core/package.json`.           |\n| `postinstall`             | Runs automatically after `yarn install` complete its own task. **Do not** run it manually.                   |\n| `build-server`            | Full build on server. Runs ALL build tasks (`build-ts`, `tslint`).   |\n| **`build`**               | Full build on both server and client                                 |\n| **`debug`**               | Performs a full build and then serves the app in watch mode. You can debug both client and server in this circumstance. |\n| `start-client`            | Build web client in `development` environment and start the debugger of client                                   |\n| `start-mobile`            | Build ReactNative project and start the Expo debugging tool, in the Expo debugging tool page you can start mobile client easily    |\n| **`start`**               | Start node server and start the debugger of client. In this circumstance you can only debug the client.      |\n| **`serve`**               | Runs node on [dist/server.js](dist/server.js) which is the apps entry point.         |\n| `build-ts`                | Compiles all source `.ts` files to `.js` files in the `dist` folder. |\n| `watch-ts`                | Same as `build-ts` but continuously watches `.ts` files and re-compiles when needed.                     |\n| `tslint`                  | Runs TSLint on project files                                                                                 |\n| `test`                    | Not ready yet.                                                       |\n| `serve-debug`             | Runs the app with the --inspect flag.                                |\n| `watch-debug`             | The same as `watch` but includes the --inspect flag so you can attach a debugger.                   |\n\n### Debugging website client\n\nAfter you run the command `yarn start` or `yarn debug`, you can visit [http://localhost:3000](http://localhost:3000) using Chrome.\nHit `F12` to open the debug mode of Chrome.\nYou can see the debugging window shows on the right side or bottom of the browser.\nThere are 2 important tabs in the debugging window.\n\n1. _Console_. You can see logs from client in this tab. We added the `redux-logger` middleware in client so you can inspect the redux states transition in this tab.\n2. _Source_. You can find your source code files in this tab. Usually your source code folder shows an orange icon. Also you can set break point and watch variables in this tab.\n\nFrom the [official document](https://developers.google.com/web/tools/chrome-devtools/javascript/) you may find the best practice on how to debug using Chrome.\n\nYou can also integrate [React DevTools](https://github.com/facebook/react-devtools) to boost your debug experience.\n\n### Debugging mobile client\n\nAfter you run the command `yarn start` or `yarn debug`, you can visit [http://localhost:19002](http://localhost:19002) using Chrome. This is the home page of Expo debugging tool.\n\nFor detail of how to debugging **please refer to [Expo debugging document](https://docs.expo.io/versions/v36.0.0/workflow/debugging/)**.\nBriefly speaking you will have similar experience as debugging on website client, they are both using Chrome.\n\n[TODO] This part will be elaborated.\n\n### Debugging server\n\nDebugging is one of the places where VS Code really shines over other editors. Node.js debugging in VS Code is easy to setup and even easier to use.\nThis project comes pre-configured with everything you need to get started.\n\nTo start debugging server you need to run the command first.\n\n```bash\nyarn debug\n```\n\nThen hit `F5` in VS Code, it looks for a top level `.vscode` folder with a `launch.json` file.\nIn this file, you can tell VS Code exactly what you want to do:\n\n```json\n{\n    \"type\": \"node\",\n    \"request\": \"attach\",\n    \"name\": \"Attach by Process ID\",\n    \"processId\": \"${command:PickProcess}\",\n    \"protocol\": \"inspector\"\n}\n```\n\nThis is mostly identical to the \"Node.js: Attach by Process ID\" template with one minor change.\nWe added `\"protocol\": \"inspector\"` which tells VS Code that we're using the latest version of Node which uses a new debug protocol.\n\nWith this file in place, you can hit `F5` to attach a debugger.\nYou will probably have multiple node processes running, so you need to find the one that shows `node dist/server/server.js`.\nNow you can set your breakpoints and wait for them be hit.\n\n### Debugging tests\n\nPlease refer to [Tests](#tests) section.\n\n## Tests\n\nYou can run all of the tests in project using `yarn test`, or run tests for client only using `yarn test-client`.\n\nAlso you can easily debug all of the client tests in debug window of VSCode, since we have configured the debug process in [.vscode/launch.json](.vscode/launch.json).\n\nWe will add more tests and grow the code coverage in near future.\n\n## Deploying the app\n\nThere are many ways to deploy an Node app, and in general, nothing about the deployment process changes because you're using TypeScript.\nIn this section, let's show you how to deploy this project to Azure App Service.\n\n### Prerequisite\n\n- [**Azure account**](https://azure.microsoft.com/en-us/free/) - If you don't have one, you can sign up for free.\nThe Azure free tier gives you plenty of resources to play around with including up to 10 App Service instances, which is what we will be using.\n- [**Docker Desktop**](https://www.docker.com/products/docker-desktop) - Usually you need to sign in or sign up on [Docker hub](https://hub.docker.com/) first.\n\n### Create production MongoDB (Option 1: Azure CosmosDB)\n\nIn this step, you create a MongoDB database in Azure. When your app is deployed to Azure, it uses this cloud database.\nFor MongoDB, we use Azure Cosmos DB. Cosmos DB supports MongoDB client connections.\n\n#### Open Azure Cloud Shell\n\n1. Sign in [Azure Portal](https://portal.azure.com) using your account.\n2. Open [Azure cloud shell button](https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-nodejs-mongodb-app#open-azure-cloud-shell) on the menu in the upper-right corner of the portal.\n3. Then if you are prompted that **You have no storage mounted**, just click **Create Storage**.\n\n#### Create a resource group\n\nIn the opened shell enter following command.\nChange the location according to your preference.\n\n```bash\naz group create --name myResourceGroup --location \"West Europe\"\n```\n\nAfter entering this you should get a Json response in the shell.\nWith following property in it.\n\n```json\n\"properties\": {\n    \"provisioningState\": \"Succeeded\"\n}\n```\n\n#### Create a Cosmos DB account\n\nIn the following command, substitute a unique Cosmos DB name for the `\u003ccosmosdb_name\u003e` placeholder.\nThis name is used as the part of the Cosmos DB endpoint, [https://\u003ccosmosdb_name\u003e.documents.azure.com/](https://\u003ccosmosdb_name\u003e.documents.azure.com/), so the name needs to be unique across all Cosmos DB accounts in Azure.\nThe name must contain only lowercase letters, numbers, and the hyphen (-) character, and must be between 3 and 50 characters long.\n\n```bash\naz cosmosdb create --name \u003ccosmosdb_name\u003e --resource-group myResourceGroup --kind MongoDB\n```\n\nWhen the Cosmos DB account is created several minutes later, the Azure CLI shows information similar to the following example:\n\n```json\n{\n  \"consistencyPolicy\":\n  {\n    \"defaultConsistencyLevel\": \"Session\",\n    \"maxIntervalInSeconds\": 5,\n    \"maxStalenessPrefix\": 100\n  },\n  \"databaseAccountOfferType\": \"Standard\",\n  \"documentEndpoint\": \"https://\u003ccosmosdb_name\u003e.documents.azure.com:443/\",\n  \"failoverPolicies\": \"\",\n  \"...\" : \"Output truncated for readability\"\n}\n```\n\n#### Retrieve the database key\n\nTo connect to the Cosmos DB database, you need the database key.\nIn the Cloud Shell, use following command to retrieve the primary key.\n\n```bash\naz cosmosdb list-keys --name \u003ccosmosdb_name\u003e --resource-group myResourceGroup\n```\n\nThe Azure CLI shows information similar to the following example:\n\n```json\n{\n  \"primaryMasterKey\": \"RS4CmUwzGRASJPMoc0kiEvdnKmxyRILC9BWisAYh3Hq4zBYKr0XQiSE4pqx3UchBeO4QRCzUt1i7w0rOkitoJw==\",\n  \"primaryReadonlyMasterKey\": \"HvitsjIYz8TwRmIuPEUAALRwqgKOzJUjW22wPL2U8zoMVhGvregBkBk9LdMTxqBgDETSq7obbwZtdeFY7hElTg==\",\n  \"secondaryMasterKey\": \"Lu9aeZTiXU4PjuuyGBbvS1N9IRG3oegIrIh95U6VOstf9bJiiIpw3IfwSUgQWSEYM3VeEyrhHJ4rn3Ci0vuFqA==\",\n  \"secondaryReadonlyMasterKey\": \"LpsCicpVZqHRy7qbMgrzbRKjbYCwCKPQRl0QpgReAOxMcggTvxJFA94fTi0oQ7xtxpftTJcXkjTirQ0pT7QFrQ==\"\n}\n```\n\nCopy the value of `primaryMasterKey`. You need this information in the next step.\n\n#### Configure the connection string in your Node.js application\n\nIn your Typescript MERN project open file [.env.production](.env.production).\nReplace the two `\u003ccosmosdb_name\u003e` placeholders with your Cosmos DB database name, and replace the `\u003cprimary_master_key\u003e` placeholder with the key you copied in the previous step.\n\n```text\nMONGODB_URI=mongodb://\u003ccosmosdb_name\u003e:\u003cprimary_master_key\u003e@\u003ccosmosdb_name\u003e.documents.azure.com:10250/typescript-mern-starter?ssl=true\u0026sslverifycertificate=false\n```\n\nThe `ssl=true` option is required because Cosmos DB requires SSL. Save your changes.\n\n### Create production MongoDB (Option 2: MongoDB Atlas)\n\n[MongoDB Atlas](https://www.mongodb.com/cloud/atlas) provides free tier cluster for up to 512MB storage. It is more suitable for startup or prototype projects comparing to Azure CosmosDB.\n\nTo build a free MongoDB service, you can follow below steps.\n\n1. [Register a MongoDB account](https://cloud.mongodb.com/user?signedOut=true#/atlas/register/accountProfile).\n2. After sign in to the cloud atlas, create a free tier (M0 Sandbox) cluster which take Azure as cloud provider.\n3. Click _Connect_ button in the cluster you just created.\n4. In step _(1) Whitelist your connection IP address_, remove the IP restriction by whitelist all IPs (filling 0.0.0.0/0).\n5. In step _(2) Create a MongoDB User_, create a cluster user with admin privilege. Using auto generated password and copy it to somewhere so that you can paste it back later.\n6. Click _Choose a connection method_.\n7. Click _Connect your application_.\n8. In step _(1) Choose your driver version_, select driver as _Node.js_ and version as **_2.2.12 or later_**.\n9. Click to copy the connection string.\n\nIn your Typescript MERN project open file [.env.production](.env.production).\nModify the variable `MONGODB_URI` using the connection string you just copied.\n\n```text\nmongodb://\u003ccluster_user_name\u003e:\u003cpassword\u003e@cluster0-shard-00-00-pyou0.azure.mongodb.net:27017,cluster0-shard-00-01-pyou0.azure.mongodb.net:27017,cluster0-shard-00-02-pyou0.azure.mongodb.net:27017/\u003cyour_db_name\u003e?ssl=true\u0026replicaSet=Cluster0-shard-0\u0026authSource=admin\u0026retryWrites=true\u0026w=majority\n```\n\nRemember to replace the placeholders in above connection string example, especially `\u003cyour_db_name\u003e`.\n\n### Create a production blob storage\n\nBlob storage is used to store multi-medias.\nNow we support Azure blob storage in this project.\nYou can switch to other cloud storage providers easily by modifying the code in [server/repository/](server/repository/).\n\nPlease refer to [this document](https://docs.microsoft.com/en-us/azure/storage/common/storage-quickstart-create-account?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json\u0026tabs=azure-portal) to create a new storage account on Azure.\n\nCopy the account name and access key in Settings.\nThen you can paste your `STORAGE_ACCOUNT` and `STORAGE_ACCOUNT_KEY` in the file [.env.production](.env.production).\n\n\u003e **Note!** In development environment, the project store the files in disk instead of cloud storage.\n\u003e Before you can test the cloud storage in development environment,\n\u003e you need to modify [server\\repository\\storage.ts](server\\repository\\storage.ts),\n\u003e and paste your `STORAGE_ACCOUNT` and `STORAGE_ACCOUNT_KEY` in the file [.env.development](.env.development).\n\n### Test the application in production mode\n\nIn file [client/core/src/models/HostUrl.ts](client/core/src/models/HostUrl.ts), change the `HOST_NAME_PROD` to the `http://localhost`.\nMeanwhile change the `HOST_PORT_PROD` from 80 to 3000 because your local 80 port may have been blocked.\n\nOpen your local terminal.\nSwitch the local node env from `development` to `production` by entering following commands.\n\n```bash\n## bash\nexport NODE_ENV=production\n```\n\n```powershell\n## powershell\n$env:NODE_ENV = \"production\"\n```\n\nPlease remember to switch the `NODE_ENV` back to `development` once you are done this section.\n\nBuild the production for your TypeScript MERN project.\n\n```bash\nyarn build\n```\n\nStart your local production server.\n\n```bash\nyarn serve\n```\n\nNavigate to [http://localhost:3000](http://localhost:3000) in a browser.\nClick _Sign Up_ in the top menu and create a test user.\nIf you are successful creating a user and logging in, then your app is writing data to the Cosmos DB database in Azure successfully.\nYou can verify the data in your Azure portal's **Azure Cosmos DB account** page using **Data Explorer** or in your **MongoDB Cluster** by clicking collection button.\n\nIn the terminal, stop Node.js by typing _Ctrl+C_.\n\n### Build app into a Docker image\n\nFirstly, we will [deploy the production app to Docker image](https://docs.docker.com/get-started/part2/) because of its great flexibility.\nNowadays almost every cloud service support deploying web app using Docker image.\nTherefore once we have a well constructed Docker image then we can easily deploy our app to **any platform** with little adaption.\nIn next section we will deploy the Docker image generated in this section to [Azure app service](https://docs.microsoft.com/en-us/azure/app-service/containers/quickstart-docker-go).\nLet's generate the Docker image locally in this section.\n\n#### Configure environment variables for production\n\nIn file [client/core/src/models/HostUrl.ts](client/core/src/models/HostUrl.ts), change the `HOST_NAME_PROD` to the target app url.\nMeanwhile change the `HOST_PORT_PROD` from 3000 back to 80.\n\nAt the same time, in the string array `CORS_WHITELIST`, you need to add **all of your possible domain names** into it.\nFor example, `\"https://www.tsmernstarter.com\"` and `\"https://tsmernstarter.com\"`.\n\n#### Build app into a local Docker image\n\nWe are ready to build the app.\nMake sure you are still at the root directory in your repository, which includes a `Dockerfile`\n\nNow run the build command.\nThis creates a Docker image, which we’re going to name using the --tag option.\nUse -t if you want to use the shorter option.\nReplace \u003cyour_app_name\u003e with your desired app name.\nThis command will take your several minutes to finish for the first time you run it.\n\n```bash\ndocker build --tag=\u003cyour_app_name\u003e .\n```\n\nWhere is your built image?\nIt’s in your machine’s local Docker image registry:\n\n```bash\n$ docker image ls\n\nREPOSITORY            TAG               IMAGE ID\n\u003cyour_app_name\u003e       latest            326387cea398\n```\n\n#### Push Docker image to Docker hub\n\nIf you don’t have a Docker account, sign up for one at [hub.docker.com](hub.docker.com).\nMake note of \u003cyour_username\u003e.\n\nLog in to the Docker public registry on your local machine.\n\n```bash\ndocker login\n```\n\nWe need to tag the image with a meaningful version label using following command, e.g. azure.\nReplace \u003cyour_app_name\u003e and \u003cyour_username\u003e, and run the command.\n\n```bash\ndocker tag \u003cyour_app_name\u003e \u003cyour_username\u003e/\u003cyour_app_name\u003e:azure\n```\n\nFinally, upload your tagged image to the repository:\n\n```bash\ndocker push \u003cyour_username\u003e/\u003cyour_app_name\u003e:azure\n```\n\nOnce complete, the results of this upload are publicly available.\nIf you log in to Docker Hub, you see the new image there, with its pull command.\n\n### Create an Azure app service using Docker image\n\nTraditionally, we can deploy a node.js app using git repository on Azure app service.\nThat is to say, you can push your git repository to the Azure app service, then it will start your app by running `npm run start`.\nIn practice this is not a easy-to-use approach since you have very limited ability to control the installation and build process for your app on Azure app service.\n\nUsing Docker image you can get rid of many annoying environment issues, and will easily migrate your app to other cloud platforms in future.\n\n#### Add an Azure app service in Azure portal\n\nOpen Azure portal, click the quick link of *App Services*.\nThen click the _+Add_ button.\nYou will probably see the portal looks like following:\n\n![Create an Azure app service in Azure portal](./images/create-app-service.png)\n\nFill the create wizard like this.\n\n- Resource Group: click *Create new*, and name it like `myLinuxGroup`\n- Name: use \u003cyour_app_name\u003e\n- Publish: click *Docker Image*\n- Operating System: Linux\n- Region: choose one near your place\n- Sku and size: Free F1 is OK, you can scale it up later on your demand\nThen click *Next: Docker \u003e*, you will probably see the portal looks like following:\n\n![Choose a Docker image for your app service](./images/choose-docker-image.png)\n\nFill this wizard like following.\n\n- Options: keep it as *Single Container*\n- Image Source: *Docker Hub*\n- Access Type: keep it *public*\n- Image and tag: \u003cyour_username\u003e/\u003cyour_app_name\u003e:azure, the one you just published in previous section\n\nFinally you are ready to create your app service with Docker image.\nClick ***Review and Create***.\nThen click ***Create*** after the portal navigate you to the next page.\n\n#### Verify your Azure app service\n\nAfter click *create* for the Azure app service, you will get the finish notification.\n\n![finish notification](./images/deploy-complete.png)\n\n\u003e **Note!** Indeed it is still preparing the resources internally.\n\u003e If you see 5xx error on your site at [https://\u003cyour_app_name\u003e.azurewebsites.net](https://\u003cyour_app_name\u003e.azurewebsites.net), don't feel frustrated.\n\u003e You have to wait up to 20 minutes until you can visit your new app successfully.\n\nAfter the app is ready, please note that the browser has marked your site trustful, i.e. Azure has served SSL for your site.\n\n**Congratulation!** You have deployed a real working web app!\n\n### Map custom domain and bind SSL certificate\n\nUsually the web address [https://\u003cyour_app_name\u003e.azurewebsites.net](https://\u003cyour_app_name\u003e.azurewebsites.net) cannot fulfil your requirement for a real product, since you would like to give your customer a more concise and noticeable url.\nYou can follow the steps below to adapt the app you just deployed on Azure to a desired domain name.\n\n1. Register a domain you like.\n2. Modify your [client/core/src/models/HostUrl.ts](client/core/src/models/HostUrl.ts), so that `export const HOST_NAME_PROD: string = \"https://\u003cdomain_name_you_registered\u003e\";`\n3. Re-deploy your app to [https://\u003cyour_app_name\u003e.azurewebsites.net](https://\u003cyour_app_name\u003e.azurewebsites.net) by following steps introduced in previous sections.\n4. Follow the tutorial of [map custom domain](https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-custom-domain).\n5. Follow the tutorial of [bind SSL certificate](https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-custom-ssl). Please note that bind a valid SSL certificate is must-do for Typescript-MERN-starter projects. \n\n### Deploy the mobile apps\n\nPlease refer to [Expo publishing documents](https://docs.expo.io/versions/v36.0.0/workflow/publishing/) for detail steps.\nExpo managed the deployment process sophisticatedly for you.\n\n[TODO] This part will be elaborated.\n\n### Summary of deployment\n\nFrom this part we can see that deploy a Typescript-MERN-starter project to Azure is very easy.\nWhat you have to be worry about is just to configure the environment variables correctly.\n\nFurther more, you can do following to improve your engineering experience if you are using Azure as your cloud platform.\n\n1. You can [configure the CI/CD procedure](https://docs.microsoft.com/en-us/azure/app-service/containers/app-service-linux-ci-cd) on Azure app service so that you can save a lot of mouse click in future.\n2. You can write your own [docker-compose.yml](https://docs.docker.com/get-started/part3/) to manage/orchestrate multiple services including your app service. For example you can add the [mongodb](https://hub.docker.com/_/mongo) service so that you can avoid using the Azure Cosmos DB. Then when you deploy your docker image, choose *Docker Compose (Preview)* instead of *Single Container* for *Options*.\n\nIf you don't like Azure, e.g. you prefer AWS, you can easily [deploy your Docker image](https://aws.amazon.com/getting-started/tutorials/deploy-docker-containers/) to AWS too.\nThe flexibility of Docker make the migration from one platform to another very simple.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdirheimerb%2Fexpress-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdirheimerb%2Fexpress-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdirheimerb%2Fexpress-starter/lists"}