diff --git a/.gitignore b/.gitignore index 7b6a6e5..76acaa4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ node_modules !.env.example !.env.*.example **.pem -.vscode \ No newline at end of file +.vscode +.terraform +*.tfvars \ No newline at end of file diff --git a/auth-service/Dockerfile b/auth-service/Dockerfile index 3735b91..ca4e802 100644 --- a/auth-service/Dockerfile +++ b/auth-service/Dockerfile @@ -1,33 +1,21 @@ -FROM node:22-alpine AS base +FROM node:22-alpine WORKDIR /app -COPY auth-service/package*.json ./ +# Cài curl do alpine không có sẵn +RUN apk add --no-cache curl -FROM base AS development +# Cần chạy build từ /root +COPY auth-service/package*.json ./ RUN npm install COPY auth-service/ . COPY shared-libs ./shared-libs -EXPOSE 3001 - -CMD ["npm", "run", "dev"] - -FROM base AS production - -RUN npm ci --omit=dev && npm cache clean --force - -RUN addgroup --system --gid 1001 nodejs \ - && adduser --system --uid 1001 nodeusr -USER nodeusr - -COPY auth-service/ . -COPY shared-libs ./shared-libs - -ENV NODE_ENV=production +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:3001/health || exit 1 EXPOSE 3001 -CMD ["npm", "start"] \ No newline at end of file +CMD ["npm", "run", "dev"] \ No newline at end of file diff --git a/auth-service/Dockerfile.lambda b/auth-service/Dockerfile.lambda new file mode 100644 index 0000000..f26a333 --- /dev/null +++ b/auth-service/Dockerfile.lambda @@ -0,0 +1,25 @@ +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS builder + +# Lambda workdir chuẩn +WORKDIR /var/task + +COPY auth-service/package*.json . + +# Không cài devDependencies và xóa cache npm +RUN npm ci --omit=dev && npm cache clean --force + +COPY auth-service/ . +COPY shared-libs/ ./shared-libs + +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS runner + +WORKDIR /var/task + +COPY --from=builder /var/task . + +# APP_ENV test AWS infra local +ENV NODE_ENV=production +ENV APP_ENV=production + +# Lambda handler +CMD ["server.handler"] \ No newline at end of file diff --git a/auth-service/controllers/authController.js b/auth-service/controllers/authController.js index b881a93..6809e41 100644 --- a/auth-service/controllers/authController.js +++ b/auth-service/controllers/authController.js @@ -1,6 +1,4 @@ -import dotenv from 'dotenv'; import bcrypt from 'bcrypt'; - import TokenRepository from "../repositories/tokenRepository.js"; import UserRepository from '../repositories/userRepository.js'; import { asyncWrapper } from "#shared/middlewares/index.js" @@ -14,8 +12,6 @@ import { } from "#shared/errors/errors.js"; import { createHash, hashToken, generateUuidv4, JwtFacade } from '../utils/index.js'; -dotenv.config(); - // POST /refresh // Cấp lại token khi accessToken hết hạn export const token = asyncWrapper(async (req, res) => { diff --git a/auth-service/server.js b/auth-service/server.js index 0f13dad..fe1c117 100644 --- a/auth-service/server.js +++ b/auth-service/server.js @@ -15,6 +15,10 @@ app.use(express.json()); app.use(cookieParser()); app.use(pinoLogger); +app.get('/health', (req, res) => { + res.status(200).json({ status: 'ok' }); +}); + app.use('/users', router); app.use(routeNotFound); diff --git a/class-service/Dockerfile b/class-service/Dockerfile index f69631c..f2ad192 100644 --- a/class-service/Dockerfile +++ b/class-service/Dockerfile @@ -1,40 +1,24 @@ -FROM node:22-alpine AS base +FROM node:22-alpine WORKDIR /app +# Cài curl do alpine không có sẵn +RUN apk add --no-cache curl + # Cần chạy build từ /root COPY class-service/package*.json ./ -FROM base AS development - RUN npm install COPY class-service/ . COPY shared-libs ./shared-libs -# Generate Prisma client cho môi trường Alpine (linux-musl) +# Generate Prisma client RUN npx prisma generate -EXPOSE 3003 - -CMD ["npm", "run", "dev"] - -FROM base AS production - -RUN addgroup --system --gid 1001 nodejs \ - && adduser --system --uid 1001 nodeusr - -RUN npm ci --omit=dev && npm cache clean --force - -COPY class-service/ . -COPY shared-libs ./shared-libs - -RUN npx prisma generate --schema=prisma/schema.prisma - -USER nodeusr - -ENV NODE_ENV=production +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:3003/health || exit 1 EXPOSE 3003 -CMD ["npm", "start"] \ No newline at end of file +CMD ["npm", "run", "dev"] \ No newline at end of file diff --git a/class-service/Dockerfile.lambda b/class-service/Dockerfile.lambda new file mode 100644 index 0000000..b1fad32 --- /dev/null +++ b/class-service/Dockerfile.lambda @@ -0,0 +1,37 @@ +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS deps + +# Lambda workdir chuẩn +WORKDIR /var/task + +# NOTE: Cần chạy build từ root +COPY class-service/package*.json . + +RUN npm ci + +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS builder + +WORKDIR /var/task + +COPY --from=deps /var/task/node_modules ./node_modules + +COPY class-service/ . +COPY shared-libs ./shared-libs + +# Generate Prisma client +RUN npx prisma generate + +# Bỏ devDependencies và xóa cache npm +RUN npm prune --omit=dev && npm cache clean --force + +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS runner + +WORKDIR /var/task + +COPY --from=builder /var/task . + +# APP_ENV test AWS infra local +ENV NODE_ENV=production +ENV APP_ENV=production + +# Lambda handler +CMD ["server.handler"] \ No newline at end of file diff --git a/class-service/package.json b/class-service/package.json index de72e14..fcc73b2 100644 --- a/class-service/package.json +++ b/class-service/package.json @@ -21,7 +21,6 @@ "axios": "^1.11.0", "bcrypt": "^6.0.0", "cookie-parser": "^1.4.7", - "dotenv": "^17.2.1", "express": "^5.1.0", "fs": "^0.0.1-security", "ioredis": "^5.7.0", @@ -29,13 +28,12 @@ "jsonwebtoken": "^9.0.2", "pino": "^9.9.0", "pino-http": "^10.5.0", - "prisma": "^6.14.0", - "serverless-http": "^4.0.0", - "uuid": "^11.1.0" + "serverless-http": "^4.0.0" }, "devDependencies": { "artillery": "^2.0.25", "nodemon": "^3.1.10", - "pino-pretty": "^13.1.1" + "pino-pretty": "^13.1.1", + "prisma": "^6.14.0" } } diff --git a/class-service/server.js b/class-service/server.js index c3284e7..458064e 100644 --- a/class-service/server.js +++ b/class-service/server.js @@ -15,6 +15,10 @@ app.use(express.json()); app.use(cookieParser()); app.use(pinoLogger); +app.get('/health', (req, res) => { + res.status(200).json({ status: 'ok' }); +}); + app.use(authentication); app.use('/classes', classRouter); diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index c4dc282..6fe6fb6 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -1,4 +1,4 @@ -# Docker compose dùng cho test database hosting +# Docker compose dùng cho test database hosting và lambda container services: redis: image: redis:7-alpine @@ -17,75 +17,182 @@ services: user: build: context: . - dockerfile: auth-service/Dockerfile - target: production + dockerfile: auth-service/Dockerfile.lambda image: classroom-user:prod container_name: user-prod ports: - - "3001:3001" + - "9001:8080" + environment: + - APP_ENV=development env_file: - ./auth-service/.env - ./env-prod/.env.user + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf -X POST http://localhost:8080/2015-03-31/functions/function/invocations \ + -H 'Content-Type: application/json' \ + -d '{ + \"version\":\"2.0\", + \"routeKey\":\"GET /health\", + \"rawPath\":\"/health\", + \"requestContext\":{ + \"http\":{ + \"method\":\"GET\", + \"path\":\"/health\" + } + } + }' || exit 1" + ] + interval: 30s + timeout: 5s + retries: 3 + start_period: 20s student: build: context: . - dockerfile: student-service/Dockerfile - target: production + dockerfile: student-service/Dockerfile.lambda image: classroom-student:prod container_name: student-prod ports: - - "3002:3002" + - "9002:8080" + environment: + - APP_ENV=development env_file: - ./student-service/.env - ./env-prod/.env.student - depends_on: - - user + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf -X POST http://localhost:8080/2015-03-31/functions/function/invocations \ + -H 'Content-Type: application/json' \ + -d '{ + \"version\":\"2.0\", + \"routeKey\":\"GET /health\", + \"rawPath\":\"/health\", + \"requestContext\":{ + \"http\":{ + \"method\":\"GET\", + \"path\":\"/health\" + } + } + }' || exit 1" + ] + interval: 30s + timeout: 5s + retries: 3 + start_period: 20s class: build: context: . - dockerfile: class-service/Dockerfile - target: production + dockerfile: class-service/Dockerfile.lambda image: classroom-class:prod container_name: class-prod ports: - - "3003:3003" + - "9003:8080" + environment: + - APP_ENV=development env_file: - ./class-service/.env - - ./env-prod/.env.class - depends_on: - - user + - ./env-prod/.env.clas + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf -X POST http://localhost:8080/2015-03-31/functions/function/invocations \ + -H 'Content-Type: application/json' \ + -d '{ + \"version\":\"2.0\", + \"routeKey\":\"GET /health\", + \"rawPath\":\"/health\", + \"requestContext\":{ + \"http\":{ + \"method\":\"GET\", + \"path\":\"/health\" + } + } + }' || exit 1" + ] + interval: 30s + timeout: 5s + retries: 3 + start_period: 20s tuition: build: context: . - dockerfile: tuition-service/Dockerfile - target: production + dockerfile: tuition-service/Dockerfile.lambda image: classroom-tuition:prod container_name: tuition-prod ports: - - "3004:3004" + - "9004:8080" + environment: + - APP_ENV=development env_file: - ./tuition-service/.env - ./env-prod/.env.tuition - depends_on: - - user + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf -X POST http://localhost:8080/2015-03-31/functions/function/invocations \ + -H 'Content-Type: application/json' \ + -d '{ + \"version\":\"2.0\", + \"routeKey\":\"GET /health\", + \"rawPath\":\"/health\", + \"requestContext\":{ + \"http\":{ + \"method\":\"GET\", + \"path\":\"/health\" + } + } + }' || exit 1" + ] + interval: 30s + timeout: 5s + retries: 3 + start_period: 20s teacher: build: context: . - dockerfile: teacher-service/Dockerfile - target: production + dockerfile: teacher-service/Dockerfile.lambda image: classroom-teacher:prod container_name: teacher-prod ports: - - "3005:3005" + - "9005:8080" + environment: + - APP_ENV=development env_file: - ./teacher-service/.env - ./env-prod/.env.teacher - depends_on: - - user + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf -X POST http://localhost:8080/2015-03-31/functions/function/invocations \ + -H 'Content-Type: application/json' \ + -d '{ + \"version\":\"2.0\", + \"routeKey\":\"GET /health\", + \"rawPath\":\"/health\", + \"requestContext\":{ + \"http\":{ + \"method\":\"GET\", + \"path\":\"/health\" + } + } + }' || exit 1" + ] + interval: 30s + timeout: 5s + retries: 3 + start_period: 20s volumes: redis_data: \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 93bdab0..2abc831 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -104,7 +104,6 @@ services: build: context: . dockerfile: auth-service/Dockerfile - target: development image: classroom-user:dev container_name: user ports: @@ -128,7 +127,6 @@ services: build: context: . dockerfile: student-service/Dockerfile - target: development image: classroom-student:dev container_name: student ports: @@ -145,13 +143,11 @@ services: - ./student-service/.env depends_on: - student-db - - auth class: build: context: . dockerfile: class-service/Dockerfile - target: development image: classroom-class:dev container_name: class ports: @@ -168,13 +164,11 @@ services: - ./class-service/.env depends_on: - class-db - - auth tuition: build: context: . dockerfile: tuition-service/Dockerfile - target: development image: classroom-tuition:dev container_name: tuition ports: @@ -191,13 +185,11 @@ services: - ./tuition-service/.env depends_on: - tuition-db - - auth teacher: build: context: . dockerfile: teacher-service/Dockerfile - target: development image: classroom-teacher:dev container_name: teacher ports: @@ -214,7 +206,6 @@ services: - CHOKIDAR_USEPOLLING=true depends_on: - teacher-db - - auth volumes: redis_data: diff --git a/shared-libs/utils/aws-secret-manager.js b/shared-libs/utils/aws-secret-manager.js index 0a31168..54870fe 100644 --- a/shared-libs/utils/aws-secret-manager.js +++ b/shared-libs/utils/aws-secret-manager.js @@ -3,7 +3,7 @@ import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-sec // NOTE: Configure aws cli để aws tự động lấy access key hoặc thêm credential khi tạo SecretsManagerClient (dev env) export default class SecretService { static async getSecret(secretName) { - if (process.env.NODE_ENV !== "production") + if (process.env.APP_ENV !== "production") return {}; const client = new SecretsManagerClient({ @@ -15,7 +15,7 @@ export default class SecretService { } static async setDatabaseUrl(secretName) { - if (process.env.NODE_ENV !== "production") + if (process.env.APP_ENV !== "production") return; const secret = await this.getSecret(secretName); diff --git a/student-service/Dockerfile b/student-service/Dockerfile index 9832e06..701c49e 100644 --- a/student-service/Dockerfile +++ b/student-service/Dockerfile @@ -1,10 +1,12 @@ -FROM node:22-alpine AS base +FROM node:22-alpine WORKDIR /app -COPY student-service/package*.json ./ +# Cài curl do alpine không có sẵn +RUN apk add --no-cache curl -FROM base AS development +# Cần chạy build từ /root +COPY student-service/package*.json ./ RUN npm install @@ -14,26 +16,9 @@ COPY shared-libs ./shared-libs # Generate Prisma client cho môi trường Alpine (linux-musl) RUN npx prisma generate -EXPOSE 3002 - -CMD ["npm", "run", "dev"] - -FROM base AS production - -RUN addgroup --system --gid 1001 nodejs \ - && adduser --system --uid 1001 nodeusr - -RUN npm ci --omit=dev && npm cache clean --force - -COPY student-service/ . -COPY shared-libs ./shared-libs - -RUN npx prisma generate --schema=prisma/schema.prisma - -USER nodeusr - -ENV NODE_ENV=production +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:3002/health || exit 1 EXPOSE 3002 -CMD ["npm", "start"] \ No newline at end of file +CMD ["npm", "run", "dev"] \ No newline at end of file diff --git a/student-service/Dockerfile.lambda b/student-service/Dockerfile.lambda new file mode 100644 index 0000000..a135f72 --- /dev/null +++ b/student-service/Dockerfile.lambda @@ -0,0 +1,37 @@ +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS deps + +# Lambda workdir chuẩn +WORKDIR /var/task + +# NOTE: Cần chạy build từ root +COPY student-service/package*.json . + +RUN npm ci + +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS builder + +WORKDIR /var/task + +COPY --from=deps /var/task/node_modules ./node_modules + +COPY student-service/ . +COPY shared-libs ./shared-libs + +# Generate Prisma client +RUN npx prisma generate + +# Bỏ devDependencies và xóa cache npm +RUN npm prune --omit=dev && npm cache clean --force + +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS runner + +WORKDIR /var/task + +COPY --from=builder /var/task . + +# APP_ENV test AWS infra local +ENV NODE_ENV=production +ENV APP_ENV=production + +# Lambda handler +CMD ["server.handler"] \ No newline at end of file diff --git a/student-service/package.json b/student-service/package.json index d2fb615..fd90bbe 100644 --- a/student-service/package.json +++ b/student-service/package.json @@ -21,7 +21,6 @@ "@prisma/client": "^6.15.0", "bcrypt": "^6.0.0", "cookie-parser": "^1.4.7", - "dotenv": "^17.2.1", "express": "^5.1.0", "fs": "^0.0.1-security", "ioredis": "^5.7.0", @@ -29,13 +28,12 @@ "jsonwebtoken": "^9.0.2", "pino": "^9.9.0", "pino-http": "^10.5.0", - "prisma": "^6.14.0", - "serverless-http": "^4.0.0", - "uuid": "^11.1.0" + "serverless-http": "^4.0.0" }, "devDependencies": { "artillery": "^2.0.25", "nodemon": "^3.1.10", - "pino-pretty": "^13.1.1" + "pino-pretty": "^13.1.1", + "prisma": "^6.14.0" } } diff --git a/student-service/server.js b/student-service/server.js index 60e1842..4f5e1c5 100644 --- a/student-service/server.js +++ b/student-service/server.js @@ -15,6 +15,10 @@ app.use(express.json()); app.use(cookieParser()); app.use(pinoLogger); +app.get('/health', (req, res) => { + res.status(200).json({ status: 'ok' }); +}); + app.use(authentication); app.use('/students', router); diff --git a/teacher-service/Dockerfile b/teacher-service/Dockerfile index 58ca9cf..7e887ec 100644 --- a/teacher-service/Dockerfile +++ b/teacher-service/Dockerfile @@ -1,10 +1,12 @@ -FROM node:22-alpine AS base +FROM node:22-alpine WORKDIR /app -COPY teacher-service/package*.json ./ +# Cài curl do alpine không có sẵn +RUN apk add --no-cache curl -FROM base AS development +# Cần chạy build từ /root +COPY teacher-service/package*.json ./ RUN npm install @@ -14,26 +16,9 @@ COPY shared-libs ./shared-libs # Generate Prisma client cho môi trường Alpine (linux-musl) RUN npx prisma generate -EXPOSE 3005 - -CMD ["npm", "run", "dev"] - -FROM base AS production - -RUN addgroup --system --gid 1001 nodejs \ - && adduser --system --uid 1001 nodeusr - -RUN npm ci --omit=dev && npm cache clean --force - -COPY teacher-service/ . -COPY shared-libs ./shared-libs - -RUN npx prisma generate --schema=prisma/schema.prisma - -USER nodeusr - -ENV NODE_ENV=production +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:3005/health || exit 1 EXPOSE 3005 -CMD ["npm", "start"] \ No newline at end of file +CMD ["npm", "run", "dev"] \ No newline at end of file diff --git a/teacher-service/Dockerfile.lambda b/teacher-service/Dockerfile.lambda new file mode 100644 index 0000000..1ae89e7 --- /dev/null +++ b/teacher-service/Dockerfile.lambda @@ -0,0 +1,37 @@ +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS deps + +# Lambda workdir chuẩn +WORKDIR /var/task + +# NOTE: Cần chạy build từ root +COPY teacher-service/package*.json . + +RUN npm ci + +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS builder + +WORKDIR /var/task + +COPY --from=deps /var/task/node_modules ./node_modules + +COPY teacher-service/ . +COPY shared-libs ./shared-libs + +# Generate Prisma client +RUN npx prisma generate + +# Bỏ devDependencies và xóa cache npm +RUN npm prune --omit=dev && npm cache clean --force + +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS runner + +WORKDIR /var/task + +COPY --from=builder /var/task . + +# APP_ENV test AWS infra local +ENV NODE_ENV=production +ENV APP_ENV=production + +# Lambda handler +CMD ["server.handler"] \ No newline at end of file diff --git a/teacher-service/package.json b/teacher-service/package.json index 80b22a8..77c21b7 100644 --- a/teacher-service/package.json +++ b/teacher-service/package.json @@ -22,7 +22,6 @@ "@prisma/client": "^6.15.0", "bcrypt": "^6.0.0", "cookie-parser": "^1.4.7", - "dotenv": "^17.2.1", "express": "^5.1.0", "fs": "^0.0.1-security", "ioredis": "^5.7.0", @@ -31,13 +30,12 @@ "multer": "^2.0.2", "pino": "^9.9.0", "pino-http": "^10.5.0", - "prisma": "^6.14.0", "serverless-http": "^4.0.0", - "sharp": "^0.34.3", - "uuid": "^11.1.0" + "sharp": "^0.34.3" }, "devDependencies": { "nodemon": "^3.1.10", - "pino-pretty": "^13.1.1" + "pino-pretty": "^13.1.1", + "prisma": "^6.14.0" } } diff --git a/teacher-service/server.js b/teacher-service/server.js index b24568c..2d4857a 100644 --- a/teacher-service/server.js +++ b/teacher-service/server.js @@ -15,6 +15,10 @@ app.use(express.json()); app.use(cookieParser()); app.use(pinoLogger); +app.get('/health', (req, res) => { + res.status(200).json({ status: 'ok' }); +}); + app.use(authentication); app.use('/teachers', teacherRouter); diff --git a/tuition-service/Dockerfile b/tuition-service/Dockerfile index 4312044..e12576f 100644 --- a/tuition-service/Dockerfile +++ b/tuition-service/Dockerfile @@ -1,12 +1,13 @@ -FROM node:22-alpine AS base +FROM node:22-alpine WORKDIR /app +# Cài curl do alpine không có sẵn +RUN apk add --no-cache curl + # Cần chạy build từ /root COPY tuition-service/package*.json ./ -FROM base AS development - RUN npm install COPY tuition-service/ . @@ -15,26 +16,9 @@ COPY shared-libs ./shared-libs # Generate Prisma client cho môi trường Alpine (linux-musl) RUN npx prisma generate -EXPOSE 3004 - -CMD ["npm", "run", "dev"] - -FROM base AS production - -RUN addgroup --system --gid 1001 nodejs \ - && adduser --system --uid 1001 nodeusr - -RUN npm ci --omit=dev && npm cache clean --force - -COPY tuition-service/ . -COPY shared-libs ./shared-libs - -RUN npx prisma generate --schema=prisma/schema.prisma - -USER nodeusr - -ENV NODE_ENV=production +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:3004/health || exit 1 EXPOSE 3004 -CMD ["npm", "start"] \ No newline at end of file +CMD ["npm", "run", "dev"] \ No newline at end of file diff --git a/tuition-service/Dockerfile.lambda b/tuition-service/Dockerfile.lambda new file mode 100644 index 0000000..a273c51 --- /dev/null +++ b/tuition-service/Dockerfile.lambda @@ -0,0 +1,37 @@ +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS deps + +# Lambda workdir chuẩn +WORKDIR /var/task + +# NOTE: Cần chạy build từ root +COPY tuition-service/package*.json . + +RUN npm ci + +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS builder + +WORKDIR /var/task + +COPY --from=deps /var/task/node_modules ./node_modules + +COPY tuition-service/ . +COPY shared-libs ./shared-libs + +# Generate Prisma client +RUN npx prisma generate + +# Bỏ devDependencies và xóa cache npm +RUN npm prune --omit=dev && npm cache clean --force + +FROM public.ecr.aws/lambda/nodejs@sha256:ba6eb28e407ede3f5d8ab441aadd4ad7558cfdb099f324f195d1f6ddc885d4bf AS runner + +WORKDIR /var/task + +COPY --from=builder /var/task . + +# APP_ENV test AWS infra local +ENV NODE_ENV=production +ENV APP_ENV=production + +# Lambda handler +CMD ["server.handler"] \ No newline at end of file diff --git a/tuition-service/package.json b/tuition-service/package.json index 6bc8c84..a19e0f9 100644 --- a/tuition-service/package.json +++ b/tuition-service/package.json @@ -21,7 +21,6 @@ "axios": "^1.11.0", "bcrypt": "^6.0.0", "cookie-parser": "^1.4.7", - "dotenv": "^17.2.1", "express": "^5.1.0", "fs": "^0.0.1-security", "ioredis": "^5.7.0", @@ -29,13 +28,12 @@ "jsonwebtoken": "^9.0.2", "pino": "^9.9.0", "pino-http": "^10.5.0", - "prisma": "^6.14.0", - "serverless-http": "^4.0.0", - "uuid": "^11.1.0" + "serverless-http": "^4.0.0" }, "devDependencies": { "artillery": "^2.0.25", "nodemon": "^3.1.10", - "pino-pretty": "^13.1.1" + "pino-pretty": "^13.1.1", + "prisma": "^6.14.0" } } diff --git a/tuition-service/server.js b/tuition-service/server.js index 1915a07..487500e 100644 --- a/tuition-service/server.js +++ b/tuition-service/server.js @@ -16,11 +16,15 @@ app.use(express.json()); app.use(cookieParser()); app.use(pinoLogger); +app.get('/health', (req, res) => { + res.status(200).json({ status: 'ok' }); +}); + app.use(authentication); -app.use('/tuition/invoices', checkClassExist, invoiceRouter); -app.use('/tuition/payments', checkClassExist, paymentRouter); -app.use('/tuition/reports', reportRouter); +app.use('/tuitions/invoices', checkClassExist, invoiceRouter); +app.use('/tuitions/payments', checkClassExist, paymentRouter); +app.use('/tuitions/reports', reportRouter); app.use(routeNotFound); app.use(errorHandler);