Nodejs

 

 

 nest g app  설치

 

 

1. Docker Compose 설정 (docker-compose-payment.yml)

먼저 Payment 마이크로서비스를 위한 독립된 Docker Compose 파일을 작성합니다.

services:

  payment:
    build:
      context: .
      dockerfile: ./apps/payment/Dockerfile
      target: development
    command: pnpm run start:dev payment
    depends_on:
      postgres_payment:
        condition: service_healthy
    env_file:
      - ./apps/payment/.env
    ports:
      - '3004:3004'  
    volumes:
      - .:/usr/src/app
      - /usr/src/app/node_modules

  postgres_payment:
    image: postgres:16
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    ports:
      - '6004:5432'
    volumes:
      - ./postgres/payment:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 10
      start_period: 5s

설명:

  • payment 서비스는 NestJS 애플리케이션을 실행하며, pnpm으로 시작됩니다.

  • postgres_payment는 해당 서비스만을 위한 전용 PostgreSQL 컨테이너입니다.

  • healthcheck 설정을 통해 DB가 준비될 때까지 대기합니다.

 

 

 

2. Dockerfile 설정 (apps/payment/Dockerfile)

NestJS 애플리케이션을 빌드하고 실행하기 위한 Dockerfile입니다.

FROM node:alpine AS development

WORKDIR /usr/src/app

COPY package*.json ./
COPY pnpm-lock.yaml ./
COPY tsconfig.json tsconfig.json
COPY nest-cli.json nest-cli.json

RUN npm i -g pnpm
RUN pnpm i

COPY apps/payment apps/payment

RUN pnpm build payment

CMD ["pnpm", "start:dev", "payment"]

설명:

  • node:alpine 경량 이미지를 기반으로 빌드합니다.

  • pnpm을 사용해 의존성을 설치하고, payment 앱을 빌드합니다.

 

 

 

3. 애플리케이션 모듈 구성

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';

import * as Joi from 'joi';
import { PaymentModule } from './payment/payment.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      validationSchema: Joi.object({
        HTTP_PORT: Joi.number().required(),
        DB_URL: Joi.string().required(),
      }),
    }),
    TypeOrmModule.forRootAsync({
      useFactory: (configService: ConfigService) => ({
        type: 'postgres',
        url: configService.getOrThrow('DB_URL'),
        autoLoadEntities: true,
        synchronize: true,
      }),
      inject: [ConfigService],
    }),
    PaymentModule,
  ],
})
export class AppModule {}

설명:

  • .env 파일의 유효성을 Joi로 검증합니다.

  • TypeORM 설정을 비동기로 주입받으며, DB_URL 환경변수로 DB 연결을 설정합니다.

  • PaymentModule을 import하여 결제 관련 기능을 모듈화합니다.

 

 

4. 앱 진입점 구성 (main.ts)

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(process.env.HTTP_PORT ?? 3004);
}
bootstrap();

설명:

  • 환경 변수 HTTP_PORT가 없으면 기본값 3004에서 서버를 실행합니다.

 

 

5. Payment 모듈 구성

payment.module.ts

import { Module } from '@nestjs/common';
import { PaymentController } from './payment.controller';
import { PaymentService } from './payment.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Payment } from './payment.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Payment])],
  controllers: [PaymentController],
  providers: [PaymentService],
})
export class PaymentModule {}

설명:

  • 해당 모듈은 단일 책임 원칙을 지키며, 결제 관련 컨트롤러/서비스를 포함합니다.

  • TypeOrmModule.forFeature로 Payment 엔티티를 모듈에 등록합니다.

 

 

 

6. Payment Entity 구성

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

export enum PaymentStatus {
  pending = 'Pending',
  rejected = 'Rejected',
  approved = 'Approved',
}

export enum PaymentMethod {
  creditCard = 'CreditCard',
  kakao = 'Kakao',
}

export enum NotificationStatus {
  pending = 'pending',
  sent = 'sent',
}

@Entity()
export class Payment {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({
    enum: PaymentStatus,
    type: 'enum',
    default: PaymentStatus.pending,
  })
  paymentStatus: PaymentStatus;

  @Column({
    enum: PaymentMethod,
    type: 'enum',
    default: PaymentMethod.creditCard,
  })
  paymentMethod: PaymentMethod;

  @Column()
  cardNumber: string;

  @Column()
  expiryYear: string;

  @Column()
  expiryMonth: string;

  @Column()
  birthOrRegistration: string;

  @Column()
  passwordTwoDigits: string;

  @Column({
    enum: NotificationStatus,
    type: 'enum',
    default: NotificationStatus.pending,
  })
  notificationStatus: NotificationStatus;
}

설명:

  • Payment 엔티티는 결제 요청 정보를 담고 있으며, 총 3개의 enum 필드를 포함합니다:

    • paymentStatus: 결제 상태 (Pending, Rejected, Approved)

    • paymentMethod: 결제 방식 (CreditCard, Kakao)

    • notificationStatus: 알림 상태 (pending, sent)

  • 카드 정보와 본인 인증 정보도 포함되어 있습니다.

  • 이후 이 엔티티를 기반으로 결제 처리 및 알림 로직이 확장됩니다.

 

 

 

7. Controller / Service 구성

payment.controller.ts

import { Controller, Get } from '@nestjs/common';
import { PaymentService } from './payment.service';

@Controller()
export class PaymentController {
  constructor(private readonly paymentService: PaymentService) {}

  @Get()
  getHello(): string {
    return this.paymentService.getHello();
  }
}

payment.service.ts

import { Injectable } from '@nestjs/common';

@Injectable()
export class PaymentService {
  getHello(): string {
    return 'Hello World!';
  }
}

 

설명:

  • 현재는 간단한 텍스트(Hello World!)를 반환하지만, 이후 실제 결제 로직으로 확장됩니다.

  • NestJS의 기본 구조 (Controller -> Service 구조)를 따릅니다.

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

사람은 항상 불가능한 짓을 억지로 하다가 생명을 잃게 되고, 또 자기에게 불편한 짓을 억지로 해서 패한다. 통솔자는 이런 일이 생기지 않도록 사전에 부하를 잘 훈련하여 가르쳐 두어야 한다. -오자

댓글 ( 0)

댓글 남기기

작성