mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 20:06:23 +00:00
✨ 주요 기능 - Azure 기반 물리아키텍처 설계 (개발환경/운영환경) - 7개 마이크로서비스 물리 구조 설계 - 네트워크 아키텍처 다이어그램 작성 (Mermaid) - 환경별 비교 분석 및 마스터 인덱스 문서 📁 생성 파일 - design/backend/physical/physical-architecture.md (마스터) - design/backend/physical/physical-architecture-dev.md (개발환경) - design/backend/physical/physical-architecture-prod.md (운영환경) - design/backend/physical/*.mmd (4개 Mermaid 다이어그램) 🎯 핵심 성과 - 비용 최적화: 개발환경 월 $143, 운영환경 월 $2,860 - 확장성: 개발환경 100명 → 운영환경 10,000명 (100배) - 가용성: 개발환경 95% → 운영환경 99.9% - 보안: 다층 보안 아키텍처 (L1~L4) 🛠️ 기술 스택 - Azure Kubernetes Service (AKS) - Azure Database for PostgreSQL Flexible - Azure Cache for Redis Premium - Azure Service Bus Premium - Application Gateway + WAF 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
319 lines
11 KiB
Plaintext
319 lines
11 KiB
Plaintext
@startuml
|
|
!theme mono
|
|
|
|
title Distribution Service 클래스 다이어그램 (상세)
|
|
|
|
package "com.kt.distribution" {
|
|
|
|
package "controller" {
|
|
class DistributionController {
|
|
- distributionService: DistributionService
|
|
+ distribute(request: DistributionRequest): ResponseEntity<DistributionResponse>
|
|
+ getDistributionStatus(eventId: String): ResponseEntity<DistributionStatusResponse>
|
|
}
|
|
}
|
|
|
|
package "service" {
|
|
class DistributionService {
|
|
- channelAdapters: List<ChannelAdapter>
|
|
- kafkaEventPublisher: Optional<KafkaEventPublisher>
|
|
- statusRepository: DistributionStatusRepository
|
|
- executorService: ExecutorService
|
|
+ distribute(request: DistributionRequest): DistributionResponse
|
|
+ getDistributionStatus(eventId: String): DistributionStatusResponse
|
|
- saveInProgressStatus(eventId: String, channels: List<ChannelType>, startedAt: LocalDateTime): void
|
|
- saveCompletedStatus(eventId: String, results: List<ChannelDistributionResult>, startedAt: LocalDateTime, completedAt: LocalDateTime, successCount: long, failureCount: long): void
|
|
- convertToChannelStatus(result: ChannelDistributionResult, eventId: String, completedAt: LocalDateTime): ChannelStatus
|
|
- publishDistributionCompletedEvent(eventId: String, results: List<ChannelDistributionResult>): void
|
|
}
|
|
|
|
class KafkaEventPublisher {
|
|
- kafkaTemplate: KafkaTemplate<String, Object>
|
|
- distributionCompletedTopic: String
|
|
+ publishDistributionCompleted(event: DistributionCompletedEvent): void
|
|
}
|
|
}
|
|
|
|
package "adapter" {
|
|
interface ChannelAdapter {
|
|
+ getChannelType(): ChannelType
|
|
+ distribute(request: DistributionRequest): ChannelDistributionResult
|
|
}
|
|
|
|
abstract class AbstractChannelAdapter implements ChannelAdapter {
|
|
+ distribute(request: DistributionRequest): ChannelDistributionResult
|
|
# executeDistribution(request: DistributionRequest): ChannelDistributionResult
|
|
# fallback(request: DistributionRequest, throwable: Throwable): ChannelDistributionResult
|
|
}
|
|
|
|
class UriDongNeTvAdapter extends AbstractChannelAdapter {
|
|
+ getChannelType(): ChannelType
|
|
# executeDistribution(request: DistributionRequest): ChannelDistributionResult
|
|
}
|
|
|
|
class RingoBizAdapter extends AbstractChannelAdapter {
|
|
+ getChannelType(): ChannelType
|
|
# executeDistribution(request: DistributionRequest): ChannelDistributionResult
|
|
}
|
|
|
|
class GiniTvAdapter extends AbstractChannelAdapter {
|
|
+ getChannelType(): ChannelType
|
|
# executeDistribution(request: DistributionRequest): ChannelDistributionResult
|
|
}
|
|
|
|
class InstagramAdapter extends AbstractChannelAdapter {
|
|
+ getChannelType(): ChannelType
|
|
# executeDistribution(request: DistributionRequest): ChannelDistributionResult
|
|
}
|
|
|
|
class NaverAdapter extends AbstractChannelAdapter {
|
|
+ getChannelType(): ChannelType
|
|
# executeDistribution(request: DistributionRequest): ChannelDistributionResult
|
|
}
|
|
|
|
class KakaoAdapter extends AbstractChannelAdapter {
|
|
+ getChannelType(): ChannelType
|
|
# executeDistribution(request: DistributionRequest): ChannelDistributionResult
|
|
}
|
|
}
|
|
|
|
package "dto" {
|
|
class DistributionRequest {
|
|
- eventId: String
|
|
- title: String
|
|
- description: String
|
|
- imageUrl: String
|
|
- channels: List<ChannelType>
|
|
- channelSettings: Map<String, Map<String, Object>>
|
|
}
|
|
|
|
class DistributionResponse {
|
|
- eventId: String
|
|
- success: boolean
|
|
- channelResults: List<ChannelDistributionResult>
|
|
- successCount: int
|
|
- failureCount: int
|
|
- completedAt: LocalDateTime
|
|
- totalExecutionTimeMs: long
|
|
- message: String
|
|
}
|
|
|
|
class ChannelDistributionResult {
|
|
- channel: ChannelType
|
|
- success: boolean
|
|
- distributionId: String
|
|
- estimatedReach: Integer
|
|
- errorMessage: String
|
|
- executionTimeMs: long
|
|
}
|
|
|
|
class DistributionStatusResponse {
|
|
- eventId: String
|
|
- overallStatus: String
|
|
- startedAt: LocalDateTime
|
|
- completedAt: LocalDateTime
|
|
- channels: List<ChannelStatus>
|
|
}
|
|
|
|
class ChannelStatus {
|
|
- channel: ChannelType
|
|
- status: String
|
|
- progress: Integer
|
|
- distributionId: String
|
|
- estimatedViews: Integer
|
|
- updateTimestamp: LocalDateTime
|
|
- eventId: String
|
|
- impressionSchedule: List<String>
|
|
- postUrl: String
|
|
- postId: String
|
|
- messageId: String
|
|
- completedAt: LocalDateTime
|
|
- errorMessage: String
|
|
- retries: Integer
|
|
- lastRetryAt: LocalDateTime
|
|
}
|
|
|
|
enum ChannelType {
|
|
URIDONGNETV
|
|
RINGOBIZ
|
|
GINITV
|
|
INSTAGRAM
|
|
NAVER
|
|
KAKAO
|
|
- displayName: String
|
|
- category: String
|
|
+ getDisplayName(): String
|
|
+ getCategory(): String
|
|
}
|
|
}
|
|
|
|
package "repository" {
|
|
class DistributionStatusRepository {
|
|
- jpaRepository: DistributionStatusJpaRepository
|
|
- mapper: DistributionStatusMapper
|
|
+ save(eventId: String, status: DistributionStatusResponse): void
|
|
+ findByEventId(eventId: String): Optional<DistributionStatusResponse>
|
|
+ delete(eventId: String): void
|
|
+ deleteAll(): void
|
|
}
|
|
|
|
interface DistributionStatusJpaRepository {
|
|
+ findByEventIdWithChannels(eventId: String): Optional<DistributionStatus>
|
|
+ deleteByEventId(eventId: String): void
|
|
}
|
|
}
|
|
|
|
package "entity" {
|
|
class DistributionStatus {
|
|
- id: Long
|
|
- eventId: String
|
|
- overallStatus: String
|
|
- startedAt: LocalDateTime
|
|
- completedAt: LocalDateTime
|
|
- channels: List<ChannelStatusEntity>
|
|
- createdAt: LocalDateTime
|
|
- updatedAt: LocalDateTime
|
|
+ addChannelStatus(channelStatus: ChannelStatusEntity): void
|
|
+ removeChannelStatus(channelStatus: ChannelStatusEntity): void
|
|
}
|
|
|
|
class ChannelStatusEntity {
|
|
- id: Long
|
|
- distributionStatus: DistributionStatus
|
|
- channel: ChannelType
|
|
- status: String
|
|
- progress: Integer
|
|
- distributionId: String
|
|
- estimatedViews: Integer
|
|
- updateTimestamp: LocalDateTime
|
|
- eventId: String
|
|
- impressionSchedule: String
|
|
- postUrl: String
|
|
- postId: String
|
|
- messageId: String
|
|
- completedAt: LocalDateTime
|
|
- errorMessage: String
|
|
- retries: Integer
|
|
- lastRetryAt: LocalDateTime
|
|
- createdAt: LocalDateTime
|
|
- updatedAt: LocalDateTime
|
|
}
|
|
}
|
|
|
|
package "mapper" {
|
|
class DistributionStatusMapper {
|
|
+ toEntity(dto: DistributionStatusResponse): DistributionStatus
|
|
+ toDto(entity: DistributionStatus): DistributionStatusResponse
|
|
+ toChannelStatusEntity(dto: ChannelStatus): ChannelStatusEntity
|
|
+ toChannelStatusDto(entity: ChannelStatusEntity): ChannelStatus
|
|
}
|
|
}
|
|
|
|
package "event" {
|
|
class DistributionCompletedEvent {
|
|
- eventId: String
|
|
- distributedChannels: List<DistributedChannelInfo>
|
|
- completedAt: LocalDateTime
|
|
}
|
|
|
|
class DistributedChannelInfo {
|
|
- channel: String
|
|
- channelType: String
|
|
- status: String
|
|
- expectedViews: Integer
|
|
}
|
|
}
|
|
|
|
package "config" {
|
|
class KafkaConfig {
|
|
+ kafkaTemplate(): KafkaTemplate<String, Object>
|
|
+ producerFactory(): ProducerFactory<String, Object>
|
|
}
|
|
|
|
class OpenApiConfig {
|
|
+ openAPI(): OpenAPI
|
|
}
|
|
|
|
class WebConfig {
|
|
+ corsConfigurer(): WebMvcConfigurer
|
|
}
|
|
}
|
|
}
|
|
|
|
' 관계 정의
|
|
DistributionController --> DistributionService : uses
|
|
DistributionService --> ChannelAdapter : uses
|
|
DistributionService --> KafkaEventPublisher : uses
|
|
DistributionService --> DistributionStatusRepository : uses
|
|
DistributionService ..> DistributionRequest : uses
|
|
DistributionService ..> DistributionResponse : creates
|
|
DistributionService ..> DistributionStatusResponse : uses
|
|
DistributionService ..> ChannelDistributionResult : uses
|
|
|
|
AbstractChannelAdapter ..|> ChannelAdapter : implements
|
|
UriDongNeTvAdapter --|> AbstractChannelAdapter : extends
|
|
RingoBizAdapter --|> AbstractChannelAdapter : extends
|
|
GiniTvAdapter --|> AbstractChannelAdapter : extends
|
|
InstagramAdapter --|> AbstractChannelAdapter : extends
|
|
NaverAdapter --|> AbstractChannelAdapter : extends
|
|
KakaoAdapter --|> AbstractChannelAdapter : extends
|
|
|
|
ChannelAdapter ..> DistributionRequest : uses
|
|
ChannelAdapter ..> ChannelDistributionResult : creates
|
|
|
|
KafkaEventPublisher ..> DistributionCompletedEvent : publishes
|
|
DistributionCompletedEvent --> DistributedChannelInfo : contains
|
|
|
|
DistributionStatusRepository --> DistributionStatusJpaRepository : uses
|
|
DistributionStatusRepository --> DistributionStatusMapper : uses
|
|
DistributionStatusRepository ..> DistributionStatusResponse : uses
|
|
DistributionStatusRepository ..> DistributionStatus : uses
|
|
|
|
DistributionStatusJpaRepository ..> DistributionStatus : manages
|
|
DistributionStatusMapper ..> DistributionStatus : maps
|
|
DistributionStatusMapper ..> DistributionStatusResponse : maps
|
|
DistributionStatusMapper ..> ChannelStatus : maps
|
|
DistributionStatusMapper ..> ChannelStatusEntity : maps
|
|
|
|
DistributionStatus "1" *-- "many" ChannelStatusEntity : contains
|
|
ChannelStatusEntity --> DistributionStatus : belongs to
|
|
|
|
DistributionRequest --> ChannelType : uses
|
|
DistributionResponse --> ChannelDistributionResult : contains
|
|
ChannelDistributionResult --> ChannelType : uses
|
|
DistributionStatusResponse --> ChannelStatus : contains
|
|
ChannelStatus --> ChannelType : uses
|
|
ChannelStatusEntity --> ChannelType : uses
|
|
|
|
note top of DistributionService
|
|
핵심 비즈니스 로직
|
|
- 다중 채널 병렬 배포 실행
|
|
- ExecutorService로 비동기 처리
|
|
- Circuit Breaker 패턴 적용
|
|
- Kafka 이벤트 발행
|
|
end note
|
|
|
|
note top of AbstractChannelAdapter
|
|
Resilience4j 적용
|
|
- @CircuitBreaker
|
|
- @Retry (지수 백오프)
|
|
- @Bulkhead
|
|
- Fallback 처리
|
|
end note
|
|
|
|
note top of DistributionStatusRepository
|
|
배포 상태 영구 저장
|
|
- PostgreSQL 데이터베이스 사용
|
|
- JPA Repository 패턴
|
|
- Entity-DTO 매핑
|
|
end note
|
|
|
|
note top of ChannelType
|
|
배포 채널 종류
|
|
- TV: 우리동네TV, 지니TV
|
|
- CALL: 링고비즈
|
|
- SNS: Instagram, Naver, Kakao
|
|
end note
|
|
|
|
@enduml
|