@startuml !theme mono title Analytics Service ERD (Entity Relationship Diagram) ' ============================================================ ' Entity Definitions ' ============================================================ entity "event_stats" as event_stats { * id : BIGSERIAL <> -- * event_id : VARCHAR(36) <> * event_title : VARCHAR(255) * user_id : VARCHAR(36) * total_participants : INTEGER * total_views : INTEGER * estimated_roi : DECIMAL(10,2) * target_roi : DECIMAL(10,2) * sales_growth_rate : DECIMAL(10,2) * total_investment : DECIMAL(15,2) * expected_revenue : DECIMAL(15,2) * status : VARCHAR(20) * created_at : TIMESTAMP * updated_at : TIMESTAMP } entity "channel_stats" as channel_stats { * id : BIGSERIAL <> -- * event_id : VARCHAR(36) <> * channel_name : VARCHAR(50) * channel_type : VARCHAR(20) * impressions : INTEGER * views : INTEGER * clicks : INTEGER * participants : INTEGER * conversions : INTEGER * distribution_cost : DECIMAL(15,2) * likes : INTEGER * comments : INTEGER * shares : INTEGER * total_calls : INTEGER * completed_calls : INTEGER * average_duration : INTEGER * created_at : TIMESTAMP * updated_at : TIMESTAMP } entity "timeline_data" as timeline_data { * id : BIGSERIAL <> -- * event_id : VARCHAR(36) <> * timestamp : TIMESTAMP * participants : INTEGER * views : INTEGER * engagement : INTEGER * conversions : INTEGER * cumulative_participants : INTEGER * created_at : TIMESTAMP * updated_at : TIMESTAMP } ' ============================================================ ' Relationships ' ============================================================ event_stats ||--o{ channel_stats : "1:N (event_id)" event_stats ||--o{ timeline_data : "1:N (event_id)" ' ============================================================ ' Notes ' ============================================================ note top of event_stats **이벤트별 통계 집계** - Kafka EventCreatedEvent로 생성 - ParticipantRegisteredEvent로 증분 업데이트 - Redis 캐싱 (1시간 TTL) - UK: event_id (이벤트당 1개 레코드) - INDEX: user_id, status, created_at end note note top of channel_stats **채널별 성과 데이터** - Kafka DistributionCompletedEvent로 생성 - 외부 API 연동 (Circuit Breaker) - UK: (event_id, channel_name) - INDEX: event_id, channel_type, participants - 채널 타입: TV, SNS, VOICE end note note top of timeline_data **시계열 분석 데이터** - ParticipantRegisteredEvent 발생 시 업데이트 - 시간별 참여 추이 기록 - INDEX: (event_id, timestamp) - 시계열 조회 최적화 - BRIN INDEX: timestamp - 대용량 시계열 데이터 - 월별 파티셔닝 권장 end note note bottom of event_stats **데이터독립성 원칙** - Analytics Service 독립 스키마 - event_id: Event Service의 이벤트 참조 (캐시) - user_id: User Service의 사용자 참조 (캐시) - FK 없음 (서비스 간 DB 조인 금지) end note note as redis_cache **Redis 캐시 구조** -- analytics:dashboard:{eventId} analytics:channel:{eventId}:{channelName} analytics:roi:{eventId} analytics:timeline:{eventId}:{granularity} analytics:user:{userId} analytics:processed:{messageId} (Set, 24h TTL) -- TTL: 3600초 (1시간) 패턴: Cache-Aside end note ' ============================================================ ' Legend ' ============================================================ legend bottom right **범례** -- PK: Primary Key FK: Foreign Key (논리적 관계만, 물리 FK 없음) UK: Unique Key INDEX: B-Tree 인덱스 BRIN: Block Range Index (시계열 최적화) -- **제약 조건** - total_participants >= 0 - total_investment >= 0 - estimated_roi >= 0 - status IN ('ACTIVE', 'ENDED', 'ARCHIVED') - channel_type IN ('TV', 'SNS', 'VOICE') - completed_calls <= total_calls end legend @enduml