기능 구현 사항 정리

박화랑·2025년 6월 13일

Spring_6기

목록 보기
27/32
  • 개발자가 강의를 검색하고 추천받을 수 있는 온라인 학습 플랫폼 Devmountain!
    이 글에서는 실제 구현 과정 중 내가 맡게 된 기능들(토스 API 연동, CI/CD, Docker, BraveSearch)에 대해서 구현 사항과 관련 내용들을 정리했다.

왜 토스페이API를 사용할까?

간단하다. 가장 편리하고 편하게 사용할 수 있는 결제 방식이다. 무엇보다 결제에 관한 기능들을 한 번씩 테스트 해보는 것은 이후에 좋은 경험이 될 것이다.

  1. 토스페이 결제 시스템

1.1 API 연동 흐름

  • 클라이언트 결제 요청 → 서버에서 토스 API 호출
  • 결제 승인/실패 → 콜백으로 응답 받아 처리

Toss 결제 흐름 설명 (구현 코드 기반)

  1. 클라이언트(프론트)에서 결제 요청
  • 사용자가 결제를 요청하면, orderId, amount, orderName, customerEmail 등의 정보가 포함된 결제 요청이 생성됨.
  • 이 요청은 Toss 결제 페이지로 리디렉션되며 사용자는 Toss UI에서 결제를 진행함.

  1. Toss에서 결제 완료 후 콜백 처리
  • 사용자가 결제를 완료하면 Toss에서 successUrl 또는 failUrl 로 리디렉션 됨.
  • 이때 클라이언트는 리디렉션된 URL에서 paymentKey, orderId, amount 값을 추출해서 서버로 전달함.
// 클라이언트에서 받은 paymentKey, orderId, amount 를 기반으로 서버 요청
paymentService.confirmPayment(paymentKey, orderId, amount);

  1. 서버에서 결제 승인 API 호출
  • TossApiClient 클래스에서 Toss의 결제 승인 API(/v1/payments/confirm)에 요청.
  • 헤더에 Authorization: Basic {secretKey}가 포함되고, JSON body로 paymentKey, orderId, amount 전송.
// TossApiClient.java
public TossPaymentResponse confirmPayment(String paymentKey, String orderId, int amount) {
    // HTTP 요청 구성 후 Toss로 전송
}

  1. 결제 승인 후 DB 저장
    • Toss에서 성공 응답을 받으면 PaymentService에서 응답 내용을 파싱.
    • 결제 결과(SUCCESS/FAIL)에 따라 DB에 저장.
    • Payment 테이블의 result, payment_key, orderID, userId 등을 저장.
// PaymentService.java
paymentRepository.save(new Payment(...)); // JPA 엔티티 저장

  1. 회원 등급 변경 처리 (FREE → PRO)
  • 결제가 성공하고 유료 상품이라면, 해당 유저의 membership_level을 PRO로 변경.
// PaymentService.java
user.setMembershipLevel(PRO);
userRepository.save(user);



  1. 응답 결과 리턴
  • 성공 시: 결제 완료 메시지 및 결제 상세 정보 리턴
  • 실패 시: 에러 메시지 전송

2. Brave Search를 이용한 외부 강의 검색 기능 정리

2.1 Brave Search란?

  • Brave Search는 GPT가 생성한 쿼리를 기반으로 실시간 웹 검색을 수행하는 외부 API
  • 최신 트렌드, 외부 정보 기반의 보완 검색이 가능하다.
  • 브레이브 서치를 사용한 이유: 무엇보다 무료로 기능을 사용할 수 있다는 장점이 있다. (무료로 월 2000회 까지 가능 및 1초에 1번 가능). 게다가 쿼리 기반 검색을 진행하는 우리 프로젝트에 맞춰 간단한 쿼리로도 많은 검색 정보를 찾을 수 있는 브레이브 서치가 적절하다고 판단했다.
    브레이브 서치 api 링크

2.2 GPT와의 연결 구조 (코드 흐름 기반)

  1. 사용자 입력 처리
  • 사용자가 챗봇에 "나는 개발자를 시작해보려고 하는 사람이야. 지금 백엔드 개발자를 해보기 위해 기초적인 강의 자료들을 찾고 있어."처럼 질의함
  • 해당 요청은 GPT가 키워드를 추출하고 Brave Search에 전달
  1. BraveSearchService
  • BraveSearchService.searchBrave(String query)
    → GPT가 만든 쿼리 문자열을 사용해 외부 Brave Search API 호출
    → BraveSearchResponseDto 형태로 결과 파싱
BraveSearchResponseDto response = braveSearchService.searchBrave(userQuery);
  1. 결과 반환 및 가공
  • BraveSearchResponseDto에는 title, url, snippet 등 주요 정보 포함
  • 유저 정보가 회원이거나 PRO 유저라면 브레이브 서치 검색결과도 같이 포함해서 조회하도록 수정
  1. LectureRecommendationService
  • 내부 DB 조회 후 유사 강의 조회 후 BraveSearchService 호출하는 로직 포함되어 있음

2.3 검색 결과 활용 방식

  • Brave 검색 결과는 프론트에 그대로 전달되거나, 요약되어 챗봇 응답에 삽입됨.
  • 예시 흐름:
  • "요즘 인기 있는 강의 알려줘" → 회원 정보 판단 (GUEST가 아닐 경우) → Brave Search 활용 → 최신 강의 링크 요약 제공

3. Docker로 프로젝트 환경 표준화하기

3.1 도커 환경 구성

  • 프로젝트 전체를 컨테이너 기반으로 구성하여 개발 환경을 통일했습니다.
  • docker-compose.yaml을 통해 여러 서비스를 한 번에 실행합니다.
  • 구성된 서비스:
    • PostgreSQL (벡터 DB 지원: ankane/pgvector)
    • Redis 및 Redis Stack
    • Spring Boot 백엔드 애플리케이션
    • 프론트엔드는 추후 추가 예정

3.2 Dockerfile & docker-compose 설명

Dockerfile

  • Spring Boot 프로젝트를 빌드하고 실행하기 위한 설정입니다.
  • 주요 구성:
    • JDK 기반 이미지에서 애플리케이션 빌드
    • 빌드된 JAR 파일 복사 및 실행
    • EXPOSE 8080 포트 설정

docker-compose.yaml

  • build: 도커 이미지 빌드 경로 지정
  • depends_on: 의존 서비스 정의
  • volumes: DB 데이터 영속성 유지
  • networks: 서비스 간 통신을 위한 네트워크 설정
services:
  postgres:
    image: ankane/pgvector:latest
    ports:
      - "${POSTGRES_PORT}:5432"
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - devmountain-postgres-volume:/var/lib/postgresql/data

  redis:
    image: redis:7.2
    ports:
      - "${REDIS_PORT}:6379"

  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "${APP_PORT}:8080"
    environment:
      SPRING_PROFILES_ACTIVE: prod
      POSTGRES_HOST: postgres
      REDIS_HOST: redis

3.3 로컬 vs 운영 환경 구성

  • .env 파일을 통해 환경 변수들을 분리 관리합니다.
  • 주요 설정:
  • SPRING_PROFILES_ACTIVE=dev 또는 prod
  • Redis/DB 포트, 비밀번호 등 설정
  • 운영 환경에서는 동일한 Docker 구성을 AWS EC2, Lightsail 등에 배포하여 사용할 수 있습니다.

4. CI/CD 자동화 구축기 (GitHub Actions 기반)

4.1 CI/CD의 필요성

  • 테스트 자동화로 코드 안정성을 확보할 수 있습니다.
  • 배포를 반복 가능한 절차로 전환하여 실수를 줄일 수 있습니다.
  • 협업 중에도 병합 이후 바로 테스트/배포되므로 생산성이 향상됩니다.

4.2 GitHub Actions 워크플로우 구성

CI: 테스트 및 빌드 자동화 (ci.yml)

  • develop 또는 main 브랜치에 push될 때 실행됩니다.
  • 주요 단계:
    • 코드 체크아웃
    • JDK 17 설정 (corretto)
    • Gradle 빌드 (test 제외)
    • Gradle 테스트 실행
name: CI - Build and Test

on:
  push:
    branches:
      - "main"
      - "develop"

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'corretto'

      - name: Build
        run: ./gradlew clean build -x test

      - name: Run Tests
        run: ./gradlew test

CD: EC2 서버 배포 자동화 (cd.yml)

  • main 브랜치에 push될 때 실행됩니다.
  • 주요 단계:
    • .env, application-prod.yml 파일 생성
    • SSH 키 설정
    • EC2 원격 접속 후 git pull, build, docker-compose로 재배포
name: CD - Deploy to EC2

on:
  push:
    branches:
      - "main"

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Code
        uses: actions/checkout@v3

      - name: Create .env file
        run: echo "${{ secrets.DOTENV_FILE }}" > .env

      - name: Create application-prod.yml
        run: |
          mkdir -p src/main/resources
          echo "${{ secrets.APPLICATION_PROD_YML }}" > src/main/resources/application-prod.yml

      - name: Set up SSH Key
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.EC2_PRIVATE_KEY }}" > ~/.ssh/devmountain-key.pem
          chmod 600 ~/.ssh/devmountain-key.pem

      - name: Deploy to EC2
        run: |
          ssh -o StrictHostKeyChecking=no -i ~/.ssh/devmountain-key.pem ubuntu@${{ secrets.EC2_HOST }} << 'EOF'
            cd ~/devmountain
            git reset --hard HEAD
            git clean -fd
            git pull origin main
            docker-compose down
            ./gradlew build -x test
            docker-compose up -d --build
          EOF

4.3 자동 테스트, 빌드, 배포까지!

  • GitHub Actions를 통해 CI와 CD를 완전히 자동화했
  • Docker 이미지 빌드부터 AWS EC2에 배포까지 한 번에 처리
  • 관련된 기본 설정들은 깃허브 페이지에서 가능
  • 위 페이지에서 시크릿 설정을 추가할 수 있다.

  1. 마무리 및 회고
  • 실제 서비스를 만들면서 느낀 점
    개발자는 시간과의 싸움이 중요하다고 느꼈다. 내가 구현했다고 끝나는 것이 아니라 다른 사람들이 구현한 내용을 총 관리해야하는 리더의 역할이 중요함을 느꼈다. 지금 팀의 리더나 부리더 같은 경우 이에 관한 관리가 많이 부족한 상태임을 알고 있지만 자신이 맡은 임무도 제대로 끝내지 못해서 다른 사람들의 작업에 대해 왈가왈부 하는 것에 상당히 부담감을 느끼는 것이 좋지 않은 상황임을 인지했다. 내 개인적으로도 직접 회의를 이끌어가며 호응을 이끌어 내려 해도 다들 의견을 표출하지 않으려는 상황이 많이 답답하고 힘들었다. 하지만 분명 나도 완벽한

  • 개선해야 할 점 & 다음 목표
    이후에는 각자 맡은 업무를 언제까지 끝낼 수 있을지 (마감일), 매일 진행 상황에 대해 브리핑을 진행하도록 회의 방향을 바꿀 것을 제안했고 모두가 이 제안을 받아들여 좀 더 협업을 소통을 통해 진행하도록 계획했다. 다음 목표의 경우 이제 MCP 클라이언트 기능을 써 볼 예정이다. 그리고 기능 개선과 직접 서버 배포 설정을 해 볼 예정이다.


profile
개발자 희망생

0개의 댓글