Skip to content

Commit

Permalink
feat: add base structure (#5)
Browse files Browse the repository at this point in the history
* feat: health check

* feat: init main.ts

* feat: update readme

* feat: add swagger

* feat: add configuration

* feat: add versioning

* feat: connect orm

* feat: add common entity

* feat: add typeorm migration

* feat: add user query

* feat: add authenticate

* feat: add typeorm custom repository

* feat: login-by email

* feat: create token

* feat: return token when login

* feat: add jwt auth guard

* fix: unit test
  • Loading branch information
Notekunn authored Nov 10, 2022
1 parent ac500c1 commit a1e7eb7
Show file tree
Hide file tree
Showing 59 changed files with 2,275 additions and 90 deletions.
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
root = true
[*]
end_of_line = lf
15 changes: 15 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
SERVICE_HOST=0.0.0.0
SERVICE_PORT=3333

DB_PORT=localhost
DB_PORT=5432
DB_USERNAME=admin
DB_PASSWORD=admin
DB_NAME=admin
DB_LOGGING=true
DB_SSL=false
DB_AUTO_RUN_MIGRATIONS=true
DB_AUTO_SYNC=false

JWT_SECRET_KEY=top_secret
JWT_EXPIRATION_TIME=7d
13 changes: 7 additions & 6 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@ module.exports = {
tsconfigRootDir: __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
plugins: ['@typescript-eslint/eslint-plugin', 'import', 'simple-import-sort'],
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
root: true,
env: {
node: true,
Expand All @@ -21,7 +18,11 @@ module.exports = {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
'prettier/prettier': ['error'],
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'import/no-default-export': 'warn',
'@typescript-eslint/no-empty-function': 'off',
},
}
4 changes: 3 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ jobs:

- name: Check lint
run: yarn lint


- name: Run test
run: yarn test
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ lerna-debug.log*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/extensions.json

.env
2 changes: 1 addition & 1 deletion .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no -- commitlint --edit ${1}
npx --no -- commitlint --edit
11 changes: 6 additions & 5 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"semi": false,
"singleQuote": true,
"printWidth": 120,
"trailingComma": "all",
"useTabs": false
"semi": false,
"singleQuote": true,
"printWidth": 120,
"trailingComma": "all",
"useTabs": false,
"endOfLine": "lf"
}
40 changes: 38 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="200" alt="Nest Logo" /></a>
<a href="https://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" height="80" alt="Nest Logo" /></a>
<a href="https://typeorm.io/" target="blank"><img src="https://avatars.githubusercontent.com/u/20165699" height="80" alt="TypeORM Logo" /></a>
<a href="https://www.postgresql.org/" target="blank"><img src="https://www.postgresql.org/media/img/about/press/elephant.png" height="80" alt="PostgreSQL Logo" /></a>
<a href="https://jestjs.io/" target="blank"><img src="https://raw.githubusercontent.com/facebook/jest/main/website/static/img/jest.png" height="80" alt="Jest Logo" /></a>
<a href="https://prettier.io/" target="blank"><img src="https://raw.githubusercontent.com/prettier/prettier/main/website/static/icon.png" height="80" alt="Prettier Logo" /></a>
<a href="https://eslint.org/" target="blank"><img src="https://raw.githubusercontent.com/eslint/archive-website/e19d0bd4b5c116996f4cd94d4e90df5cc4367236/assets/img/logo.svg" height="80" alt="ESLint Logo" /></a>
<a href="https://docs.docker.com/" target="blank"><img src="https://www.docker.com/wp-content/uploads/2022/03/Moby-logo.png" height="80" alt="Docker Logo" /></a>
</p>

<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
<p align="center">
<a href="https://github.com/features/actions" target="blank"><img src="https://avatars.githubusercontent.com/u/44036562" height="80" alt="GitHub Actions Logo" /></a>
<a href="https://cloud.google.com/kubernetes-engine" target="blank"><img src="https://raw.githubusercontent.com/kubernetes/kubernetes/master/logo/logo.png" height="80" alt="Kubernetes Logo" /></a>
<a href="https://commitlint.js.org/" target="blank"><img src="https://raw.githubusercontent.com/conventional-changelog/commitlint/master/docs/assets/icon.svg" height="80" alt="CommitLint Logo" /></a>
<a href="https://semantic-release.gitbook.io/semantic-release/" target="blank"><img src="https://raw.githubusercontent.com/semantic-release/semantic-release/master/media/semantic-release-logo.svg" height="80" alt="Semantic Release Logo" /></a>
<a href="https://github.com/nestjs/swagger" target="blank"><img src="https://raw.githubusercontent.com/swagger-api/swagger-ui/master/dist/favicon-32x32.png" height="80" alt="CommitLint Logo" /></a>
<a href="https://www.fastify.io/" target="blank"><img src="https://github.com/fastify/graphics/raw/HEAD/fastify-landscape-outlined.svg" height="80" alt="Fastify Logo" /></a>
</p>

## Description

Expand Down Expand Up @@ -44,3 +57,26 @@ $ npm run test:e2e
# test coverage
$ npm run test:cov
```

## TypeORM

```bash
# generate migration
yarn migration:generate MigrationName
# or
yarn build && yarn typeorm migration:generate -p ./src/database/migrations/MigrationName

# run migration
yarn migration:run
```

- Other commands:

```bash
# drop schema
yarn typeorm schema:drop

# create migration
yarn migration:create MigrationName

```
21 changes: 21 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: '3.4'

services:
db:
image: postgres:latest
environment:
- 'POSTGRES_USER=admin'
- 'POSTGRES_PASSWORD=admin'
volumes:
- data:/var/lib/postgresql/data
ports:
- 5432:5432
restart: always
networks:
- db-network
volumes:
data: null

networks:
db-network:
driver: bridge
4 changes: 2 additions & 2 deletions lint-staged.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
'./src/**/*.{js,jsx,ts,tsx,json,css,scss,md}': ['yarn format:write'],
'./src/**/*.+(js|json|ts|tsx)': ['yarn lint:fix'],
'./src/**/*.{json,css,scss,md}': ['yarn format:write'],
'./src/**/*.+(ts|tsx)': ['yarn lint:fix'],
}
32 changes: 31 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"private": true,
"license": "UNLICENSED",
"scripts": {
"prepare": "husky install",
"prebuild": "rimraf dist",
"build": "nest build",
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
Expand All @@ -16,6 +17,11 @@
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js -d ./src/ormconfig.ts",
"migration:generate": "f() { yarn build && yarn typeorm migration:generate -p \"./src/databases/migrations/$@\"; }; f",
"migration:run": "yarn build && yarn typeorm migration:run",
"migration:revert": "yarn typeorm migration:revert",
"migration:create": "f() { yarn typeorm migration:create \"./src/databases/migrations/$@\"; }; f",
"start:prod": "node dist/main",
"test": "jest",
"test:watch": "jest --watch",
Expand All @@ -24,16 +30,35 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@fastify/helmet": "^10.0.2",
"@fastify/static": "^6.5.0",
"@nestjs/common": "^9.0.0",
"@nestjs/config": "^2.2.0",
"@nestjs/core": "^9.0.0",
"@nestjs/cqrs": "^9.0.1",
"@nestjs/jwt": "^9.0.0",
"@nestjs/passport": "^9.0.0",
"@nestjs/platform-express": "^9.0.0",
"@nestjs/platform-fastify": "^9.1.6",
"@nestjs/swagger": "^6.1.3",
"@nestjs/typeorm": "^9.0.1",
"bcrypt": "^5.1.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"morgan": "^1.10.0",
"passport": "^0.6.0",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"pg": "^8.8.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0"
"rxjs": "^7.2.0",
"typeorm": "^0.3.10"
},
"devDependencies": {
"@commitlint/cli": "^17.2.0",
"@commitlint/config-conventional": "^17.2.0",
"@nestjs-architects/typed-cqrs": "^1.0.0",
"@nestjs/cli": "^9.0.0",
"@nestjs/schematics": "^9.0.0",
"@nestjs/testing": "^9.0.0",
Expand All @@ -45,13 +70,18 @@
"@semantic-release/release-notes-generator": "^10.0.3",
"@types/express": "^4.17.13",
"@types/jest": "28.1.8",
"@types/morgan": "^1.9.3",
"@types/node": "^16.0.0",
"@types/passport": "^1.0.11",
"@types/passport-jwt": "^3.0.7",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-simple-import-sort": "^8.0.0",
"husky": "^8.0.1",
"jest": "28.1.3",
"lint-staged": "^13.0.3",
Expand Down
13 changes: 9 additions & 4 deletions src/app.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import { ConfigModule } from '@nestjs/config'
import { Test, TestingModule } from '@nestjs/testing'

import { AppController } from './app.controller'
import { AppService } from './app.service'
import { appConfiguration } from './configurations/app.config'
import { jwtConfiguration } from './configurations/jwt.config'
import { typeormConfiguration } from './configurations/typeorm.config'

describe('AppController', () => {
let appController: AppController

beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
controllers: [AppController],
providers: [AppService],
imports: [ConfigModule.forRoot({ load: [appConfiguration, typeormConfiguration, jwtConfiguration] })],
providers: [],
}).compile()

appController = app.get<AppController>(AppController)
})

describe('root', () => {
it('should return "Hello World!"', () => {
expect(appController.getHello()).toBe('Hello World!')
it('should return version when health check', () => {
expect(appController.healthCheck().version).toMatch(/^v(\d+).(\d+).(\d+)$/g)
})
})
})
17 changes: 12 additions & 5 deletions src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import { Controller, Get } from '@nestjs/common'
import { AppService } from './app.service'
import { ConfigService } from '@nestjs/config'
import { ApiTags } from '@nestjs/swagger'

import { AppConfiguration } from './configurations/app.config'

@Controller()
@ApiTags('app')
export class AppController {
constructor(private readonly appService: AppService) {}
constructor(private readonly configService: ConfigService) {}

@Get()
getHello(): string {
return this.appService.getHello()
@Get('/healthz')
healthCheck() {
const { version } = this.configService.get<AppConfiguration>('app')
return {
version: `v${version}`,
}
}
}
26 changes: 23 additions & 3 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
import { UserModule } from '@modules/users/user.module'
import { Module } from '@nestjs/common'
import { ConfigModule, ConfigService } from '@nestjs/config'
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'

import { AppController } from './app.controller'
import { AppService } from './app.service'
import { appConfiguration } from './configurations/app.config'
import { jwtConfiguration } from './configurations/jwt.config'
import { typeormConfiguration } from './configurations/typeorm.config'
import { AuthModule } from './modules/auth/auth.module'

const appModules = [AuthModule, UserModule]

@Module({
imports: [],
imports: [
ConfigModule.forRoot({
ignoreEnvFile: process.env.NODE_ENV === 'production',
load: [appConfiguration, typeormConfiguration, jwtConfiguration],
isGlobal: true,
}),
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: (configService: ConfigService) => configService.get<TypeOrmModuleOptions>('orm'),
}),
...appModules,
],
controllers: [AppController],
providers: [AppService],
providers: [],
})
export class AppModule {}
8 changes: 0 additions & 8 deletions src/app.service.ts

This file was deleted.

8 changes: 8 additions & 0 deletions src/common/entities/abstract.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { PrimaryGeneratedColumn } from 'typeorm'

import { BaseEntity } from './base.entity'

export class AbstractEntity extends BaseEntity {
@PrimaryGeneratedColumn()
id: number
}
12 changes: 12 additions & 0 deletions src/common/entities/base.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { AggregateRoot } from '@nestjs/cqrs'
import { CreateDateColumn, DeleteDateColumn, UpdateDateColumn } from 'typeorm'
export class BaseEntity extends AggregateRoot {
@CreateDateColumn({ type: 'timestamp with time zone' })
createdAt: Date

@UpdateDateColumn({ type: 'timestamp with time zone' })
updatedAt: Date

@DeleteDateColumn({ type: 'timestamp with time zone', nullable: true })
deletedAt?: Date
}
15 changes: 15 additions & 0 deletions src/configurations/app.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { registerAs } from '@nestjs/config'

export interface AppConfiguration {
readonly host: string
readonly port: number
readonly version: string
}

export const appConfiguration = registerAs<AppConfiguration>('app', () => {
return {
host: process.env.SERVICE_HOST || '0.0.0.0',
port: +process.env.SERVICE_PORT || 3000,
version: process.env.SERVICE_VERSION || process.env.npm_package_version || '0.0.0',
}
})
9 changes: 9 additions & 0 deletions src/configurations/jwt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { registerAs } from '@nestjs/config'
import { JwtModuleOptions } from '@nestjs/jwt'

export const jwtConfiguration = registerAs<JwtModuleOptions>('jwt', () => ({
secret: process.env.JWT_SECRET_KEY || 'secret',
signOptions: {
expiresIn: process.env.JWT_EXPIRATION_TIME || '7d',
},
}))
Loading

0 comments on commit a1e7eb7

Please sign in to comment.