Skip to content

헥사고날 아키텍처와 TDD를 적용한 Spring Boot 기반 온라인 커뮤니티 플랫폼

Notifications You must be signed in to change notification settings

see-projects/back

Repository files navigation

See - 헥사고날 아키텍처 기반 커뮤니티 플랫폼

Java Spring Boot MySQL Test Coverage Architecture

See는 회원 인증과 소셜 커뮤니티 기능을 제공하는 현대적인 웹 애플리케이션입니다. 헥사고날 아키텍처와 도메인 주도 설계(DDD) 원칙을 적용하여 확장 가능하고 유지보수하기 쉬운 구조로 설계되었습니다.

📚 관련 문서

주요 기능

회원 관리

  • 회원 가입/로그인: JWT 토큰 기반 인증 시스템
  • 프로필 관리: 닉네임, 자기소개, 프로필 주소 설정
  • 계정 상태 관리: 활성화/비활성화 상태 전환
  • 보안: BCrypt 암호화로 비밀번호 안전 보관

포스트 시스템

  • 포스트 작성/수정/삭제: 풍부한 콘텐츠 작성 도구
  • 상태 관리: 초안(DRAFT) → 발행(PUBLISHED) → 숨김(HIDDEN) → 삭제(DELETED)
  • 카테고리 분류: TECH, LIFE, TRAVEL, FOOD, HOBBY 카테고리
  • 실시간 통계: 조회수, 좋아요 수, 댓글 수 추적
  • 도메인 이벤트: 비즈니스 이벤트 기반 사이드 이펙트 처리
  • 검색 캐시: Elasticsearch 키워드 검색 결과를 Redis에 3분 TTL로 캐싱하여 응답 지연 최소화

댓글 시스템

  • 계층형 댓글: 대댓글 지원으로 깊이 있는 토론
  • 실시간 소통: 즉시 반영되는 댓글 시스템
  • 권한 관리: 작성자만 수정/삭제 가능
  • 상태 관리: 활성/숨김/삭제 상태 지원

상호작용 시스템

  • 좋아요: 포스트에 대한 사용자 선호도 표현
  • 통계 관리: 이벤트 기반 비동기 통계 업데이트
  • 중복 방지: 동일 사용자의 중복 좋아요 차단

아키텍처

헥사고날 아키텍처 (Ports & Adapters)

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   Web API       │────▶│   Application   │────▶│     Domain      │
│   (Adapter)     │     │  (Use Cases)    │     │  (Aggregates)   │
└─────────────────┘     └─────────────────┘     └─────────────────┘
         │                        │                        │
         ▼                        ▼                        ▼
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   Security      │     │   Persistence   │     │ Domain Events   │
│   (Adapter)     │     │   (Adapter)     │     │ (Event Handler) │
└─────────────────┘     └─────────────────┘     └─────────────────┘

계층별 책임

  • Domain Layer: 비즈니스 규칙과 도메인 로직

    • 애그리거트 루트: Member, Post, Comment, PostLike, PostStats
    • 값 객체: Email, Profile, PostContent, CommentContent
    • 도메인 이벤트: PostCreated, PostViewed, PostLiked 등
  • Application Layer: 유스케이스 조율과 트랜잭션 관리

    • Primary Port: MemberManager, PostManager, CommentManager
    • Secondary Port: MemberRepository, PostRepository, PostStatsRepository
    • 이벤트 핸들러: PostEventHandler, PostStatsEventHandler
  • Adapter Layer: 외부 시스템과의 연동

    • Web API: REST 엔드포인트
    • Security: JWT 인증/인가
    • Persistence: JPA 구현체
    • Integration: Kafka 프로듀서/컨슈머, Elasticsearch 색인기

이벤트 파이프라인

  1. 도메인 이벤트 발행: Post, Comment 등 애그리거트가 AbstractAggregateRoot를 통해 이벤트를 수집합니다.
  2. 애플리케이션 이벤트: PostEventHandler가 스프링 애플리케이션 이벤트를 받아 PostEventPublisher(포트)에 위임합니다.
  3. Kafka 전송: PostEventProducer는 트랜잭션 커밋 이후 Kafka로 메시지를 전송하며, postId를 메시지 키로 사용하고 RetryTemplate으로 재시도 정책을 적용합니다.
  4. 컨슈머 처리: PostEventConsumerDefaultErrorHandler가 적용된 리스너 컨테이너에서 메시지를 소비하고, PostEventProcessor가 최신 게시글을 재조회해 Elasticsearch 색인을 갱신합니다.
  5. Fallback 모드: see.kafka.enabled=false 일 때는 DirectPostEventPublisher가 즉시 색인 작업을 수행하여 Kafka 없이도 동일한 로직을 유지합니다.

기술 스택

Core Framework

  • Java 21: 최신 LTS 버전으로 성능과 보안 강화
  • Spring Boot 3.5.4: 최신 스프링 부트로 개발 생산성 향상
  • Spring Data JPA: 데이터 접근 계층 추상화
  • Spring Security: 인증/인가 보안 체계
  • Spring Retry: 외부 시스템 연동 시 재시도 정책 지원

Storage & Messaging

  • MySQL 8.0: 운영 환경 데이터베이스
  • H2: 개발/테스트 환경 인메모리 데이터베이스
  • Elasticsearch 8.x: 검색 인덱스 저장소
  • Apache Kafka 7.x (Confluent): 도메인 이벤트 브로커
  • Docker Compose: 컨테이너 기반 개발 환경

Testing & Quality

  • JUnit 5: 현대적인 테스트 프레임워크
  • AssertJ: 가독성 높은 테스트 어서션
  • ArchUnit: 아키텍처 규칙 자동 검증
  • 95% 테스트 커버리지: TDD 기반 높은 코드 품질
  • JaCoCo: 테스트 커버리지 측정

Development Tools

  • Lombok: 보일러플레이트 코드 자동 생성
  • Docker: 일관된 개발/운영 환경
  • GitHub Actions: CI/CD 자동화

빠른 시작

사전 요구사항

  • Java 21 이상
  • Docker & Docker Compose
  • IDE (IntelliJ IDEA 권장)

1. 프로젝트 클론

git clone https://github.com/your-repo/see.git
cd see

2. 인프라 기동 (선택)

# MySQL, Elasticsearch, Kafka를 한 번에 실행하려면
docker compose up -d mysql elasticsearch kafka

# 또는 필요한 서비스만 선택적으로 실행할 수 있습니다.

Kafka를 사용하지 않는 개발 환경이라면 위 단계를 생략하고 see.kafka.enabled=false 프로필을 활성화하면 됩니다.

3. 애플리케이션 실행

./gradlew bootRun

4. 환경 설정 팁

  • see.kafka.enabled=false: Kafka 없이 즉시 색인을 수행 (기본 테스트 프로필)
  • spring.kafka.bootstrap-servers: 로컬 Kafka 브로커 주소 (임베디드 테스트에서는 자동 주입)
  • spring.elasticsearch.uris: Elasticsearch 연결 주소 (기본값 http://localhost:9200)

5. API 테스트

# 회원 가입
curl -X POST http://localhost:8080/api/members \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "nickname": "테스터",
    "password": "password123",
    "profileAddress": "tester"
  }'

# 로그인
curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "password123"
  }'

# 포스트 작성
curl -X POST http://localhost:8080/api/posts \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {JWT_TOKEN}" \
  -d '{
    "title": "첫 번째 포스트",
    "body": "헥사고날 아키텍처에 대한 글입니다.",
    "category": "TECH"
  }'

프로젝트 구조

src/
├── main/java/dooya/see/
│   ├── domain/                 # 도메인 계층
│   │   ├── member/             # 회원 애그리거트
│   │   │   ├── Member.java
│   │   │   ├── MemberDetail.java
│   │   │   ├── Profile.java
│   │   │   └── Email.java
│   │   ├── post/               # 포스트 애그리거트  
│   │   │   ├── Post.java
│   │   │   ├── PostContent.java
│   │   │   ├── PostMetaData.java
│   │   │   ├── PostStats.java
│   │   │   └── event/          # 도메인 이벤트
│   │   ├── comment/            # 댓글 애그리거트
│   │   ├── postlike/           # 좋아요 애그리거트
│   │   └── shared/             # 공유 도메인 객체
│   ├── application/            # 애플리케이션 계층
│   │   ├── member/             
│   │   │   ├── provided/       # Primary Port
│   │   │   └── required/       # Secondary Port  
│   │   ├── post/
│   │   │   ├── PostStatsEventHandler.java
│   │   │   ├── provided/
│   │   │   └── required/
│   │   └── comment/
│   └── adapter/                # 어댑터 계층
│       ├── webapi/             # REST API
│       ├── security/           # 보안
│       ├── persistence/        # 데이터베이스
│       └── integration/        # Kafka, Elasticsearch 연동
└── test/                       # 테스트 코드
    ├── domain/                 # 단위 테스트 (순수 Java)
    ├── application/            # 통합 테스트
    └── adapter/                # API 테스트 (E2E)

테스트

테스트 전략

  • 단위 테스트: 도메인 로직을 순수 Java로 빠르게 검증
  • 통합 테스트: 포트 구현체를 모의 객체로 대체하여 애플리케이션 서비스 검증
  • 인수 테스트: 실제 어댑터를 사용하여 End-to-End 시나리오 검증
  • Kafka 통합 테스트: Embedded Kafka를 활용해 이벤트 파이프라인을 종단 간 검증

테스트 실행

# 전체 테스트 (Kafka 비활성화 프로필 기본 적용)
./gradlew test

# Kafka 파이프라인 통합 테스트만 실행 (Embedded Kafka)
./gradlew test --tests PostEventKafkaPipelineTest

# 테스트 커버리지 확인  
./gradlew jacocoTestReport
open build/jacocoHtml/index.html

# 아키텍처 규칙 검증
./gradlew test --tests "*ArchUnitTest"

# 벤치마크 데이터 적재 (필요 시 forceReload=true)
./gradlew bootRun --args='--spring.profiles.active=benchmark-data --benchmark.data.post-count=50000'

# JMH 기반 DB vs ES 검색 성능 측정
./gradlew jmh

# Gatling 부하 테스트 실행 (서버 실행 필요)
./gradlew gatlingRun -Pgatling.simulationClass=dooya.see.search.PostSearchSimulation

주요 지표

  • 테스트 커버리지: 95% (JaCoCo 측정)
  • 아키텍처 준수율: 100% (ArchUnit으로 자동 검증)
  • 빌드 시간: 평균 2분 이하
  • API 응답시간: 평균 200ms 이하

개발 원칙

1. 도메인 주도 설계 (DDD)

  • 유비쿼터스 언어: 비즈니스 용어를 코드에 직접 반영
  • 애그리거트 패턴: 트랜잭션과 일관성 경계 명확히 설정
  • 도메인 이벤트: 애그리거트 간 느슨한 결합 유지

2. 헥사고날 아키텍처

  • 의존성 역전: 모든 의존성이 도메인 중심으로 향함
  • 포트와 어댑터: 인터페이스 기반 확장 가능한 설계
  • 관심사 분리: 비즈니스 로직과 기술적 세부사항 완전 분리

3. 테스트 주도 개발 (TDD)

  • Red-Green-Refactor: 실패하는 테스트부터 시작
  • Given-When-Then: 모든 테스트를 일관된 구조로 작성
  • 높은 커버리지: 95% 테스트 커버리지로 안전한 리팩토링 보장

도메인 이벤트 시스템

이벤트 처리 방식

// 이벤트 발행 (도메인 계층)
public void publish() {
    this.status = PostStatus.PUBLISHED;
    this.addDomainEvent(new PostPublished(this.getId(), this.memberId));
}

// 이벤트 처리 (애플리케이션 계층)
@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handlePostViewed(PostViewed event) {
    try {
        postStatsManager.incrementViewCount(event.postId());
    } catch (Exception e) {
        // 사이드 이펙트 실패가 메인 로직에 영향 없도록 격리
    }
}

이벤트 종류

  • PostCreated: 포스트 생성 시 통계 초기화
  • PostViewed: 조회 시 조회수 증가
  • PostLiked/PostUnliked: 좋아요/취소 시 좋아요 수 증감
  • CommentCreated/CommentDeleted: 댓글 생성/삭제 시 댓글 수 증감

보안

  • JWT 토큰: Stateless 인증 방식
  • BCrypt 암호화: 강력한 비밀번호 해싱
  • CORS 설정: 안전한 크로스 도메인 요청
  • 입력 검증: 도메인 객체에서 비즈니스 규칙 검증
  • 권한 관리: 리소스 소유자만 수정/삭제 가능

CI/CD

GitHub Actions

  • 자동화된 빌드: 모든 푸시/PR에서 자동 빌드
  • 품질 게이트:
    • 모든 테스트 통과
    • 95% 이상 테스트 커버리지
    • ArchUnit 아키텍처 규칙 준수
  • Docker 지원: 컨테이너화된 배포

개발 워크플로우

# 1단계: TDD로 비즈니스 로직 개발
# 2단계: ArchUnit으로 아키텍처 검증  
# 3단계: 통합 테스트로 전체 플로우 검증
# 4단계: 코드 리뷰 후 머지

성능 최적화

애그리거트 분리

  • PostStats 설계: Post 애그리거트 내의 별도 엔티티로 통계 전용 처리
  • 이벤트 기반 업데이트: 통계는 비동기로 최종 일관성 보장
  • 트랜잭션 분리: 통계 실패가 본 작업에 영향 없음

데이터베이스 최적화

  • 적절한 인덱싱: 조회 성능 최적화
  • 연관관계 최적화: N+1 문제 방지
  • 커넥션 풀: HikariCP로 커넥션 관리

확장 계획

Phase 1 (현재)

  • ✅ 기본 CRUD 기능
  • ✅ 헥사고날 아키텍처 적용
  • ✅ 도메인 이벤트 시스템
  • ✅ 95% 테스트 커버리지

Phase 2 (예정)

  • 📋 태그 시스템
  • 📋 팔로우 기능
  • 📋 알림 시스템
  • 📋 검색 기능

Phase 3 (장기)

  • 📋 CQRS 패턴 도입
  • 📋 마이크로서비스 분리
  • 📋 실시간 기능 (WebSocket)

기여 가이드라인

  1. 아키텍처 원칙 준수: ArchUnit 테스트 통과 필수
  2. 테스트 작성: 모든 기능에 대한 테스트 코드 작성
  3. 커버리지 유지: 95% 이상 테스트 커버리지 유지
  4. 코드 리뷰: 모든 변경사항은 코드 리뷰 후 머지
  5. 커밋 컨벤션: Conventional Commits 규칙 준수

See 프로젝트는 현대적인 백엔드 개발 패러다임을 실무에 적용한 레퍼런스 프로젝트입니다. 헥사고날 아키텍처, DDD, TDD의 조합으로 확장 가능하고 유지보수하기 쉬운 고품질 소프트웨어를 추구합니다.

About

헥사고날 아키텍처와 TDD를 적용한 Spring Boot 기반 온라인 커뮤니티 플랫폼

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published