mean Documentation

The MEAN stack uses Mongo, Express, Angular(6) and Node for simple and scalable fullstack js applications

12,043 stars TypeScript TypeScript 1 file ยท ~3,780 tokens #angular#express#javascript#mongodb#node#stack
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy mean on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name mean -p 4040:4040 --restart always mean
Configured Services & Ports
โš™๏ธ app
image: mean
๐Ÿ”Œ Ports: 4040:4040
โš™๏ธ mongo
image: mongo:4.2
docker-compose.yml
yaml (docker-compose.yml)
version: '3.8'

services:
  app:
    build: ./
    image: mean
    ports:
      - 4040:4040
    environment:
      NODE_ENV: production
      SERVER_PORT: 4040
      JWT_SECRET: 0a6b944d-d2fb-46fc-a85e-0295c986cd9f
      MONGO_HOST: mongodb://mongo/mean
    restart: always
    depends_on:
      - mongo

  mongo:
    image: mongo:4.2
    volumes:
      - mongo_data:/data/db

volumes:
  mongo_data:

File: README.md

Welcome to the mean stack

The mean stack is intended to provide a simple and fun starting point for cloud native fullstack javascript applications.
MEAN is a set of Open Source components that together, provide an end-to-end framework for building dynamic web applications; starting from the top (code running in the browser) to the bottom (database). The stack is made up of:

  • MongoDB : Document database โ€“ used by your back-end application to store its data as JSON (JavaScript Object Notation) documents
  • Express (sometimes referred to as Express.js): Back-end web application framework running on top of Node.js
  • Angular (formerly Angular.js): Front-end web app framework; runs your JavaScript code in the user's browser, allowing your application UI to be dynamic
  • Node.js : JavaScript runtime environment โ€“ lets you implement your application back-end in JavaScript

Pre-requisites

Installation

text
git clone https://github.com/linnovate/mean
cd mean
cp .env.example .env
yarn
yarn start (for development)

Docker based

โš ๏ธ Make sure your Docker version is 19.03.0+.

text
git clone https://github.com/linnovate/mean
cd mean
cp .env.example .env
docker-compose up -d

Credits

  • The MEAN name was coined by Valeri Karpov.
  • Initial concept and development were done by Amos Haviv and sponsored by Linnovate.
  • Inspired by the great work of Madhusudhan Srinivasa.

File: _config.yml

theme: jekyll-theme-minimal
logo: https://www.linnovate.net/sites/all/themes/linnovate/images/mean-picture.png


File: angular.json

{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"mean": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"tsConfig": "./tsconfig.app.json",
"polyfills": "src/polyfills.ts",
"assets": ["src/assets", "src/favicon.ico"],
"styles": ["src/styles.scss"],
"scripts": [],
"aot": false,
"vendorChunk": true,
"extractLicenses": false,
"buildOptimizer": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true
},
"configurations": {
"production": {
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "mean:build"
},
"configurations": {
"production": {
"browserTarget": "mean:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "mean:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"karmaConfig": "./karma.conf.js",
"polyfills": "src/polyfills.ts",
"tsConfig": "./tsconfig.spec.json",
"scripts": [],
"styles": ["src/styles.scss"],
"assets": ["src/assets", "src/favicon.ico"]
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": ["src//*.ts", "src//*.html"]
}
}
}
}
},
"schematics": {
"@schematics/angular:component": {
"prefix": "app",
"style": "scss"
},
"@schematics/angular:directive": {
"prefix": "app"
}
}
}


File: docker-compose.yml

version: '3.8'

services:
app:
build: ./
image: mean
ports:
- 4040:4040
environment:
NODE_ENV: production
SERVER_PORT: 4040
JWT_SECRET: 0a6b944d-d2fb-46fc-a85e-0295c986cd9f
MONGO_HOST: mongodb://mongo/mean
restart: always
depends_on:
- mongo

mongo:
image: mongo:4.2
volumes:
- mongo_data:/data/db

volumes:
mongo_data:


File: package.json

{
"name": "mean",
"version": "2.0.2",
"license": "MIT",
"scripts": {
"ng": "ng",
"serve": "node server",
"start": "concurrently -c "yellow.bold,green.bold" -n "SERVER,BUILD" "nodemon server" "ng build --watch"",
"build:prod": "ng build --configuration production",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"postinstall": "husky install"
},
"private": true,
"dependencies": {
"@angular/animations": "^15.2.9",
"@angular/cdk": "^15.2.9",
"@angular/common": "^15.2.9",
"@angular/compiler": "^15.2.9",
"@angular/core": "^15.2.9",
"@angular/forms": "^15.2.9",
"@angular/material": "^15.2.9",
"@angular/platform-browser": "^15.2.9",
"@angular/platform-browser-dynamic": "^15.2.9",
"@angular/router": "^15.2.9",
"bcrypt": "^5.0.1",
"body-parser": "^1.18.2",
"compression": "^1.7.2",
"cookie-parser": "^1.4.3",
"cors": "^2.8.4",
"dotenv": "^10.0.0",
"events": "^3.0.0",
"express": "^4.16.3",
"express-async-handler": "^1.1.3",
"express-jwt": "^5.3.1",
"express-validation": "^1.0.2",
"formidable": "^3.1.3",
"helmet": "^4.6.0",
"http-errors": "^1.6.3",
"joi": "^17.4.2",
"jsonwebtoken": "^8.2.1",
"method-override": "^3.0.0",
"mongoose": "^6.0.13",
"morgan": "^1.9.1",
"nodemon": "^2.0.15",
"passport": "^0.4.0",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"rxjs": "^7.4.0",
"swagger-ui-express": "^4.1.6",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^15.2.9",
"@angular-eslint/builder": "14.0.2",
"@angular-eslint/eslint-plugin": "14.0.2",
"@angular-eslint/eslint-plugin-template": "14.0.2",
"@angular-eslint/schematics": "14.0.2",
"@angular-eslint/template-parser": "14.0.2",
"@angular/cli": "^15.2.9",
"@angular/compiler-cli": "^15.2.9",
"@angular/language-service": "^15.2.9",
"@types/jasmine": "~3.6.0",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~15.0.0",
"@typescript-eslint/eslint-plugin": "5.3.0",
"@typescript-eslint/parser": "5.3.0",
"concurrently": "^3.5.1",
"eslint": "^8.2.0",
"husky": "^7.0.2",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~6.3.2",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"lint-staged": "^13.0.3",
"prettier": "^2.7.1",
"ts-node": "~6.1.0",
"typescript": "4.9.5"
}
}


File: tsconfig.app.json

{
"extends": "./tsconfig.json",
"files": [
"src/polyfills.ts",
"src/main.ts"
],
"include": [
"src/**/*.d.ts"
],
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
}


File: tsconfig.json

{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@app/": ["src/app/"]
},
"target": "ES2022",
"typeRoots": ["node_modules/@types"],
"lib": ["ESNext", "DOM"],
"module": "es2020",
"moduleResolution": "node",
"strict": true,
"sourceMap": true,
"declaration": false,
"importHelpers": true,
"experimentalDecorators": true,
"suppressImplicitAnyIndexErrors": true,
"useDefineForClassFields": false
}
}


File: tsconfig.spec.json

{
"extends": "./tsconfig.json",
"compilerOptions": {
"baseUrl": "./",
"module": "commonjs",
"types": [
"jasmine",
"node"
]
},
"files": [
"src/test.ts",
"src/polyfills.ts"
],
"include": [
"src//*.spec.ts",
"src/
/*.d.ts"
]
}


File: tslint.json

{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"deprecation": {
"severity": "warn"
},
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs/Rx"
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"no-output-on-prefix": true,
"no-inputs-metadata-property": true,
"no-outputs-metadata-property": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-output-rename": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true
}
}


File: .eslintrc.json

{
"root": true,
"ignorePatterns": ["projects/**/"],
"overrides": [
{
"files": ["
.ts"],
"parserOptions": {
"project": ["tsconfig.json"],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {}
},
{
"files": ["*.html"],
"extends": ["plugin:@angular-eslint/template/recommended"],
"rules": {}
}
]
}


File: server/config/swagger.json

{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "Mean Application API",
"description": "Mean Application API",
"license": {
"name": "MIT",
"url": "https://opensource.org/licenses/MIT"
}
},
"host": "localhost:4040",
"basePath": "/api/",
"tags": [
{
"name": "Users",
"description": "API for users in the system"
},
{
"name": "Auth",
"description": "API for auth in the system"
}
],
"schemes": [
"http"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"securityDefinitions": {
"AuthHeader": {
"type": "apiKey",
"in": "header",
"name": "Authorization"
}
},
"paths": {
"/auth/login": {
"post": {
"tags": ["Auth"],
"description": "Login to the system",
"parameters": [{
"name": "auth",
"in": "body",
"description": "User auth details",
"schema": {
"type": "object",
"required": ["email", "password"],
"properties": {
"email": {
"type": "string"
},
"password": {
"type": "string"
}
}
}
}],
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "User is loggedin",
"schema": {
"$ref": "#/definitions/User"
}
}
}
}
}
},
"definitions": {
"User": {
"required": [
"email",
"fullname"
],
"properties": {
"_id": {
"type": "string",
"uniqueItems": true
},
"email": {
"type": "string",
"uniqueItems": true
},
"fullname": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"roles": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"Users": {
"type": "array",
"$ref": "#/definitions/User"
},
"Auth": {
"type": "object",
"properties": [{
"token": {
"type": "string"
},
"user": {
"$ref": "#/definitions/User"
}
}]
}
}
}