백엔드 아키텍처

← 아키텍처 개요


요약

항목 내용
언어 Java 25 (Virtual Threads, JEP 491)
프레임워크 Spring Boot 3.5.6 (Spring MVC)
아키텍처 Hexagonal (Ports & Adapters)
DB PostgreSQL 16 + JPA + QueryDSL 5.1.0
캐시 Redis 7 (RedisCacheManager)
실시간 STOMP over WebSocket + Redis Pub/Sub
파일 MinIO (S3 호환)
ID Snowflake ID (애플리케이션 생성)
암호화 AES-256 (메시지 내용)
마이그레이션 Flyway (SQL)

헥사고날 아키텍처

graph TD
    subgraph "Inbound Adapters"
        REST[REST 컨트롤러<br/>8개]
        WS[WebSocket 컨트롤러<br/>STOMP]
    end

    subgraph "Application"
        PORT_IN[Inbound Ports]
        UC[서비스<br/>Use Cases]
        PORT_OUT[Outbound Ports]
    end

    subgraph "Domain"
        ENT[엔티티 · 비즈니스 로직]
    end

    subgraph "Outbound Adapters"
        JPA[JPA → PostgreSQL]
        REDIS[Redis<br/>캐시 · Pub/Sub]
        S3[MinIO → 파일]
        FCM[FCM → 푸시]
    end

    REST --> PORT_IN
    WS --> PORT_IN
    PORT_IN --> UC
    UC --> ENT
    UC --> PORT_OUT
    PORT_OUT --> JPA
    PORT_OUT --> REDIS
    PORT_OUT --> S3
    PORT_OUT --> FCM

의존성 방향: Adapter → Application → Domain (도메인은 외부 의존 없음)


패키지 구조

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
com.cotalk/
├── adapter/inbound/
│   ├── rest/              # 8개 REST 컨트롤러 + DTO (record)
│   └── websocket/         # STOMP WebSocket 컨트롤러
├── adapter/outbound/
│   ├── persistence/       # JPA 리포지토리
│   ├── redis/             # Redis 캐시, Pub/Sub
│   ├── storage/           # MinIO 파일
│   └── fcm/               # Firebase 푸시
├── application/
│   ├── port/inbound/      # Use Case 인터페이스
│   ├── port/outbound/     # Repository 인터페이스
│   ├── service/           # Use Case 구현체
│   └── dto/               # Request/Response
├── domain/
│   ├── entity/            # JPA 엔티티
│   ├── enums/             # 상태 Enum
│   └── exception/         # 도메인 예외
└── config/                # Security, WebSocket, Cache, Redis, RateLimit

핵심 설계 패턴

패턴 설명
AES-256 투명 암호화 JPA @Converter로 메시지 저장 시 자동 암호화/조회 시 복호화
Snowflake ID 3개 인스턴스에서 충돌 없는 분산 ID 생성 (BIGINT)
CQRS-lite 명령/조회 Use Case 인터페이스 분리
스키마 버전관리 WebSocket 메시지에 schemaVersion + eventId 포함

실시간 메시징

멀티 인스턴스 메시지 흐름

sequenceDiagram
    participant C as 클라이언트 A
    participant I1 as app-1
    participant R as Redis Pub/Sub
    participant I2 as app-2
    participant I3 as app-3

    C->>I1: STOMP SEND
    I1->>I1: DB 저장 (AES-256)
    I1->>R: PUBLISH chat:room:{id}
    R->>I1: → 로컬 WebSocket 전달
    R->>I2: → 로컬 WebSocket 전달
    R->>I3: → 로컬 WebSocket 전달

Redis 채널 구조

채널 용도
chat:room:{roomId} 채팅 메시지
chat:room:{roomId}:reaction 리액션 이벤트
chat:room:{roomId}:event READ, TYPING, DELETE, UPDATE 등
user:event:{userId} 채팅 목록 업데이트

이벤트 타입

MESSAGE · REACTION_ADDED · REACTION_REMOVED · TYPING · STOP_TYPING · READ · MESSAGE_DELETED · MESSAGE_UPDATED · LINK_PREVIEW_UPDATED · USER_LEFT · USER_JOINED


보안

항목 구현
인증 JWT (HMAC-SHA256), Access + Refresh Token
비밀번호 BCrypt
메시지 암호화 AES-256 at rest
Rate Limiting Bucket4j + Redis (인스턴스 간 공유)
Actuator 민감 엔드포인트 제거

Rate Limit

엔드포인트 제한
로그인 5회/분
회원가입 3회/분
파일 업로드 10회/분 + 50회/시간

캐시 (Redis)

캐시 TTL
USER 1시간
CHAT_ROOM 30분
STATISTICS 5분

관측성

도구 용도
Micrometer + Prometheus 커스텀 메트릭 (메시지, 로그인, WebSocket, Redis)
Micrometer Tracing (Brave) 분산 추적 → Zipkin
Logstash Logback Encoder 구조화 JSON 로깅 → Loki

프론트엔드 아키텍처