diff --git a/.github/workflows/apigateway-ci.yml b/.github/workflows/apigateway-ci.yml new file mode 100644 index 0000000..dc4b665 --- /dev/null +++ b/.github/workflows/apigateway-ci.yml @@ -0,0 +1,31 @@ +name: ApiGateway-CI + +on: + push: + branches: ['*'] + paths: + - 'apps/apigateway/**' + - '.github/workflows/apigateway-ci.yml' + +env: + SERVICE: apigateway + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [20.x] + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npm ci + - run: npm run lint:apigateway + - run: npm run build:apigateway + - run: npm run test:apigateway diff --git a/apps/Dockerfile.apigateway b/apps/Dockerfile.apigateway new file mode 100644 index 0000000..b444d31 --- /dev/null +++ b/apps/Dockerfile.apigateway @@ -0,0 +1,48 @@ +FROM node:alpine As development + +ARG service + +WORKDIR /usr/src/app + +COPY package*.json ./ + +WORKDIR /usr/src/app/apps/${service} + +COPY apps/${service}/package*.json ./ + +WORKDIR /usr/src/app + +RUN npm install --workspace=${service} + +COPY . . + +RUN npm run build:${service} + + +FROM node:alpine as production + +ARG service +ARG NODE_ENV=production +ENV NODE_ENV=${NODE_ENV} + +WORKDIR /usr/src/app + +COPY package*.json ./ + +WORKDIR /usr/src/app/apps/${service} + +COPY apps/${service}/package*.json ./ + +WORKDIR /usr/src/app + +RUN npm install --omit=dev --workspace=${service} +# RUN echo ${service} + +# COPY . . + +COPY --from=development /usr/src/app/dist/apps/${service} ./dist + +CMD ["node", "dist/server.js"] + +# docker build --build-arg="service=apigateway" -f ./apps/Dockerfile.apigateway . -t libraryapp-apigateway +# docker run -p 8080:8080 libraryapp/apigateway diff --git a/apps/Dockerfile.service b/apps/Dockerfile.service index dd3ce44..f8b1f5a 100644 --- a/apps/Dockerfile.service +++ b/apps/Dockerfile.service @@ -6,7 +6,13 @@ WORKDIR /usr/src/app COPY package*.json ./ -RUN npm install +WORKDIR /usr/src/app/apps/${service} + +COPY apps/${service}/package*.json ./ + +WORKDIR /usr/src/app + +RUN npm install --workspace=${service} COPY . . @@ -14,6 +20,7 @@ RUN npm run build ${service} FROM node:alpine as production +ARG service ARG NODE_ENV=production ENV NODE_ENV=${NODE_ENV} @@ -21,10 +28,20 @@ WORKDIR /usr/src/app COPY package*.json ./ -RUN npm install --omit=dev +WORKDIR /usr/src/app/apps/${service} + +COPY apps/${service}/package*.json ./ + +WORKDIR /usr/src/app + +RUN npm install --omit=dev --workspace=${service} +# RUN echo ${service} # COPY . . -COPY --from=development /usr/src/app/dist ./dist +COPY --from=development /usr/src/app/dist/apps/${service} ./dist + +CMD ["node", "dist/main.js"] -CMD ["node", "dist/apps/${service}/main"] \ No newline at end of file +# docker build --build-arg="service=apigateway" -f ./apps/Dockerfile.apigateway . -t libraryapp-apigateway +# docker run -p 8080:8080 libraryapp/apigateway diff --git a/apps/Dockerfile.view b/apps/Dockerfile.view index d0e5cc0..cbb2ce7 100644 --- a/apps/Dockerfile.view +++ b/apps/Dockerfile.view @@ -6,13 +6,20 @@ WORKDIR /usr/src/app COPY package*.json ./ -WORKDIR /usr/src/app/apps/ui +WORKDIR /usr/src/app/apps/${service} +COPY apps/${service}/package*.json ./ +WORKDIR /usr/src/app/apps/ui COPY apps/ui/package*.json ./ +WORKDIR /usr/src/app/packages/common +COPY packages/common/package*.json ./ + WORKDIR /usr/src/app -RUN npm install +RUN npm install --workspace=${service} +RUN npm install --workspace=@repo/common +RUN npm install --workspace=ui COPY . . @@ -22,17 +29,27 @@ RUN npm run build:ui FROM node:alpine as production +ARG service ARG NODE_ENV=production ENV NODE_ENV=${NODE_ENV} +ENV SERVICE ${service} WORKDIR /usr/src/app COPY package*.json ./ -RUN npm install --omit=dev +WORKDIR /usr/src/app/apps/${service} + +COPY apps/${service}/package*.json ./ + +WORKDIR /usr/src/app + +RUN npm install --omit=dev --workspace=${service} # COPY . . +# NOTE: keep the app folder name, as will be serving dist/ui/index.html COPY --from=development /usr/src/app/dist ./dist -CMD ["node", "dist/apps/${service}/main"] \ No newline at end of file +# Execute from this workdir, as shared for both ui and view +CMD node dist/apps/$SERVICE/main diff --git a/apps/apigateway/.env b/apps/apigateway/.env new file mode 100644 index 0000000..755da6c --- /dev/null +++ b/apps/apigateway/.env @@ -0,0 +1,4 @@ +BASEURL_BOOK=http://localhost:8001 +BASEURL_CUSTOMER=http://localhost:8002 +BASEURL_BORROWING=http://localhost:8003 +BASEURL_PAYMENT=http://localhost:8004 diff --git a/apps/apigateway/jest.config.js b/apps/apigateway/jest.config.js new file mode 100644 index 0000000..3745fc2 --- /dev/null +++ b/apps/apigateway/jest.config.js @@ -0,0 +1,5 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', +}; diff --git a/apps/apigateway/package.json b/apps/apigateway/package.json new file mode 100644 index 0000000..8501be7 --- /dev/null +++ b/apps/apigateway/package.json @@ -0,0 +1,31 @@ +{ + "name": "apigateway", + "private": true, + "version": "0.0.0", + "scripts": { + "build": "tsc", + "dev": "ts-node-dev --respawn --transpile-only src/server.ts", + "start": "cd ../.. && cd dist/apps/apigateway && node server.js", + "start:prod": "npm run start", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --fix", + "test": "jest test/*.ts" + }, + "dependencies": { + "cors": "^2.8.5", + "dotenv": "^16.3.1", + "express": "^4.18.2", + "http-proxy-middleware": "^2.0.6", + "morgan": "^1.10.0" + }, + "devDependencies": { + "@jest/globals": "^29.7.0", + "@types/cors": "^2.8.17", + "@types/morgan": "^1.9.9", + "jest": "^29.7.0", + "supertest": "^6.3.3", + "ts-jest": "^29.1.1", + "ts-node-dev": "^2.0.0", + "turbo": "^1.11.2", + "typescript": "^5.3.3" + } +} diff --git a/apps/apigateway/src/app.ts b/apps/apigateway/src/app.ts new file mode 100644 index 0000000..55a1ae7 --- /dev/null +++ b/apps/apigateway/src/app.ts @@ -0,0 +1,24 @@ +import * as cors from 'cors'; +import 'dotenv/config'; +import * as express from 'express'; +import { setupLogging } from './logging'; +import { setupProxies } from './proxy'; +import { ROUTES } from './routes'; + +const app = express(); + +const corsOptions: cors.CorsOptions = { + // origin: '*', + // credentials: true, //access-control-allow-credentials:true + // optionsSuccessStatus: 200, +}; +app.use(cors(corsOptions)); + +setupProxies(app, ROUTES); +setupLogging(app); + +app.get('/', (req, res) => { + return res.send('Welcome to API Gateway!'); +}); + +export default app; diff --git a/apps/apigateway/src/logging.ts b/apps/apigateway/src/logging.ts new file mode 100644 index 0000000..ee901dc --- /dev/null +++ b/apps/apigateway/src/logging.ts @@ -0,0 +1,8 @@ +import * as morgan from 'morgan'; +import * as express from 'express'; + +const loggingMode = process.env.NODE_ENV === 'production' ? 'combined' : 'dev'; + +export const setupLogging = (app: express.Application) => { + app.use(morgan(loggingMode)); +}; diff --git a/apps/apigateway/src/proxy.ts b/apps/apigateway/src/proxy.ts new file mode 100644 index 0000000..89b25af --- /dev/null +++ b/apps/apigateway/src/proxy.ts @@ -0,0 +1,9 @@ +import * as express from 'express'; +import { createProxyMiddleware } from 'http-proxy-middleware'; +import type { IRoute } from './routes'; + +export const setupProxies = (app: express.Application, routes: IRoute[]) => { + routes.forEach((r) => { + app.use(r.url, createProxyMiddleware(r.proxy)); + }); +}; diff --git a/apps/apigateway/src/routes.ts b/apps/apigateway/src/routes.ts new file mode 100644 index 0000000..064900b --- /dev/null +++ b/apps/apigateway/src/routes.ts @@ -0,0 +1,104 @@ +import 'dotenv/config'; +import { Options } from 'http-proxy-middleware'; + +export interface IRoute { + url: string; + auth?: boolean; + creditCheck?: boolean; + rateLimit?: { windowMs: number; max: number }; + proxy: Options; +} + +const BASEURL_BOOK = process.env.BASEURL_BOOK || 'http://localhost:8001'; +const BASEURL_CUSTOMER = + process.env.BASEURL_CUSTOMER || 'http://localhost:8002'; +const BASEURL_BORROWING = + process.env.BASEURL_BORROWING || 'http://localhost:8003'; +const BASEURL_PAYMENT = process.env.BASEURL_PAYMENT || 'http://localhost:8004'; + +export const ROUTES: IRoute[] = [ + // Book + { + url: '/api/book', + auth: false, + creditCheck: false, + proxy: { + target: BASEURL_BOOK, + changeOrigin: true, + pathRewrite: { + '^/api/book': '', + }, + }, + }, + // Customer + { + url: '/api/customer', + auth: false, + creditCheck: false, + proxy: { + target: BASEURL_CUSTOMER, + changeOrigin: true, + pathRewrite: { + '^/api/customer': '', + }, + }, + }, + // Borrowing + { + url: '/api/borrowing', + auth: false, + creditCheck: false, + proxy: { + target: BASEURL_BORROWING, + changeOrigin: true, + pathRewrite: { + '^/api/borrowing': '', + }, + }, + }, + // Paymenet + { + url: '/api/payment', + auth: false, + creditCheck: false, + proxy: { + target: BASEURL_PAYMENT, + changeOrigin: true, + ws: false, // use http polling + pathRewrite: { + '^/api/payment': '', + }, + }, + }, +]; + +// export const ROUTES: IRoute[] = [ +// { +// url: '/free', +// auth: false, +// creditCheck: false, +// rateLimit: { +// windowMs: 15 * 60 * 1000, +// max: 5, +// }, +// proxy: { +// target: 'https://www.google.com', +// changeOrigin: true, +// pathRewrite: { +// [`^/free`]: '', +// }, +// }, +// }, +// { +// url: '/premium', +// auth: true, +// creditCheck: true, +// proxy: { +// target: 'https://www.google.com', +// changeOrigin: true, +// pathRewrite: { +// [`^/premium`]: '', +// }, +// }, +// }, +// ]; diff --git a/apps/apigateway/src/server.ts b/apps/apigateway/src/server.ts new file mode 100644 index 0000000..87b6919 --- /dev/null +++ b/apps/apigateway/src/server.ts @@ -0,0 +1,7 @@ +import app from './app'; + +const PORT = 8080; + +app.listen(PORT, () => { + console.log(`Listening at PORT ${PORT}`); +}); diff --git a/apps/apigateway/test/app.test.ts b/apps/apigateway/test/app.test.ts new file mode 100644 index 0000000..54509ff --- /dev/null +++ b/apps/apigateway/test/app.test.ts @@ -0,0 +1,13 @@ +import { describe, expect, test } from '@jest/globals'; +import * as request from 'supertest'; +import app from '../src/app'; + +describe('Test the root path', () => { + test('Should have success status code', () => { + return request(app) + .get('/') + .then((response) => { + expect(response.statusCode).toBe(200); + }); + }); +}); diff --git a/apps/apigateway/tsconfig.json b/apps/apigateway/tsconfig.json new file mode 100644 index 0000000..13a7f5a --- /dev/null +++ b/apps/apigateway/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "rootDir": "./src", + "target": "ES6", + "module": "commonjs", + "allowJs": false, + "outDir": "../../dist/apps/apigateway/", + "esModuleInterop": false, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + }, + "exclude": ["test/*", "jest.**"] +} diff --git a/apps/apigateway/turbo.json b/apps/apigateway/turbo.json new file mode 100644 index 0000000..4886466 --- /dev/null +++ b/apps/apigateway/turbo.json @@ -0,0 +1,12 @@ +{ + "extends": ["//"], + "pipeline": { + "build": { + "dependsOn": ["^build"], + "outputs": ["dist", "../../dist/apps/**"] + }, + "start": { + "dependsOn": ["build"] + } + } +} diff --git a/apps/book/package.json b/apps/book/package.json index 754e128..0bd997c 100644 --- a/apps/book/package.json +++ b/apps/book/package.json @@ -5,5 +5,53 @@ "start:prod": "cd ../.. && node dist/apps/book/main", "dev": "cd ../.. && npm run start:dev book", "build": "cd ../.. && npm run build book" + }, + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.2.10", + "@nestjs/mongoose": "^10.0.2", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.0", + "@nestjs/serve-static": "^4.0.0", + "@nestjs/swagger": "^7.1.15", + "@nestjs/websockets": "^10.3.0", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.3", + "class-validator": "^0.14.0", + "joi": "^17.11.0", + "mongoose": "^8.0.0", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@golevelup/nestjs-rabbitmq": "^4.1.0", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", + "mongodb-memory-server": "^9.1.1", + "prettier": "^3.0.0", + "react-router-dom": "^6.20.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "turbo": "^1.11.2", + "typescript": "^5.1.3" } } diff --git a/apps/borrowing/package.json b/apps/borrowing/package.json index 76ee18b..8c5f862 100644 --- a/apps/borrowing/package.json +++ b/apps/borrowing/package.json @@ -5,5 +5,53 @@ "start:prod": "cd ../.. && node dist/apps/borrowing/main", "dev": "cd ../.. && npm run start:dev borrowing", "build": "cd ../.. && npm run build borrowing" + }, + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.2.10", + "@nestjs/mongoose": "^10.0.2", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.0", + "@nestjs/serve-static": "^4.0.0", + "@nestjs/swagger": "^7.1.15", + "@nestjs/websockets": "^10.3.0", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.3", + "class-validator": "^0.14.0", + "joi": "^17.11.0", + "mongoose": "^8.0.0", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@golevelup/nestjs-rabbitmq": "^4.1.0", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", + "mongodb-memory-server": "^9.1.1", + "prettier": "^3.0.0", + "react-router-dom": "^6.20.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "turbo": "^1.11.2", + "typescript": "^5.1.3" } } diff --git a/apps/customer/package.json b/apps/customer/package.json index 019fd5f..79c9ffb 100644 --- a/apps/customer/package.json +++ b/apps/customer/package.json @@ -5,5 +5,53 @@ "start:prod": "cd ../.. && node dist/apps/customer/main", "dev": "cd ../.. && npm run start:dev customer", "build": "cd ../.. && npm run build customer" + }, + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.2.10", + "@nestjs/mongoose": "^10.0.2", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.0", + "@nestjs/serve-static": "^4.0.0", + "@nestjs/swagger": "^7.1.15", + "@nestjs/websockets": "^10.3.0", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.3", + "class-validator": "^0.14.0", + "joi": "^17.11.0", + "mongoose": "^8.0.0", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@golevelup/nestjs-rabbitmq": "^4.1.0", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", + "mongodb-memory-server": "^9.1.1", + "prettier": "^3.0.0", + "react-router-dom": "^6.20.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "turbo": "^1.11.2", + "typescript": "^5.1.3" } } diff --git a/apps/notification/package.json b/apps/notification/package.json index 9c2e81c..4ddf075 100644 --- a/apps/notification/package.json +++ b/apps/notification/package.json @@ -5,5 +5,53 @@ "start:prod": "cd ../.. && node dist/apps/notification/main", "dev": "cd ../.. && npm run start:dev notification", "build": "cd ../.. && npm run build notification" + }, + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.2.10", + "@nestjs/mongoose": "^10.0.2", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.0", + "@nestjs/serve-static": "^4.0.0", + "@nestjs/swagger": "^7.1.15", + "@nestjs/websockets": "^10.3.0", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.3", + "class-validator": "^0.14.0", + "joi": "^17.11.0", + "mongoose": "^8.0.0", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@golevelup/nestjs-rabbitmq": "^4.1.0", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", + "mongodb-memory-server": "^9.1.1", + "prettier": "^3.0.0", + "react-router-dom": "^6.20.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "turbo": "^1.11.2", + "typescript": "^5.1.3" } } diff --git a/apps/payment/package.json b/apps/payment/package.json index a1ea151..f095a61 100644 --- a/apps/payment/package.json +++ b/apps/payment/package.json @@ -5,5 +5,53 @@ "start:prod": "cd ../.. && node dist/apps/payment/main", "dev": "cd ../.. && npm run start:dev payment", "build": "cd ../.. && npm run build payment" + }, + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.2.10", + "@nestjs/mongoose": "^10.0.2", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.0", + "@nestjs/serve-static": "^4.0.0", + "@nestjs/swagger": "^7.1.15", + "@nestjs/websockets": "^10.3.0", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.3", + "class-validator": "^0.14.0", + "joi": "^17.11.0", + "mongoose": "^8.0.0", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@golevelup/nestjs-rabbitmq": "^4.1.0", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", + "mongodb-memory-server": "^9.1.1", + "prettier": "^3.0.0", + "react-router-dom": "^6.20.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "turbo": "^1.11.2", + "typescript": "^5.1.3" } } diff --git a/apps/ui/.env b/apps/ui/.env index 1f27c0d..b473bf3 100644 --- a/apps/ui/.env +++ b/apps/ui/.env @@ -1,4 +1,4 @@ -VITE_BOOK_API_BASE_URL='http://localhost:8001' -VITE_CUSTOMER_API_BASE_URL='http://localhost:8002' -VITE_BORROWING_API_BASE_URL='http://localhost:8003' -VITE_PAYMENT_API_BASE_URL='http://localhost:8004' +VITE_BOOK_API_BASE_URL='http://localhost:8080' +VITE_CUSTOMER_API_BASE_URL='http://localhost:8080' +VITE_BORROWING_API_BASE_URL='http://localhost:8080' +VITE_PAYMENT_API_BASE_URL='http://localhost:8080' diff --git a/apps/ui/src/api/book-api.ts b/apps/ui/src/api/book-api.ts index cb7b3b3..c3de7b7 100644 --- a/apps/ui/src/api/book-api.ts +++ b/apps/ui/src/api/book-api.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { IBook } from '../interfaces/book'; const BASE_URL = import.meta.env.VITE_BOOK_API_BASE_URL; -const resource = '/books'; +const resource = '/api/book/books'; const url = `${BASE_URL}${resource}`; export async function getBooks() { diff --git a/apps/ui/src/api/borrowing-api.ts b/apps/ui/src/api/borrowing-api.ts index 35810b3..11fb0b7 100644 --- a/apps/ui/src/api/borrowing-api.ts +++ b/apps/ui/src/api/borrowing-api.ts @@ -2,7 +2,7 @@ import { IBorrowing } from '../interfaces/borrowing'; import axios from 'axios'; const BASE_URL = import.meta.env.VITE_BORROWING_API_BASE_URL; -const resource = '/borrowings'; +const resource = '/api/borrowing/borrowings'; const url = `${BASE_URL}${resource}`; export async function getBorrowings({ customer_id }: { customer_id: string }) { diff --git a/apps/ui/src/api/customer-api.ts b/apps/ui/src/api/customer-api.ts index 81ef239..11e82ee 100644 --- a/apps/ui/src/api/customer-api.ts +++ b/apps/ui/src/api/customer-api.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { ICustomer } from '../interfaces/customer'; const BASE_URL = import.meta.env.VITE_CUSTOMER_API_BASE_URL; -const resource = '/customers'; +const resource = '/api/customer/customers'; const url = `${BASE_URL}${resource}`; export async function getCustomers() { diff --git a/apps/ui/src/api/payment-api.ts b/apps/ui/src/api/payment-api.ts index 4c4c1bf..2d87979 100644 --- a/apps/ui/src/api/payment-api.ts +++ b/apps/ui/src/api/payment-api.ts @@ -1,7 +1,7 @@ import axios from 'axios'; const BASE_URL = import.meta.env.VITE_PAYMENT_API_BASE_URL; -const resource = '/payments'; +const resource = '/api/payment/payments'; const url = `${BASE_URL}${resource}`; export async function getPayments({ borrowing_id }: { borrowing_id: string }) { diff --git a/apps/ui/src/utils/socket.ts b/apps/ui/src/utils/socket.ts index fa5d28a..364628b 100644 --- a/apps/ui/src/utils/socket.ts +++ b/apps/ui/src/utils/socket.ts @@ -2,4 +2,6 @@ import { io } from 'socket.io-client'; const PAYMENT_URL = import.meta.env.VITE_PAYMENT_API_BASE_URL; -export const paymentSocket = io(PAYMENT_URL); +export const paymentSocket = io(PAYMENT_URL, { + path: '/api/payment/socket.io', +}); diff --git a/apps/view/package.json b/apps/view/package.json index a7a6fcb..bf8db62 100644 --- a/apps/view/package.json +++ b/apps/view/package.json @@ -5,5 +5,53 @@ "start:prod": "cd ../.. && node dist/apps/view/main", "dev": "cd ../.. && npm run start:dev view", "build": "cd ../.. && npm run build view" + }, + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.2.10", + "@nestjs/mongoose": "^10.0.2", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.0", + "@nestjs/serve-static": "^4.0.0", + "@nestjs/swagger": "^7.1.15", + "@nestjs/websockets": "^10.3.0", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.3", + "class-validator": "^0.14.0", + "joi": "^17.11.0", + "mongoose": "^8.0.0", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@golevelup/nestjs-rabbitmq": "^4.1.0", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", + "mongodb-memory-server": "^9.1.1", + "prettier": "^3.0.0", + "react-router-dom": "^6.20.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "turbo": "^1.11.2", + "typescript": "^5.1.3" } } diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..e31bb85 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,176 @@ +# NOTE: The ports of internal services (eg. book, customer, payment, borrowing) are not exposed in production + +services: + # app services + book: + build: + context: . + dockerfile: ./apps/Dockerfile.service + target: production + args: + service: book + env_file: + - ./apps/book/.env + environment: + - MONGODB_URI=mongodb://mongodb:27017/libraryapp-book + - RABBIT_MQ_URI=amqp://rabbitmq:5672 + depends_on: + - mongodb + - rabbitmq + # ports: + # - '8001:8001' + networks: + - node-network + links: + - mongodb + - rabbitmq + customer: + build: + context: . + dockerfile: ./apps/Dockerfile.service + target: production + args: + service: customer + env_file: + - ./apps/customer/.env + environment: + - MONGODB_URI=mongodb://mongodb:27017/libraryapp-customer + depends_on: + - mongodb + # ports: + # - '8002:8002' + networks: + - node-network + links: + - mongodb + borrowing: + build: + context: . + dockerfile: ./apps/Dockerfile.service + target: production + args: + service: borrowing + env_file: + - ./apps/borrowing/.env + environment: + - MONGODB_URI=mongodb://mongodb:27017/libraryapp-borrowing + - RABBIT_MQ_URI=amqp://rabbitmq:5672 + depends_on: + - mongodb + - rabbitmq + # ports: + # - '8003:8003' + networks: + - node-network + links: + - mongodb + - rabbitmq + payment: + build: + context: . + dockerfile: ./apps/Dockerfile.service + target: production + args: + service: payment + env_file: + - ./apps/payment/.env + environment: + - MONGODB_URI=mongodb://mongodb:27017/libraryapp-payment + - RABBIT_MQ_URI=amqp://rabbitmq:5672 + depends_on: + - mongodb + - rabbitmq + # ports: + # - '8004:8004' + networks: + - node-network + links: + - mongodb + - rabbitmq + notification: + build: + context: . + dockerfile: ./apps/Dockerfile.service + target: production + args: + service: notification + env_file: + - ./apps/notification/.env + environment: + - RABBIT_MQ_URI=amqp://rabbitmq:5672 + depends_on: + - rabbitmq + # ports: + # - '8005:8005' + networks: + - node-network + links: + - rabbitmq + view: + build: + context: . + dockerfile: ./apps/Dockerfile.view + args: + service: view + env_file: + - ./apps/view/.env + depends_on: + - book + - customer + - borrowing + - payment + - notification + ports: + - '8000:8000' + networks: + - node-network + apigateway: + build: + context: . + dockerfile: ./apps/Dockerfile.apigateway + target: production + args: + service: apigateway + env_file: + - ./apps/apigateway/.env + depends_on: + - view + ports: + - '8080:8080' + networks: + - node-network + links: + - book + - customer + - borrowing + - payment + environment: + - BASEURL_BOOK=http://book:8001 + - BASEURL_CUSTOMER=http://customer:8002 + - BASEURL_BORROWING=http://borrowing:8003 + - BASEURL_PAYMENT=http://payment:8004 + + # Dependencies + rabbitmq: + image: rabbitmq + ports: + - '5672:5672' + networks: + - node-network + mongodb: + image: mongo:6 + volumes: + - mongodb_data_container:/data/db + ports: + - '27017:27017' + networks: + - node-network + +volumes: + mongodb_data_container: +networks: + node-network: + driver: bridge +# docker compose -f docker-compose.prod.yml up -d +# docker compose -f docker-compose.prod.yml up -d --build +# docker compose -f docker-compose.prod.yml down diff --git a/docker-compose.yml b/docker-compose.yml index ad0a9ed..82b0db8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,7 @@ services: # app services book: + image: libraryapp-dev-book build: context: . dockerfile: ./apps/Dockerfile.service @@ -27,6 +28,7 @@ services: - mongodb - rabbitmq customer: + image: libraryapp-dev-customer build: context: . dockerfile: ./apps/Dockerfile.service @@ -50,6 +52,7 @@ services: links: - mongodb borrowing: + image: libraryapp-dev-borrowing build: context: . dockerfile: ./apps/Dockerfile.service @@ -76,6 +79,7 @@ services: - mongodb - rabbitmq payment: + image: libraryapp-dev-payment build: context: . dockerfile: ./apps/Dockerfile.service @@ -102,6 +106,7 @@ services: - mongodb - rabbitmq notification: + image: libraryapp-dev-notification build: context: . dockerfile: ./apps/Dockerfile.service @@ -125,6 +130,7 @@ services: links: - rabbitmq view: + image: libraryapp-dev-view build: context: . dockerfile: ./apps/Dockerfile.view @@ -134,6 +140,12 @@ services: command: npm run start:dev view env_file: - ./apps/view/.env + depends_on: + - book + - customer + - borrowing + - payment + - notification volumes: - .:/usr/src/app - /usr/src/app/node_modules @@ -142,6 +154,37 @@ services: networks: - node-network + apigateway: + image: libraryapp-dev-apigateway + build: + context: . + dockerfile: ./apps/Dockerfile.apigateway + target: development + args: + service: apigateway + command: npm run dev:apigateway + env_file: + - ./apps/apigateway/.env + depends_on: + - view + volumes: + - .:/usr/src/app + - /usr/src/app/node_modules + ports: + - '8080:8080' + networks: + - node-network + links: + - book + - customer + - borrowing + - payment + environment: + - BASEURL_BOOK=http://book:8001 + - BASEURL_CUSTOMER=http://customer:8002 + - BASEURL_BORROWING=http://borrowing:8003 + - BASEURL_PAYMENT=http://payment:8004 + # Dependencies rabbitmq: image: rabbitmq diff --git a/package-lock.json b/package-lock.json index e837dfb..e34d514 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,232 @@ "apps/*", "packages/*" ], + "devDependencies": { + "turbo": "^1.11.2" + } + }, + "apps/apigateway": { + "version": "0.0.0", + "dependencies": { + "cors": "^2.8.5", + "dotenv": "^16.3.1", + "express": "^4.18.2", + "http-proxy-middleware": "^2.0.6", + "morgan": "^1.10.0" + }, + "devDependencies": { + "@jest/globals": "^29.7.0", + "@types/cors": "^2.8.17", + "@types/morgan": "^1.9.9", + "jest": "^29.7.0", + "supertest": "^6.3.3", + "ts-jest": "^29.1.1", + "ts-node-dev": "^2.0.0", + "turbo": "^1.11.2", + "typescript": "^5.3.3" + } + }, + "apps/book": { + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.2.10", + "@nestjs/mongoose": "^10.0.2", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.0", + "@nestjs/serve-static": "^4.0.0", + "@nestjs/swagger": "^7.1.15", + "@nestjs/websockets": "^10.3.0", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.3", + "class-validator": "^0.14.0", + "joi": "^17.11.0", + "mongoose": "^8.0.0", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@golevelup/nestjs-rabbitmq": "^4.1.0", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", + "mongodb-memory-server": "^9.1.1", + "prettier": "^3.0.0", + "react-router-dom": "^6.20.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "turbo": "^1.11.2", + "typescript": "^5.1.3" + } + }, + "apps/borrowing": { + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.2.10", + "@nestjs/mongoose": "^10.0.2", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.0", + "@nestjs/serve-static": "^4.0.0", + "@nestjs/swagger": "^7.1.15", + "@nestjs/websockets": "^10.3.0", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.3", + "class-validator": "^0.14.0", + "joi": "^17.11.0", + "mongoose": "^8.0.0", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@golevelup/nestjs-rabbitmq": "^4.1.0", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", + "mongodb-memory-server": "^9.1.1", + "prettier": "^3.0.0", + "react-router-dom": "^6.20.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "turbo": "^1.11.2", + "typescript": "^5.1.3" + } + }, + "apps/customer": { + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.2.10", + "@nestjs/mongoose": "^10.0.2", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.0", + "@nestjs/serve-static": "^4.0.0", + "@nestjs/swagger": "^7.1.15", + "@nestjs/websockets": "^10.3.0", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.3", + "class-validator": "^0.14.0", + "joi": "^17.11.0", + "mongoose": "^8.0.0", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@golevelup/nestjs-rabbitmq": "^4.1.0", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", + "mongodb-memory-server": "^9.1.1", + "prettier": "^3.0.0", + "react-router-dom": "^6.20.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "turbo": "^1.11.2", + "typescript": "^5.1.3" + } + }, + "apps/notification": { + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.2.10", + "@nestjs/mongoose": "^10.0.2", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.0", + "@nestjs/serve-static": "^4.0.0", + "@nestjs/swagger": "^7.1.15", + "@nestjs/websockets": "^10.3.0", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.3", + "class-validator": "^0.14.0", + "joi": "^17.11.0", + "mongoose": "^8.0.0", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@golevelup/nestjs-rabbitmq": "^4.1.0", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", + "mongodb-memory-server": "^9.1.1", + "prettier": "^3.0.0", + "react-router-dom": "^6.20.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "turbo": "^1.11.2", + "typescript": "^5.1.3" + } + }, + "apps/payment": { "dependencies": { "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.1.1", @@ -61,11 +287,6 @@ "typescript": "^5.1.3" } }, - "apps/book": {}, - "apps/borrowing": {}, - "apps/customer": {}, - "apps/notification": {}, - "apps/payment": {}, "apps/ui": { "version": "0.0.0", "dependencies": { @@ -96,7 +317,56 @@ "vite": "^5.0.5" } }, - "apps/view": {}, + "apps/view": { + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.2.10", + "@nestjs/mongoose": "^10.0.2", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.0", + "@nestjs/serve-static": "^4.0.0", + "@nestjs/swagger": "^7.1.15", + "@nestjs/websockets": "^10.3.0", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.3", + "class-validator": "^0.14.0", + "joi": "^17.11.0", + "mongoose": "^8.0.0", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@golevelup/nestjs-rabbitmq": "^4.1.0", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", + "mongodb-memory-server": "^9.1.1", + "prettier": "^3.0.0", + "react-router-dom": "^6.20.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "turbo": "^1.11.2", + "typescript": "^5.1.3" + } + }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", @@ -3400,7 +3670,7 @@ "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, + "devOptional": true, "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -3410,7 +3680,7 @@ "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, + "devOptional": true, "dependencies": { "@types/node": "*" } @@ -3464,7 +3734,7 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, + "devOptional": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -3476,7 +3746,7 @@ "version": "4.17.41", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", - "dev": true, + "devOptional": true, "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -3497,7 +3767,15 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true + "devOptional": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dependencies": { + "@types/node": "*" + } }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", @@ -3549,7 +3827,16 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "devOptional": true + }, + "node_modules/@types/morgan": { + "version": "1.9.9", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz", + "integrity": "sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } }, "node_modules/@types/node": { "version": "20.10.2", @@ -3573,13 +3860,13 @@ "version": "6.9.10", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", - "dev": true + "devOptional": true }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true + "devOptional": true }, "node_modules/@types/react": { "version": "18.2.41", @@ -3623,7 +3910,7 @@ "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, + "devOptional": true, "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -3633,7 +3920,7 @@ "version": "1.15.5", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", - "dev": true, + "devOptional": true, "dependencies": { "@types/http-errors": "*", "@types/mime": "*", @@ -3646,6 +3933,18 @@ "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, + "node_modules/@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", + "dev": true + }, + "node_modules/@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true + }, "node_modules/@types/superagent": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.1.tgz", @@ -4275,6 +4574,10 @@ "node": ">= 8" } }, + "node_modules/apigateway": { + "resolved": "apps/apigateway", + "link": true + }, "node_modules/append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", @@ -4732,7 +5035,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -5777,6 +6079,15 @@ "node": ">=12" } }, + "node_modules/dynamic-dedupe": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", + "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", + "dev": true, + "dependencies": { + "xtend": "^4.0.0" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -6225,6 +6536,11 @@ "node": ">= 0.6" } }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -6535,7 +6851,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -7124,6 +7439,42 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, "node_modules/https-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", @@ -7348,7 +7699,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -7375,7 +7725,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -7414,7 +7763,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -7428,6 +7776,17 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -8557,7 +8916,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -9364,7 +9722,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -11020,7 +11377,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -11183,6 +11539,96 @@ } } }, + "node_modules/ts-node-dev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", + "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.1", + "dynamic-dedupe": "^0.3.0", + "minimist": "^1.2.6", + "mkdirp": "^1.0.4", + "resolve": "^1.0.0", + "rimraf": "^2.6.1", + "source-map-support": "^0.5.12", + "tree-kill": "^1.2.2", + "ts-node": "^10.4.0", + "tsconfig": "^7.0.0" + }, + "bin": { + "ts-node-dev": "lib/bin.js", + "tsnd": "lib/bin.js" + }, + "engines": { + "node": ">=0.8.0" + }, + "peerDependencies": { + "node-notifier": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/ts-node-dev/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ts-node-dev/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node-dev/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "dependencies": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + } + }, "node_modules/tsconfig-paths": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", @@ -11220,6 +11666,24 @@ "node": ">=4" } }, + "node_modules/tsconfig/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tsconfig/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -11371,9 +11835,9 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, "node_modules/typescript": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", - "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 2962d8b..58560e3 100644 --- a/package.json +++ b/package.json @@ -28,57 +28,16 @@ "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "jest --config jest-e2e.json", + "test:apigateway": "turbo test --filter=apigateway", "dev:ui": "turbo dev --filter=ui", "build:ui": "turbo build --filter=ui", - "lint:ui": "turbo lint --filter=ui" - }, - "dependencies": { - "@nestjs/common": "^10.0.0", - "@nestjs/config": "^3.1.1", - "@nestjs/core": "^10.0.0", - "@nestjs/microservices": "^10.2.10", - "@nestjs/mongoose": "^10.0.2", - "@nestjs/platform-express": "^10.0.0", - "@nestjs/platform-socket.io": "^10.3.0", - "@nestjs/serve-static": "^4.0.0", - "@nestjs/swagger": "^7.1.15", - "@nestjs/websockets": "^10.3.0", - "amqp-connection-manager": "^4.1.14", - "amqplib": "^0.10.3", - "class-validator": "^0.14.0", - "joi": "^17.11.0", - "mongoose": "^8.0.0", - "morgan": "^1.10.0", - "reflect-metadata": "^0.1.13", - "rxjs": "^7.8.1" + "build:apigateway": "turbo build --filter=apigateway", + "lint:ui": "turbo lint --filter=ui", + "dev:apigateway": "turbo dev --filter=apigateway", + "lint:apigateway": "turbo lint --filter=apigateway" }, "devDependencies": { - "@golevelup/nestjs-rabbitmq": "^4.1.0", - "@nestjs/cli": "^10.0.0", - "@nestjs/schematics": "^10.0.0", - "@nestjs/testing": "^10.0.0", - "@types/express": "^4.17.17", - "@types/jest": "^29.5.2", - "@types/node": "^20.3.1", - "@types/supertest": "^6.0.2", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", - "eslint": "^8.42.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-prettier": "^5.0.0", - "jest": "^29.5.0", - "jest-mock-extended": "^3.0.5", - "mongodb-memory-server": "^9.1.1", - "prettier": "^3.0.0", - "react-router-dom": "^6.20.1", - "source-map-support": "^0.5.21", - "supertest": "^6.3.3", - "ts-jest": "^29.1.0", - "ts-loader": "^9.4.3", - "ts-node": "^10.9.1", - "tsconfig-paths": "^4.2.0", - "turbo": "^1.11.2", - "typescript": "^5.1.3" + "turbo": "^1.11.2" }, "jest": { "moduleFileExtensions": [ diff --git a/turbo.json b/turbo.json index e5082df..55ee8b6 100644 --- a/turbo.json +++ b/turbo.json @@ -12,7 +12,8 @@ "start:prod": { "dependsOn": ["build"] }, - "lint": {} + "lint": {}, + "test": {} }, "globalDependencies": ["tsconfig.json"]