MIJI DApp Server Docs

개발 환경 설정 가이드 V2 (DEV_README2.md)

- 세부 운영 및 배포 가이드 -

본 문서는 DEV_README.md (v8)를 기반으로, 실제 구현 및 배포에 필요한 10가지 세부 항목(CI/CD, 큐 파라미터, 로깅, Mocking 등)을 정의합니다.

1. 환경 변수 명세 (/server/.env.example)

DEV_README.md (v8)의 ConfigModule을 지원하기 위한 상세 .env 키 목록입니다.

# -——————————–
# NestJS & Server
# -——————————–
NODE_ENV=development
SERVER_PORT=3000

# -——————————–
# Auth & Security (A-120, 7번 항목)
# -——————————–
# 콤마(,)로 구분된 복수의 키를 지원 (키 회전용)
GLOBAL_SECRET_KEY=primary_key,secondary_key
# Throttler (Rate Limit) - 1분에 60개 요청
THROTTLE_TTL=60
THROTTLE_LIMIT=60

# -——————————–
# Databases (P1-1, P1-3)
# -——————————–
DB_URI=mongodb+srv://…
REDIS_HOST=localhost
REDIS_PORT=6379

# -——————————–
# AWS Credentials (P1-2, M-050)
# -——————————–
# (권장) EC2 Instance Role을 사용하면 아래 2개는 필요 없음. 로컬 개발용.
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=ap-northeast-2
S3_BUCKET_NAME=miji-nft-assets-dev

# -——————————–
# Blockchain & Secrets (P1-2, B-100)
# -——————————–
# (핵심) 서버 지갑 PK가 저장된 Secrets Manager의 ARN
PK_SECRET_ARN=arn:aws:secretsmanager:ap-northeast-2:….
# (핵심) PK 캐시 TTL (초) (M1 제안)
PK_CACHE_TTL_SECONDS=300
# (신규) 로컬 개발 시 Mock PK (2번 항목 참조)
LOCAL_DEV_PK=0x…

# -——————————–
# Chain RPC Endpoints (B-100)
# -——————————–
CHAIN_RPC_URL_43114=[https://api.avax.network/ext/bc/C/rpc](https://api.avax.network/ext/bc/C/rpc)
CHAIN_RPC_URL_137=[https://polygon-rpc.com](https://polygon-rpc.com)

# -——————————–
# Webhooks (H-200)
# -——————————–
WEBHOOK_URL_DEFAULT=[https://api.miji.service.com/v1/webhook/nft](https://api.miji.service.com/v1/webhook/nft)
WEBHOOK_SECRET=whsec_…

2. Secrets Manager 구조 및 운영 (M1, M4)

PLAN.md (M1)에 따라 PK는 5분(300초)간 인메모리 캐싱합니다.

3. Bull 큐 운영 파라미터 (B3)

PLAN.md (v8)의 3개 큐에 대해, concurrency (동시 처리 수) 및 timeout (작업 시간 초과)을 명시합니다. (M2 제안)

큐 이름 PLAN.md ID Concurrency (동시 처리) Timeout (ms) Job 옵션 (기본값)
minting-queue (T-110) 5 (노드 과부하 방지) 120,000 (2분) attempts: 3, backoff: { type: ‘exponential’, delay: 5000 }
deployment-queue (C-130) 1 (배포는 순차 처리) 300,000 (5분) attempts: 2, backoff: { type: ‘exponential’, delay: 10000 }
webhook-queue (H-200) 10 (웹훅은 다발적 전송) 5,000 (5초) attempts: 5, backoff: { type: ‘exponential’, delay: 10000 }

4. 배포 파이프라인 (CI/CD) (B1)

사용자 시나리오(GitHub Actions -> ECR -> CodeDeploy -> EC2)를 반영한 상세 워크플로우입니다.

4-1. Dockerfile (ARM64 전용)

server/Dockerfile (멀티 스테이지/아티팩트 포함)

# -——————————–
# Stage 1: Builder
# -——————————–
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY server/package.json ./server/
COPY contracts/package.json ./contracts/
RUN npm install -g pnpm
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm --filter contracts build
RUN pnpm --filter server build

# -——————————–
# Stage 2: Final Runtime
# -——————————–
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/server/dist ./dist
COPY --from=builder /app/contracts/artifacts ./artifacts
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/server/node_modules ./server/node_modules
CMD [“node”, “dist/main.js”]

4-2. GitHub Actions (.github/workflows/deploy.yml)

main 브랜치 푸시 시, Docker 이미지를 빌드/푸시하고 CodeDeploy 배포를 트리거합니다.

name: Deploy to EC2 (Dev)

on:
push:
branches:
- main # (Dev 배포용) 또는 ‘develop’ 브랜치

jobs:
# 1. Docker 이미지 빌드 및 ECR 푸시
build-and-push:
name: Build and Push to ECR
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

  \- name: Configure AWS Credentials  
    uses: aws-actions/configure-aws-credentials@v4  
    with:  
      aws-access-key-id: $  
      aws-secret-access-key: $  
      aws-region: $

  \- name: Login to Amazon ECR  
    id: login-ecr  
    uses: aws-actions/amazon-ecr-login@v2

  \- name: Set up QEMU (for ARM build)  
    uses: docker/setup-qemu-action@v3

  \- name: Set up Docker Buildx  
    uses: docker/setup-buildx-action@v3

  \- name: Build and push (ARM64)  
    id: build-image  
    uses: docker/build-push-action@v5  
    with:  
      context: .  
      file: server/Dockerfile  
      push: true  
      tags: $/$:latest  
      platforms: linux/arm64 \# (B1) ARM64 전용 빌드

# 2. AWS CodeDeploy 실행
trigger-deploy:
name: Trigger AWS CodeDeploy
runs-on: ubuntu-latest
needs: build-and-push # 빌드 잡이 성공해야 실행
steps:
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
# (자격 증명 동일)

  \- name: Trigger CodeDeploy  
    run: |  
      aws deploy create-deployment \\  
        \--application-name Miji-NFT-Server-App \\  
        \--deployment-group-name Miji-NFT-Server-Dev-Group \\  
        \--deployment-config-name CodeDeployDefault.OneAtATime \\  
        \--description "Deploy from GitHub Actions" \\  
        \--revision '{"revisionType": "AppSpecContent", "appSpecContent": {"content": "...", "sha256": "..."}}'  
      \# (참고: CodeDeploy 설정에 따라 ECR/S3 리비전을 지정해야 함)

4-3. EC2 배포 스크립트 (appspec.yml 및 셸 스크립트)

EC2 인스턴스에 codedeploy-agent가 설치되어 있어야 하며, 루트에 appspec.yml 파일이 필요합니다.

/appspec.yml

version: 0.0
os: linux
files:
- source: /docker-compose.yml # (6번 항목)
destination: /home/ec2-user/miji-nft-server/
hooks:
ApplicationStop:
- location: scripts/stop_server.sh
timeout: 30
runas: ec2-user
BeforeInstall:
- location: scripts/pull_image.sh
timeout: 300
runas: ec2-user
ApplicationStart:
- location: scripts/start_server.sh
timeout: 60
runas: ec2-user

/scripts/pull_image.sh (CodeDeploy가 ECR에서 새 이미지를 받도록 함)

#!/bin/bash
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
ECR_REGISTRY=${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-2.amazonaws.com
IMAGE_NAME=miji-nft-repository-name # (GitHub 변수와 일치)

aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $ECR_REGISTRY
docker pull $ECR_REGISTRY/$IMAGE_NAME:latest

/scripts/start_server.sh (Docker Compose 실행)

#!/bin/bash
cd /home/ec2-user/miji-nft-server/
# .env 파일은 CodeDeploy 외부에서 관리(e.g., S3에서 가져오기)되어야 함
docker-compose up -d --no-build

5. 컨트랙트 배포 전략 (v8 원안)

(DEV_README.md (v8) 원안을 따름)
서버는 **동적 배포 API(C-130)**를 제공합니다. CI/CD(Dockerfile) 시 contracts/의 ABI/Bytecode를 서버 이미지에 미리 구워넣고, ContractsProcessor가 이 아티팩트를 읽어 deployment-queue를 통해 비동기로 배포합니다.

6. 테스트 인프라 (B4)

(제안대로 확정)

7. 인증/보안 디테일 (Rate Limit)

8. 메타데이터 규칙 (DTO)

9. Webhook 대상 규격 (H-200)

10. 운영 모니터링 (M3)

  1. 로그 포맷 (JSON): nestjs-pino를 사용하여 JSON 로그를 출력합니다. (M3 제안)
    • server/src/app.module.ts (설정 예시):
      import { Module } from ‘@nestjs/common’;
      import { LoggerModule } from ‘nestjs-pino’;

      @Module({
      imports: [
      LoggerModule.forRootAsync({
      useFactory: () => ({
      pinoHttp: {
      // (M3) Production에서는 JSON, Dev에서는 예쁘게
      transport: process.env.NODE_ENV !== ‘production’
      ? { target: ‘pino-pretty’ }
      : undefined,
      // (M3) 타임스탬프, 레벨, 컨텍스트 포함 (기본값)
      level: process.env.NODE_ENV !== ‘production’ ? ‘debug’ : ‘info’,
      },
      }),
      }),
      // … (기타 모듈)
      ],
      })
      export class AppModule {}

  2. 로그 수집: (사용자 계획) CloudWatch Agent가 위 JSON 로그를 수집합니다. 알람 및 대시보드는 별도 Terraform 리포지토리에서 관리합니다.
  3. 큐 모니터링: @bull-board/nestjs 라이브러리를 /admin/queues 엔드포인트에 적용하여 1인 개발자가 실패한 Job을 시각적으로 모니터링합니다. (이전과 동일)