From 36c73f1cb9938af7dd99ba948e00a14f829f33b8 Mon Sep 17 00:00:00 2001 From: milon27 Date: Mon, 2 Dec 2024 23:02:55 +0600 Subject: [PATCH] refacor + update folder --- .doc/doc.md | 4 +- .env.dev | 3 ++ .env.prod | 3 ++ Dockerfile | 6 +-- docker-compose.dev.yml | 15 -------- docker-compose.local.yml | 38 +++++++++++++++++++ docker-compose.prod.yml | 11 ------ docker-compose.yml | 30 +++++++-------- package.json | 7 ++-- pnpm-lock.yaml | 24 ++++++------ readme.md | 2 +- src/__test__/auth/logged-in-user.test.ts | 2 +- src/__test__/auth/login.test.ts | 6 +-- src/__test__/auth/logout.test.ts | 4 +- src/__test__/auth/register.test.ts | 2 +- src/__test__/data.ts | 4 +- src/__test__/test.util.ts | 2 +- src/common/dto/params.dto.ts | 5 ++- src/common/model/error.model.ts | 2 +- src/config/db/db.ts | 4 +- .../db/schema/{user => }/user.schema.ts | 4 +- src/config/db/utils/dbml.ts | 10 +++++ src/config/env.config.ts | 6 ++- src/{config => }/constant/code.constant.ts | 0 src/{config => }/constant/common.constant.ts | 4 +- src/{config => }/constant/key.constant.ts | 0 .../forget-password.controller.ts | 4 +- .../forget-password/forget-password.router.ts | 2 +- .../login-register.controller.ts | 6 +-- .../login-register/login-register.service.ts | 8 ++-- src/feature/auth/logout/logout.controller.ts | 4 +- src/feature/auth/token/token.controller.ts | 6 +-- .../verify-email/verify-email.controller.ts | 4 +- .../auth/verify-email/verify-email.router.ts | 2 +- .../health-check/health-check.controller.ts | 2 +- src/feature/user/dto/user.dto.ts | 2 +- src/feature/user/user.controller.ts | 2 +- src/feature/user/user.service.ts | 2 +- src/middleware/auth.mid.ts | 2 +- src/middleware/error.mid.ts | 2 +- src/middleware/limiter/email.limiter.ts | 4 +- src/middleware/limiter/global-rete.limiter.ts | 4 +- src/middleware/limiter/pdf.limiter.ts | 4 +- src/middleware/validate.mid.ts | 2 +- src/utils/access-token.util.ts | 4 +- src/utils/date.util.ts | 4 +- src/utils/error-response.util.ts | 2 +- src/utils/my-response.util.ts | 2 +- src/utils/redis.util.ts | 2 +- src/utils/zod.util.ts | 8 ++-- todo.md | 1 + 51 files changed, 158 insertions(+), 125 deletions(-) delete mode 100644 docker-compose.dev.yml create mode 100644 docker-compose.local.yml delete mode 100644 docker-compose.prod.yml rename src/config/db/schema/{user => }/user.schema.ts (94%) create mode 100644 src/config/db/utils/dbml.ts rename src/{config => }/constant/code.constant.ts (100%) rename src/{config => }/constant/common.constant.ts (92%) rename src/{config => }/constant/key.constant.ts (100%) diff --git a/.doc/doc.md b/.doc/doc.md index 22bcfb1..cce2396 100644 --- a/.doc/doc.md +++ b/.doc/doc.md @@ -1 +1,3 @@ -# write postman link \ No newline at end of file +# write postman link + +https://m27lab.postman.co/workspace/M27LAB~849f4e55-931f-4f55-96d9-fad5e24d1590/collection/12238877-777ce19b-5ed0-4a9d-ada9-74506e32d70e?action=share&source=copy-link&creator=12238877&active-environment=fed60369-7ea2-443c-b309-5a013b681d7d \ No newline at end of file diff --git a/.env.dev b/.env.dev index f4ca574..d8189f1 100644 --- a/.env.dev +++ b/.env.dev @@ -9,6 +9,9 @@ TZ=Etc/UTC DATABASE_URL="mysql://root:myPassWord@localhost:3308/test" # test, test # redis +# with ssl +# REDIS_URL="rediss://default:xxxxx@xxxx.upstash.io:6379" +# without ssl REDIS_URL="redis://default:1234567@localhost:6379" # redis cluster (not used) REDIS_CLUSTER_ENABLE='false' diff --git a/.env.prod b/.env.prod index 2ab773b..808b86c 100644 --- a/.env.prod +++ b/.env.prod @@ -9,6 +9,9 @@ TZ=Etc/UTC DATABASE_URL="mysql://root:myPassWord@localhost:3308/test" # test, test # redis +# with ssl +# REDIS_URL="rediss://default:xxxxx@xxxx.upstash.io:6379" +# without ssl REDIS_URL="redis://default:1234567@localhost:6379" # redis cluster (not used) REDIS_CLUSTER_ENABLE='false' diff --git a/Dockerfile b/Dockerfile index 47746ff..50544f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18.13.0-alpine as build +FROM node:20.18.0-alpine as build RUN npm install -g pnpm WORKDIR /app @@ -14,7 +14,7 @@ RUN npm run build # # ------------------dev ------------------- -FROM node:18.13.0-alpine as dev +FROM node:20.18.0-alpine as dev RUN npm install -g pnpm WORKDIR /app @@ -36,7 +36,7 @@ CMD ["/bin/sh", "-c", "pnpm db:migrate:prod && pnpm db:seed:prod && node dist/sr # # ------------------prod ------------------- -FROM node:18.13.0-alpine as prod +FROM node:20.18.0-alpine as prod RUN npm install -g pnpm WORKDIR /app diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml deleted file mode 100644 index df9d1e6..0000000 --- a/docker-compose.dev.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: "3.9" -services: - np_api: - container_name: np_api - build: - context: . - dockerfile: Dockerfile - target: dev - # env_file: - # - .env.local - # depends_on: - # - postgres - # - redis - ports: - - 4000:4000 diff --git a/docker-compose.local.yml b/docker-compose.local.yml new file mode 100644 index 0000000..c4e7e72 --- /dev/null +++ b/docker-compose.local.yml @@ -0,0 +1,38 @@ +services: + mysql: + container_name: mysql + image: mysql:8.0.33 + restart: always + environment: + - MYSQL_ROOT_PASSWORD=myPassWord + - MYSQL_DATABASE=test + ports: + - 3308:3306 + volumes: + - db_vol:/var/lib/mysql + # - .backup-db:/docker-entrypoint-initdb.d + + redis: + container_name: redis + image: redis:7.4.1-alpine + restart: always + volumes: + - redis_vol:/data + environment: + - REDIS_PASSWORD=1234567 + ports: + - 6379:6379 + + api: + container_name: api + build: + context: . + dockerfile: Dockerfile + target: prod + restart: always + ports: + - 4000:4000 + +volumes: + db_vol: + redis_vol: diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml deleted file mode 100644 index 58c41a2..0000000 --- a/docker-compose.prod.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: "3.9" -services: - api: - container_name: api - build: - context: . - dockerfile: Dockerfile - target: prod - restart: always - ports: - - 4000:4000 diff --git a/docker-compose.yml b/docker-compose.yml index 5728ef2..df834d6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,20 +1,7 @@ -version: "3.9" services: - mysql: - container_name: mysql - image: mysql:8.0.33 - restart: always - environment: - - MYSQL_ROOT_PASSWORD=myPassWord - - MYSQL_DATABASE=test - ports: - - 3308:3306 - volumes: - - db_vol:/var/lib/mysql - # - .backup-db:/docker-entrypoint-initdb.d redis: container_name: redis - image: redis:7.0.7-alpine + image: redis:7.4.1-alpine restart: always volumes: - redis_vol:/data @@ -23,6 +10,17 @@ services: ports: - 6379:6379 + nginx_proxy: + container_name: nginx_proxy + image: "jc21/nginx-proxy-manager:latest" + restart: unless-stopped + ports: + - "80:80" + - "81:81" + - "443:443" + volumes: + - ./data:/data + - ./letsencrypt:/etc/letsencrypt + volumes: - db_vol: {} - redis_vol: {} + redis_vol: diff --git a/package.json b/package.json index 1743ac2..d4a9207 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "build": "tsc --outDir dist", "lint": "npx eslint . --fix", "lint:check": "npx eslint .", - "test": "cross-env NODE_ENV=test npm run db:clean && cross-env NODE_ENV=test npm run db:seed && cross-env NODE_ENV=test vitest --config ./vitest.config.mjs", + "test": "cross-env NODE_ENV=test npm run db:migrate && cross-env NODE_ENV=test npm run db:clean && cross-env NODE_ENV=test npm run db:seed && cross-env NODE_ENV=test vitest --config ./vitest.config.mjs", + "dbml:generate": "ts-node src/config/db/utils/dbml.ts", "db:generate": "drizzle-kit generate:mysql", "db:rollback": "drizzle-kit drop --config=drizzle.config.ts", "db:migrate": "ts-node --files src/config/db/utils/migrator.ts", @@ -21,8 +22,7 @@ "db:all:clean": "pnpm db:clean && pnpm redis:clean && pnpm db:seed", "np": "nestpress ", "version:inc": "npm version patch --no-git-tag-version && git add .", - "all:update": "pnpm update -i -L", - "prepare": "husky install" + "all:update": "pnpm update -i -L" }, "keywords": [ "express", @@ -71,6 +71,7 @@ "@typescript-eslint/parser": "7.1.0", "cross-env": "7.0.3", "drizzle-kit": "0.20.14", + "drizzle-dbml-generator": "0.9.0", "eslint": "8.57.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "18.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 56cb930..834da1e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,6 +115,9 @@ devDependencies: cross-env: specifier: 7.0.3 version: 7.0.3 + drizzle-dbml-generator: + specifier: 0.9.0 + version: 0.9.0(drizzle-orm@0.29.4) drizzle-kit: specifier: 0.20.14 version: 0.20.14 @@ -2401,7 +2404,6 @@ packages: /denque@2.1.0: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} - dev: false /depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} @@ -2473,6 +2475,14 @@ packages: wordwrap: 1.0.0 dev: true + /drizzle-dbml-generator@0.9.0(drizzle-orm@0.29.4): + resolution: {integrity: sha512-R/INfHUJNtxUkanSng8suh6er3snYKzMLFCeshqMMtGbrzo1+ulOY6qyrWXkY1d5jLuFwydySUD6bIZSyr0aSg==} + peerDependencies: + drizzle-orm: '>=0.32.0' + dependencies: + drizzle-orm: 0.29.4(mysql2@3.9.2) + dev: true + /drizzle-kit@0.20.14: resolution: {integrity: sha512-0fHv3YIEaUcSVPSGyaaBfOi9bmpajjhbJNdPsRMIUvYdLVxBu9eGjH8mRc3Qk7HVmEidFc/lhG1YyJhoXrn5yA==} hasBin: true @@ -2567,7 +2577,6 @@ packages: optional: true dependencies: mysql2: 3.9.2 - dev: false /duplexer2@0.1.4: resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} @@ -3578,7 +3587,6 @@ packages: resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} dependencies: is-property: 1.0.2 - dev: false /get-assigned-identifiers@1.2.0: resolution: {integrity: sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==} @@ -3915,7 +3923,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 - dev: false /ignore@5.3.1: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} @@ -4102,7 +4109,6 @@ packages: /is-property@1.0.2: resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} - dev: false /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} @@ -4411,7 +4417,6 @@ packages: /long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} - dev: false /loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} @@ -4435,12 +4440,10 @@ packages: /lru-cache@7.18.3: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} - dev: false /lru-cache@8.0.5: resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} engines: {node: '>=16.14'} - dev: false /lru-memoizer@2.2.0: resolution: {integrity: sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==} @@ -4623,14 +4626,12 @@ packages: named-placeholders: 1.1.3 seq-queue: 0.0.5 sqlstring: 2.3.3 - dev: false /named-placeholders@1.1.3: resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} engines: {node: '>=12.0.0'} dependencies: lru-cache: 7.18.3 - dev: false /nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} @@ -5294,7 +5295,6 @@ packages: /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: false /sax@1.3.0: resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} @@ -5347,7 +5347,6 @@ packages: /seq-queue@0.0.5: resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} - dev: false /serve-static@1.15.0: resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} @@ -5558,7 +5557,6 @@ packages: /sqlstring@2.3.3: resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} engines: {node: '>= 0.6'} - dev: false /stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} diff --git a/readme.md b/readme.md index 0cb3a0d..96bbe4c 100644 --- a/readme.md +++ b/readme.md @@ -30,7 +30,7 @@ npx nestpress@latest module category blog ```bash pnpm i - # rename .env.dev (if available) to .env then update db connection string (DATABASE_URL) and other env variable if needed + # rename .env.dev to .env then update db connection string (DATABASE_URL) and other env variable if needed pnpm: db:migrate # reload / reopen vscode to restart TS server diff --git a/src/__test__/auth/logged-in-user.test.ts b/src/__test__/auth/logged-in-user.test.ts index 8899f51..ddecbc8 100644 --- a/src/__test__/auth/logged-in-user.test.ts +++ b/src/__test__/auth/logged-in-user.test.ts @@ -1,7 +1,7 @@ import supertest from "supertest" import { afterAll, beforeAll, describe, expect, it } from "vitest" import app from "../../app" -import { StatusCode } from "../../config/constant/code.constant" +import { StatusCode } from "../../constant/code.constant" import { TestUtil } from "../test.util" describe("logged in user 👤", () => { diff --git a/src/__test__/auth/login.test.ts b/src/__test__/auth/login.test.ts index dc87694..3fa9b08 100644 --- a/src/__test__/auth/login.test.ts +++ b/src/__test__/auth/login.test.ts @@ -1,8 +1,8 @@ import supertest from "supertest" import { afterAll, beforeAll, describe, expect, it } from "vitest" import app from "../../app" -import { StatusCode } from "../../config/constant/code.constant" -import { Constant } from "../../config/constant/common.constant" +import { StatusCode } from "../../constant/code.constant" +import { CommonConstant } from "../../constant/common.constant" import { createUserPayload } from "../data" import { TestUtil } from "../test.util" @@ -44,7 +44,7 @@ describe("login 🎇", () => { it("given admin credentials", async () => { const { statusCode, body } = await supertest(app).post("/v1/auth/login-with-email").send({ email: createUserPayload.user.email, - password: Constant.DEFAULT_ADMIN_PASSWORD, + password: CommonConstant.DEFAULT_ADMIN_PASSWORD, }) expect(statusCode).toBe(StatusCode.OK) expect(body.response.accessToken).toBeDefined() diff --git a/src/__test__/auth/logout.test.ts b/src/__test__/auth/logout.test.ts index d26f5f1..8597dce 100644 --- a/src/__test__/auth/logout.test.ts +++ b/src/__test__/auth/logout.test.ts @@ -1,8 +1,8 @@ import supertest from "supertest" import { afterAll, beforeAll, describe, expect, it } from "vitest" import app from "../../app" -import { StatusCode } from "../../config/constant/code.constant" -import { KeyConstant } from "../../config/constant/key.constant" +import { StatusCode } from "../../constant/code.constant" +import { KeyConstant } from "../../constant/key.constant" import { TestUtil } from "../test.util" // login -> login normal, login invalid, login as admin diff --git a/src/__test__/auth/register.test.ts b/src/__test__/auth/register.test.ts index 218bf91..870441e 100644 --- a/src/__test__/auth/register.test.ts +++ b/src/__test__/auth/register.test.ts @@ -1,7 +1,7 @@ import supertest from "supertest" import { afterAll, beforeAll, describe, expect, it } from "vitest" import app from "../../app" -import { ErrorCode, StatusCode } from "../../config/constant/code.constant" +import { ErrorCode, StatusCode } from "../../constant/code.constant" import { createUserPayload } from "../data" import { TestUtil } from "../test.util" diff --git a/src/__test__/data.ts b/src/__test__/data.ts index d7a5bab..b4c429e 100644 --- a/src/__test__/data.ts +++ b/src/__test__/data.ts @@ -1,4 +1,4 @@ -import { Constant } from "../config/constant/common.constant" +import { CommonConstant } from "../constant/common.constant" import { ILoginWithEmailDto } from "../feature/auth/login-register/dto/login.dto" import { IRegisterDto, RegisterProvider } from "../feature/auth/login-register/dto/register.dto" @@ -12,6 +12,6 @@ export const createUserPayload: IRegisterDto = { user: { ...loginUserPayload, fullName: "test", - timeZone: Constant.TIMEZONE, + timeZone: CommonConstant.TIMEZONE, }, } diff --git a/src/__test__/test.util.ts b/src/__test__/test.util.ts index d648423..3fa706a 100644 --- a/src/__test__/test.util.ts +++ b/src/__test__/test.util.ts @@ -4,8 +4,8 @@ /* eslint-disable no-console */ import { sql } from "drizzle-orm" import { MySqlQueryResult } from "drizzle-orm/mysql2" -import { KeyConstant } from "../config/constant/key.constant" import { db } from "../config/db/db" +import { KeyConstant } from "../constant/key.constant" import { UserService } from "../feature/user/user.service" import { AccessTokenUtil } from "../utils/access-token.util" import { RedisUtil } from "../utils/redis.util" diff --git a/src/common/dto/params.dto.ts b/src/common/dto/params.dto.ts index 35c92e4..500efdc 100644 --- a/src/common/dto/params.dto.ts +++ b/src/common/dto/params.dto.ts @@ -1,5 +1,6 @@ import { z } from "zod" -import { Constant } from "../../config/constant/common.constant" + +import { CommonConstant } from "../../constant/common.constant" import { ZodEmailString, ZodNumericString, ZodSimpleString } from "../../utils/zod.util" export const EmailParamDto = z @@ -29,7 +30,7 @@ export type ISlugParamDto = z.infer export const GetAllQueryParamDto = z .object({ page: ZodNumericString.optional().default("1"), - size: ZodNumericString.optional().default(Constant.PAGE_SIZE.toString()), + size: ZodNumericString.optional().default(CommonConstant.PAGE_SIZE.toString()), }) .strict() diff --git a/src/common/model/error.model.ts b/src/common/model/error.model.ts index ff44c6e..3566899 100644 --- a/src/common/model/error.model.ts +++ b/src/common/model/error.model.ts @@ -1,6 +1,6 @@ /* eslint-disable max-classes-per-file */ -import { ErrorCode, StatusCode } from "../../config/constant/code.constant" +import { ErrorCode, StatusCode } from "../../constant/code.constant" export class ServerError extends Error { statusCode = StatusCode.SERVER_ERROR diff --git a/src/config/db/db.ts b/src/config/db/db.ts index 18da576..14a3d16 100644 --- a/src/config/db/db.ts +++ b/src/config/db/db.ts @@ -2,9 +2,9 @@ import { drizzle } from "drizzle-orm/mysql2" import mysql from "mysql2/promise" import { EnvConfig } from "../env.config" -import * as user from "./schema/user/user.schema" +import * as user from "./schema/user.schema" -const schemas = { +export const schemas = { ...user, } diff --git a/src/config/db/schema/user/user.schema.ts b/src/config/db/schema/user.schema.ts similarity index 94% rename from src/config/db/schema/user/user.schema.ts rename to src/config/db/schema/user.schema.ts index 15cf9c4..2722e21 100644 --- a/src/config/db/schema/user/user.schema.ts +++ b/src/config/db/schema/user.schema.ts @@ -1,6 +1,6 @@ import { sql } from "drizzle-orm" import { boolean, datetime, mysqlEnum, mysqlTable, varchar } from "drizzle-orm/mysql-core" -import { Constant } from "../../../constant/common.constant" +import { CommonConstant } from "../../../constant/common.constant" export const GenderEnum = ["male", "female"] as const export type IGenderEnum = (typeof GenderEnum)[number] @@ -23,7 +23,7 @@ export const UserSchema = mysqlTable("user_table", { zipCode: varchar("zip_code", { length: 50 }), address: varchar("address", { length: 255 }), // extra info - timeZone: varchar("time_zone", { length: 50 }).notNull().default(Constant.TIMEZONE), + timeZone: varchar("time_zone", { length: 50 }).notNull().default(CommonConstant.TIMEZONE), fcmToken: varchar("fcm_token", { length: 255 }), lastLoggedIn: datetime("last_logged_in") .default(sql`(CURRENT_TIMESTAMP)`) diff --git a/src/config/db/utils/dbml.ts b/src/config/db/utils/dbml.ts new file mode 100644 index 0000000..b995fb8 --- /dev/null +++ b/src/config/db/utils/dbml.ts @@ -0,0 +1,10 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { mysqlGenerate } from "drizzle-dbml-generator" // Using Postgres for this example + +import { schemas } from "../db" + +mysqlGenerate({ + schema: schemas, + out: "./resources/dbml/schema.dbml", + relational: true, +}) diff --git a/src/config/env.config.ts b/src/config/env.config.ts index 089d138..189f07b 100644 --- a/src/config/env.config.ts +++ b/src/config/env.config.ts @@ -8,10 +8,14 @@ import path from "path" const initEnvConfig = () => { if (!process.env.parsed) { - const envPath = process.env.NODE_ENV ? `.env.${process.env.NODE_ENV}` : ".env" + // const envPath = process.env.NODE_ENV ? `.env.${process.env.NODE_ENV}` : ".env" + const envPath = ".env" const envFullPath = path.resolve(envPath) try { + if (!fs.existsSync(envFullPath)) { + throw new Error(".env not found! rename .env.dev and create .env, update db url etc.") + } fs.accessSync(envFullPath, fs.constants.R_OK) console.debug("init", envPath) dotenv.config({ path: envFullPath }) diff --git a/src/config/constant/code.constant.ts b/src/constant/code.constant.ts similarity index 100% rename from src/config/constant/code.constant.ts rename to src/constant/code.constant.ts diff --git a/src/config/constant/common.constant.ts b/src/constant/common.constant.ts similarity index 92% rename from src/config/constant/common.constant.ts rename to src/constant/common.constant.ts index 36448eb..7e73911 100644 --- a/src/config/constant/common.constant.ts +++ b/src/constant/common.constant.ts @@ -1,6 +1,6 @@ -import { EnvConfig } from "../env.config" +import { EnvConfig } from "../config/env.config" -export const Constant = { +export const CommonConstant = { DEFAULT_PASSWORD: "123456", GOOGLE_PASSWORD: "nestpress1234", DEFAULT_ADMIN_PASSWORD: "nestpress1234", diff --git a/src/config/constant/key.constant.ts b/src/constant/key.constant.ts similarity index 100% rename from src/config/constant/key.constant.ts rename to src/constant/key.constant.ts diff --git a/src/feature/auth/forget-password/forget-password.controller.ts b/src/feature/auth/forget-password/forget-password.controller.ts index b50a3c4..038b05f 100644 --- a/src/feature/auth/forget-password/forget-password.controller.ts +++ b/src/feature/auth/forget-password/forget-password.controller.ts @@ -2,8 +2,8 @@ import { NextFunction, Request, Response } from "express" import { IEmailParamDto } from "../../../common/dto/params.dto" import { BadRequestError, NotFoundError, ServerError } from "../../../common/model/error.model" import { SendResetPasswordCodeEmail } from "../../../common/module/email/send-email.util" -import { StatusCode } from "../../../config/constant/code.constant" -import { KeyConstant } from "../../../config/constant/key.constant" +import { StatusCode } from "../../../constant/code.constant" +import { KeyConstant } from "../../../constant/key.constant" import { MyResponse } from "../../../utils/my-response.util" import { OtpUtils } from "../../../utils/otp.util" import { UserService } from "../../user/user.service" diff --git a/src/feature/auth/forget-password/forget-password.router.ts b/src/feature/auth/forget-password/forget-password.router.ts index 98ff075..89f8981 100644 --- a/src/feature/auth/forget-password/forget-password.router.ts +++ b/src/feature/auth/forget-password/forget-password.router.ts @@ -1,6 +1,6 @@ import { Router } from "express" import { EmailParamDto } from "../../../common/dto/params.dto" -import { KeyConstant } from "../../../config/constant/key.constant" +import { KeyConstant } from "../../../constant/key.constant" import { emailLimiter } from "../../../middleware/limiter/email.limiter" import { validateMid } from "../../../middleware/validate.mid" import { ResetPasswordDto } from "./dto/forget-password.dto" diff --git a/src/feature/auth/login-register/login-register.controller.ts b/src/feature/auth/login-register/login-register.controller.ts index 4470f4a..09b9a91 100644 --- a/src/feature/auth/login-register/login-register.controller.ts +++ b/src/feature/auth/login-register/login-register.controller.ts @@ -1,7 +1,7 @@ import { NextFunction, Request, Response } from "express" import { NotFoundError, ServerError } from "../../../common/model/error.model" -import { ErrorCode, StatusCode } from "../../../config/constant/code.constant" -import { Constant } from "../../../config/constant/common.constant" +import { ErrorCode, StatusCode } from "../../../constant/code.constant" +import { CommonConstant } from "../../../constant/common.constant" import { MyResponse } from "../../../utils/my-response.util" import { UserService } from "../../user/user.service" import { ILoginWithEmailDto, ILoginWithGoogleDto } from "./dto/login.dto" @@ -52,7 +52,7 @@ export const LoginRegisterController = { const user = await UserService.registerAndGetUser( body.provider === RegisterProvider.simple ? body.user - : { ...body.user, password: Constant.GOOGLE_PASSWORD }, + : { ...body.user, password: CommonConstant.GOOGLE_PASSWORD }, body.provider === RegisterProvider.google ) if (!user) { diff --git a/src/feature/auth/login-register/login-register.service.ts b/src/feature/auth/login-register/login-register.service.ts index 41b7f43..4d40a30 100644 --- a/src/feature/auth/login-register/login-register.service.ts +++ b/src/feature/auth/login-register/login-register.service.ts @@ -3,12 +3,12 @@ import { Request, Response } from "express" import { OAuth2Client, TokenPayload } from "google-auth-library" import { ICurrentUser } from "../../../common/model/current-user.model" import { UnAuthorizedError } from "../../../common/model/error.model" -import { StatusCode } from "../../../config/constant/code.constant" -import { Constant } from "../../../config/constant/common.constant" -import { KeyConstant } from "../../../config/constant/key.constant" import { db } from "../../../config/db/db" import { EnvConfig } from "../../../config/env.config" import { myLogger } from "../../../config/logger" +import { StatusCode } from "../../../constant/code.constant" +import { CommonConstant } from "../../../constant/common.constant" +import { KeyConstant } from "../../../constant/key.constant" import { AccessTokenUtil } from "../../../utils/access-token.util" import { CookieUtil } from "../../../utils/cookie.util" import { MyResponse } from "../../../utils/my-response.util" @@ -39,7 +39,7 @@ export const LoginRegisterService = { } // check password const ckPass = password - ? password === Constant.DEFAULT_ADMIN_PASSWORD + ? password === CommonConstant.DEFAULT_ADMIN_PASSWORD ? true : await bcryptjs.compare(password, `${user.password}`) : true diff --git a/src/feature/auth/logout/logout.controller.ts b/src/feature/auth/logout/logout.controller.ts index 811fed1..556e7c3 100644 --- a/src/feature/auth/logout/logout.controller.ts +++ b/src/feature/auth/logout/logout.controller.ts @@ -1,11 +1,11 @@ import { NextFunction, Request, Response } from "express" import { UnAuthorizedError } from "../../../common/model/error.model" -import { StatusCode } from "../../../config/constant/code.constant" -import { KeyConstant } from "../../../config/constant/key.constant" import { AccessTokenUtil } from "../../../utils/access-token.util" import { CookieUtil } from "../../../utils/cookie.util" import { MyResponse } from "../../../utils/my-response.util" +import { StatusCode } from "../../../constant/code.constant" +import { KeyConstant } from "../../../constant/key.constant" import { UserService } from "../../user/user.service" import { ILogoutDto } from "./dto/logout.dto" diff --git a/src/feature/auth/token/token.controller.ts b/src/feature/auth/token/token.controller.ts index f05245f..e682079 100644 --- a/src/feature/auth/token/token.controller.ts +++ b/src/feature/auth/token/token.controller.ts @@ -1,7 +1,7 @@ import { NextFunction, Request, Response } from "express" -import { StatusCode } from "../../../config/constant/code.constant" -import { ValidityConstant } from "../../../config/constant/common.constant" -import { KeyConstant } from "../../../config/constant/key.constant" +import { StatusCode } from "../../../constant/code.constant" +import { ValidityConstant } from "../../../constant/common.constant" +import { KeyConstant } from "../../../constant/key.constant" import { MyResponse } from "../../../utils/my-response.util" import { RedisUtil } from "../../../utils/redis.util" diff --git a/src/feature/auth/verify-email/verify-email.controller.ts b/src/feature/auth/verify-email/verify-email.controller.ts index 8e8d3ae..6dcc2f4 100644 --- a/src/feature/auth/verify-email/verify-email.controller.ts +++ b/src/feature/auth/verify-email/verify-email.controller.ts @@ -2,8 +2,8 @@ import { NextFunction, Request, Response } from "express" import { IEmailParamDto } from "../../../common/dto/params.dto" import { BadRequestError, ServerError, UnAuthorizedError } from "../../../common/model/error.model" import { SendEmailVerificationCode } from "../../../common/module/email/send-email.util" -import { StatusCode } from "../../../config/constant/code.constant" -import { KeyConstant } from "../../../config/constant/key.constant" +import { StatusCode } from "../../../constant/code.constant" +import { KeyConstant } from "../../../constant/key.constant" import { MyResponse } from "../../../utils/my-response.util" import { OtpUtils } from "../../../utils/otp.util" import { UserService } from "../../user/user.service" diff --git a/src/feature/auth/verify-email/verify-email.router.ts b/src/feature/auth/verify-email/verify-email.router.ts index 6bf085a..755d749 100644 --- a/src/feature/auth/verify-email/verify-email.router.ts +++ b/src/feature/auth/verify-email/verify-email.router.ts @@ -1,6 +1,6 @@ import { Router } from "express" import { EmailParamDto } from "../../../common/dto/params.dto" -import { KeyConstant } from "../../../config/constant/key.constant" +import { KeyConstant } from "../../../constant/key.constant" import { AuthMid } from "../../../middleware/auth.mid" import { emailLimiter } from "../../../middleware/limiter/email.limiter" import { validateMid } from "../../../middleware/validate.mid" diff --git a/src/feature/health-check/health-check.controller.ts b/src/feature/health-check/health-check.controller.ts index 561dda9..bdb523c 100644 --- a/src/feature/health-check/health-check.controller.ts +++ b/src/feature/health-check/health-check.controller.ts @@ -2,10 +2,10 @@ import { sql } from "drizzle-orm" import { Request, Response } from "express" import { DbService } from "../../common/module/db/db.service" import { FCMService } from "../../common/module/fcm/fcm.service" -import { ErrorCode, StatusCode } from "../../config/constant/code.constant" import { db } from "../../config/db/db" import { EnvConfig } from "../../config/env.config" import { myLogger } from "../../config/logger" +import { ErrorCode, StatusCode } from "../../constant/code.constant" import { CommonUtil } from "../../utils/common.util" import { MyErrorResponse, MyResponse } from "../../utils/my-response.util" import { RedisUtil } from "../../utils/redis.util" diff --git a/src/feature/user/dto/user.dto.ts b/src/feature/user/dto/user.dto.ts index 1e67731..1a5b8bf 100644 --- a/src/feature/user/dto/user.dto.ts +++ b/src/feature/user/dto/user.dto.ts @@ -1,5 +1,5 @@ import { z } from "zod" -import { GenderEnum } from "../../../config/db/schema/user/user.schema" +import { GenderEnum } from "../../../config/db/schema/user.schema" import { ZodDateString, ZodEmailString, diff --git a/src/feature/user/user.controller.ts b/src/feature/user/user.controller.ts index 128803f..b1933fc 100644 --- a/src/feature/user/user.controller.ts +++ b/src/feature/user/user.controller.ts @@ -1,6 +1,6 @@ import { NextFunction, Request, Response } from "express" import { ForbiddenError, UnAuthorizedError } from "../../common/model/error.model" -import { StatusCode } from "../../config/constant/code.constant" +import { StatusCode } from "../../constant/code.constant" import { MyResponse } from "../../utils/my-response.util" import { IUpdateUserDto } from "./dto/user.dto" import { UserService } from "./user.service" diff --git a/src/feature/user/user.service.ts b/src/feature/user/user.service.ts index 0506931..bdb718c 100644 --- a/src/feature/user/user.service.ts +++ b/src/feature/user/user.service.ts @@ -2,7 +2,7 @@ import bcryptjs from "bcryptjs" import { eq, sql } from "drizzle-orm" import { ICurrentUser } from "../../common/model/current-user.model" import { IDb, db } from "../../config/db/db" -import { ICreateUser, IUser, IUserNoPassword, UserSchema } from "../../config/db/schema/user/user.schema" +import { ICreateUser, IUser, IUserNoPassword, UserSchema } from "../../config/db/schema/user.schema" import { UniqueId } from "../../utils/common.util" import { ICreateUserDto } from "./dto/user.dto" diff --git a/src/middleware/auth.mid.ts b/src/middleware/auth.mid.ts index 8913574..84e92a0 100644 --- a/src/middleware/auth.mid.ts +++ b/src/middleware/auth.mid.ts @@ -1,6 +1,6 @@ import { NextFunction, Request, Response } from "express" import { ForbiddenError } from "../common/model/error.model" -import { KeyConstant } from "../config/constant/key.constant" +import { KeyConstant } from "../constant/key.constant" import { AccessTokenUtil } from "../utils/access-token.util" const isLoggedInMid = async (req: Request, res: Response, next: NextFunction) => { diff --git a/src/middleware/error.mid.ts b/src/middleware/error.mid.ts index eff8a99..031c7be 100644 --- a/src/middleware/error.mid.ts +++ b/src/middleware/error.mid.ts @@ -1,6 +1,6 @@ import { ErrorRequestHandler, NextFunction, Request, Response } from "express" -import { ErrorCode, StatusCode } from "../config/constant/code.constant" import { myLogger } from "../config/logger" +import { ErrorCode, StatusCode } from "../constant/code.constant" import errorResponse from "../utils/error-response.util" import { MyErrorResponse } from "../utils/my-response.util" diff --git a/src/middleware/limiter/email.limiter.ts b/src/middleware/limiter/email.limiter.ts index 70ffdd4..bc1f507 100644 --- a/src/middleware/limiter/email.limiter.ts +++ b/src/middleware/limiter/email.limiter.ts @@ -1,9 +1,9 @@ // used for reset password+email verification import rateLimit from "express-rate-limit" import RedisStore from "rate-limit-redis" -import { ErrorCode } from "../../config/constant/code.constant" -import { ValidityConstant } from "../../config/constant/common.constant" import { redisClient } from "../../config/redis/redis.config" +import { ErrorCode } from "../../constant/code.constant" +import { ValidityConstant } from "../../constant/common.constant" import { MyErrorResponse } from "../../utils/my-response.util" /** diff --git a/src/middleware/limiter/global-rete.limiter.ts b/src/middleware/limiter/global-rete.limiter.ts index c0eec19..73a08fb 100644 --- a/src/middleware/limiter/global-rete.limiter.ts +++ b/src/middleware/limiter/global-rete.limiter.ts @@ -1,6 +1,6 @@ import rateLimit from "express-rate-limit" -import { ErrorCode } from "../../config/constant/code.constant" -import { ValidityConstant } from "../../config/constant/common.constant" +import { ErrorCode } from "../../constant/code.constant" +import { ValidityConstant } from "../../constant/common.constant" import { MyErrorResponse } from "../../utils/my-response.util" export const globalRateLimiter = rateLimit({ diff --git a/src/middleware/limiter/pdf.limiter.ts b/src/middleware/limiter/pdf.limiter.ts index 2f99dad..b5da599 100644 --- a/src/middleware/limiter/pdf.limiter.ts +++ b/src/middleware/limiter/pdf.limiter.ts @@ -1,6 +1,6 @@ import rateLimit from "express-rate-limit" -import { ErrorCode } from "../../config/constant/code.constant" -import { ValidityConstant } from "../../config/constant/common.constant" +import { ErrorCode } from "../../constant/code.constant" +import { ValidityConstant } from "../../constant/common.constant" import { MyErrorResponse } from "../../utils/my-response.util" /** diff --git a/src/middleware/validate.mid.ts b/src/middleware/validate.mid.ts index 87af147..bc37092 100644 --- a/src/middleware/validate.mid.ts +++ b/src/middleware/validate.mid.ts @@ -1,7 +1,7 @@ import { NextFunction, Request, Response } from "express" import { AnyZodObject, ZodTypeAny, z } from "zod" -import { ErrorCode, StatusCode } from "../config/constant/code.constant" import { myLogger } from "../config/logger" +import { ErrorCode, StatusCode } from "../constant/code.constant" import { MyErrorResponse } from "../utils/my-response.util" export const validateMid = ({ diff --git a/src/utils/access-token.util.ts b/src/utils/access-token.util.ts index ec73693..496f271 100644 --- a/src/utils/access-token.util.ts +++ b/src/utils/access-token.util.ts @@ -1,8 +1,8 @@ import { ICurrentUser } from "../common/model/current-user.model" import { ServerError, UnAuthorizedError } from "../common/model/error.model" -import { ValidityConstant } from "../config/constant/common.constant" -import { KeyConstant } from "../config/constant/key.constant" import { myLogger } from "../config/logger" +import { ValidityConstant } from "../constant/common.constant" +import { KeyConstant } from "../constant/key.constant" import { UniqueId } from "./common.util" import { RedisUtil } from "./redis.util" diff --git a/src/utils/date.util.ts b/src/utils/date.util.ts index 643cf28..f691865 100644 --- a/src/utils/date.util.ts +++ b/src/utils/date.util.ts @@ -1,6 +1,6 @@ import { format } from "date-fns" import { utcToZonedTime } from "date-fns-tz" -import { Constant } from "../config/constant/common.constant" +import { CommonConstant } from "../constant/common.constant" const DateUtil = { // write Util function related to dates using "date-fns" library @@ -21,7 +21,7 @@ const DateUtil = { * @description get user local date based on this timezone * @returns e.g 24th Nov, 1st jan */ - getOnlyDate: (date: Date, timeZone: string = Constant.TIMEZONE) => { + getOnlyDate: (date: Date, timeZone: string = CommonConstant.TIMEZONE) => { return format(utcToZonedTime(date, timeZone), "do MMM") }, /** diff --git a/src/utils/error-response.util.ts b/src/utils/error-response.util.ts index a6be7ed..657b6d1 100644 --- a/src/utils/error-response.util.ts +++ b/src/utils/error-response.util.ts @@ -1,7 +1,7 @@ import { Response } from "express" import { QueryError } from "mysql2" import { ServerError } from "../common/model/error.model" -import { ErrorCode, StatusCode } from "../config/constant/code.constant" +import { ErrorCode, StatusCode } from "../constant/code.constant" import { MyErrorResponse } from "./my-response.util" const errorResponse = (res: Response, e: unknown) => { diff --git a/src/utils/my-response.util.ts b/src/utils/my-response.util.ts index df877e2..f7e4f10 100644 --- a/src/utils/my-response.util.ts +++ b/src/utils/my-response.util.ts @@ -1,5 +1,5 @@ import { z } from "zod" -import { ErrorCode, StatusCode } from "../config/constant/code.constant" +import { ErrorCode, StatusCode } from "../constant/code.constant" export const MyResponse = (message: string, response?: T, statusCode = StatusCode.OK) => { return { diff --git a/src/utils/redis.util.ts b/src/utils/redis.util.ts index 2e15109..822cb3f 100644 --- a/src/utils/redis.util.ts +++ b/src/utils/redis.util.ts @@ -62,7 +62,7 @@ export const RedisUtil = { // eslint-disable-next-line @typescript-eslint/no-explicit-any const old = await RedisUtil.getData(key) const updatedValue = { ...old, ...newValue } - pipeline.set(key, MyJSON.stringify(updatedValue) ,"KEEPTTL") + pipeline.set(key, MyJSON.stringify(updatedValue), "KEEPTTL") } // Execute the pipeline diff --git a/src/utils/zod.util.ts b/src/utils/zod.util.ts index c8f5203..f2d2734 100644 --- a/src/utils/zod.util.ts +++ b/src/utils/zod.util.ts @@ -1,22 +1,22 @@ import { z } from "zod" -import { Constant } from "../config/constant/common.constant" +import { CommonConstant } from "../constant/common.constant" export const ZodNameString = z .string() .trim() - .regex(Constant.NAME_STRING, "Only Bengali or English characters, number, space are allowed") + .regex(CommonConstant.NAME_STRING, "Only Bengali or English characters, number, space are allowed") .nonempty("It's Required") export const ZodNumericString = z .string() .trim() - .regex(new RegExp(Constant.STRING_NUM_PATTERN), "Only number is allowed") + .regex(new RegExp(CommonConstant.STRING_NUM_PATTERN), "Only number is allowed") .nonempty("It's Required") export const ZodNumericNonNegString = z .string() .trim() - .regex(new RegExp(Constant.STRING_NUM_PATTERN_NON_NEG), "Only positive number is allowed") + .regex(new RegExp(CommonConstant.STRING_NUM_PATTERN_NON_NEG), "Only positive number is allowed") export const ZodSimpleString = z.string().trim().nonempty("It's Required") diff --git a/todo.md b/todo.md index e69de29..ed773a2 100644 --- a/todo.md +++ b/todo.md @@ -0,0 +1 @@ +- add this file in .gitignore so that you can keep your personal todo file