# Distribution Service 데이터베이스 설계서 ## 📋 데이터설계 요약 ### 설계 개요 - **서비스명**: Distribution Service - **아키텍처 패턴**: Layered Architecture - **데이터베이스**: PostgreSQL (배포 상태 영구 저장), Redis (실시간 모니터링) - **설계 일시**: 2025-10-29 - **설계자**: Backend Developer (최수연 "아키텍처") ### 데이터 특성 - **배포 상태 관리**: 이벤트별 다중 채널 배포 상태 추적 - **채널 독립성**: 6개 채널(TV, CALL, SNS)별 독립적 상태 관리 - **실시간 모니터링**: Redis 캐시를 통한 배포 진행 상태 실시간 조회 - **성과 추적**: 채널별 도달률(estimatedViews), 완료 시간, 재시도 횟수 추적 - **에러 관리**: 채널별 에러 메시지, 재시도 정보 저장 ### 주요 테이블 1. **distribution_status**: 배포 전체 상태 관리 (이벤트 ID, 전체 상태, 시작/완료 시간) 2. **channel_status**: 채널별 세부 배포 상태 (채널 타입, 진행률, 배포 ID, 도달률, 에러 정보) ### 캐시 설계 - **event:{eventId}:distribution**: 배포 상태 실시간 조회 (TTL: 1시간) - **distribution:channel:{eventId}:{channel}**: 채널별 상태 캐시 (TTL: 30분) --- ## 1. 데이터베이스 스키마 설계 ### 1.1 PostgreSQL 테이블 설계 #### 1.1.1 distribution_status (배포 상태 테이블) **테이블 목적**: 이벤트별 배포 전체 상태 관리 | 컬럼명 | 타입 | NULL | 기본값 | 설명 | |--------|------|------|--------|------| | id | BIGSERIAL | NO | - | 배포 상태 ID (PK) | | event_id | VARCHAR(36) | NO | - | 이벤트 ID (UUID) | | overall_status | VARCHAR(20) | NO | - | 전체 배포 상태 (IN_PROGRESS, COMPLETED, FAILED, PARTIAL_SUCCESS) | | started_at | TIMESTAMP | NO | - | 배포 시작 시간 | | completed_at | TIMESTAMP | YES | NULL | 배포 완료 시간 | | created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 생성 시간 | | updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 수정 시간 | **제약 조건**: - PRIMARY KEY: id - UNIQUE KEY: event_id (이벤트당 하나의 배포 상태만 존재) - INDEX: event_id (조회 성능 최적화) - CHECK: overall_status IN ('IN_PROGRESS', 'COMPLETED', 'FAILED', 'PARTIAL_SUCCESS') #### 1.1.2 channel_status (채널 배포 상태 테이블) **테이블 목적**: 채널별 세부 배포 상태 및 성과 추적 | 컬럼명 | 타입 | NULL | 기본값 | 설명 | |--------|------|------|--------|------| | id | BIGSERIAL | NO | - | 채널 상태 ID (PK) | | distribution_status_id | BIGINT | NO | - | 배포 상태 ID (FK) | | channel | VARCHAR(20) | NO | - | 채널 타입 (URIDONGNETV, RINGOBIZ, GINITV, INSTAGRAM, NAVER, KAKAO) | | status | VARCHAR(20) | NO | - | 채널 배포 상태 (PENDING, IN_PROGRESS, SUCCESS, FAILED) | | progress | INTEGER | YES | 0 | 진행률 (0-100) | | distribution_id | VARCHAR(100) | YES | NULL | 채널별 배포 ID (외부 시스템 ID) | | estimated_views | INTEGER | YES | 0 | 예상 도달률 (조회수) | | update_timestamp | TIMESTAMP | NO | CURRENT_TIMESTAMP | 상태 업데이트 시간 | | event_id | VARCHAR(36) | NO | - | 이벤트 ID (조회 최적화용) | | impression_schedule | TEXT | YES | NULL | 노출 일정 (JSON 배열) | | post_url | VARCHAR(500) | YES | NULL | 게시물 URL | | post_id | VARCHAR(100) | YES | NULL | 게시물 ID | | message_id | VARCHAR(100) | YES | NULL | 메시지 ID (카카오톡) | | completed_at | TIMESTAMP | YES | NULL | 채널 배포 완료 시간 | | error_message | TEXT | YES | NULL | 에러 메시지 | | retries | INTEGER | YES | 0 | 재시도 횟수 | | last_retry_at | TIMESTAMP | YES | NULL | 마지막 재시도 시간 | | created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 생성 시간 | | updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 수정 시간 | **제약 조건**: - PRIMARY KEY: id - FOREIGN KEY: distribution_status_id REFERENCES distribution_status(id) ON DELETE CASCADE - UNIQUE KEY: (distribution_status_id, channel) - 배포당 채널별 하나의 상태만 존재 - INDEX: event_id (이벤트별 조회 최적화) - INDEX: (event_id, channel) (채널별 조회 최적화) - INDEX: status (상태별 조회 최적화) - CHECK: channel IN ('URIDONGNETV', 'RINGOBIZ', 'GINITV', 'INSTAGRAM', 'NAVER', 'KAKAO') - CHECK: status IN ('PENDING', 'IN_PROGRESS', 'SUCCESS', 'FAILED') - CHECK: progress BETWEEN 0 AND 100 --- ### 1.2 Redis 캐시 설계 #### 1.2.1 배포 상태 캐시 **키 패턴**: `event:{eventId}:distribution` **데이터 구조**: Hash ```json { "eventId": "uuid", "overallStatus": "IN_PROGRESS", "startedAt": "2025-10-29T10:00:00", "completedAt": null, "successCount": 3, "failureCount": 1, "totalChannels": 6 } ``` **TTL**: 1시간 (3600초) **사용 목적**: - 배포 상태 실시간 조회 성능 최적화 - DB 부하 감소 (조회 빈도가 높은 데이터) - 배포 진행 중 빠른 상태 업데이트 #### 1.2.2 채널별 상태 캐시 **키 패턴**: `distribution:channel:{eventId}:{channel}` **데이터 구조**: Hash ```json { "channel": "INSTAGRAM", "status": "IN_PROGRESS", "progress": 75, "distributionId": "ig_post_12345", "estimatedViews": 5000, "updateTimestamp": "2025-10-29T10:30:00", "postUrl": "https://instagram.com/p/abc123", "errorMessage": null } ``` **TTL**: 30분 (1800초) **사용 목적**: - 채널별 배포 상태 실시간 모니터링 - 진행률 추적 및 업데이트 - 외부 API 호출 결과 임시 저장 --- ## 2. Entity-Table 매핑 ### 2.1 DistributionStatus Entity → distribution_status Table | Entity 필드 | 테이블 컬럼 | 매핑 | |-------------|-------------|------| | id | id | 1:1 | | eventId | event_id | 1:1 | | overallStatus | overall_status | 1:1 | | startedAt | started_at | 1:1 | | completedAt | completed_at | 1:1 | | channels | (관계) | 1:N → channel_status | | createdAt | created_at | 1:1 (BaseTimeEntity) | | updatedAt | updated_at | 1:1 (BaseTimeEntity) | ### 2.2 ChannelStatusEntity Entity → channel_status Table | Entity 필드 | 테이블 컬럼 | 매핑 | |-------------|-------------|------| | id | id | 1:1 | | distributionStatus | distribution_status_id | N:1 (FK) | | channel | channel | 1:1 (Enum) | | status | status | 1:1 | | progress | progress | 1:1 | | distributionId | distribution_id | 1:1 | | estimatedViews | estimated_views | 1:1 | | updateTimestamp | update_timestamp | 1:1 | | eventId | event_id | 1:1 | | impressionSchedule | impression_schedule | 1:1 (JSON String) | | postUrl | post_url | 1:1 | | postId | post_id | 1:1 | | messageId | message_id | 1:1 | | completedAt | completed_at | 1:1 | | errorMessage | error_message | 1:1 | | retries | retries | 1:1 | | lastRetryAt | last_retry_at | 1:1 | | createdAt | created_at | 1:1 (BaseTimeEntity) | | updatedAt | updated_at | 1:1 (BaseTimeEntity) | --- ## 3. 데이터 관계 ### 3.1 테이블 간 관계 ``` distribution_status (1) ----< (N) channel_status - 하나의 배포 상태는 여러 채널 상태를 가짐 - CASCADE DELETE: 배포 상태 삭제 시 채널 상태도 함께 삭제 ``` ### 3.2 인덱스 전략 **distribution_status 테이블**: - PRIMARY KEY: id (클러스터 인덱스) - UNIQUE INDEX: event_id (이벤트별 배포 상태 유일성 보장) **channel_status 테이블**: - PRIMARY KEY: id (클러스터 인덱스) - UNIQUE INDEX: (distribution_status_id, channel) (배포당 채널별 유일성) - INDEX: event_id (이벤트별 채널 상태 조회 최적화) - INDEX: (event_id, channel) (복합 조회 최적화) - INDEX: status (상태별 필터링 최적화) --- ## 4. 데이터 독립성 설계 ### 4.1 서비스 간 데이터 분리 **Distribution Service 데이터 소유권**: - 배포 상태 및 채널별 성과 데이터 완전 소유 - 타 서비스의 데이터를 직접 조회하지 않음 **타 서비스 데이터 참조**: - **Event ID**: Event Service에서 생성한 ID를 참조 (FK 없음) - **User ID**: 직접 저장하지 않음 (인증 정보로만 사용) - **참조 방식**: Redis 캐시 또는 Kafka 이벤트로만 참조 ### 4.2 데이터 동기화 전략 **Kafka 이벤트 발행**: ```java // 배포 완료 시 이벤트 발행 Topic: distribution-completed Event: { "eventId": "uuid", "distributedChannels": [ { "channel": "INSTAGRAM", "status": "SUCCESS", "expectedViews": 5000 } ], "completedAt": "2025-10-29T11:00:00" } ``` **Analytics Service 연동**: - Distribution Service → Kafka → Analytics Service - 채널별 성과 데이터 비동기 전달 - 장애 격리 보장 (Circuit Breaker) --- ## 5. 쿼리 성능 최적화 ### 5.1 조회 쿼리 최적화 **이벤트별 배포 상태 조회**: ```sql -- 인덱스 활용: event_id SELECT ds.*, cs.* FROM distribution_status ds LEFT JOIN channel_status cs ON ds.id = cs.distribution_status_id WHERE ds.event_id = ?; ``` **채널별 배포 현황 조회**: ```sql -- 인덱스 활용: (event_id, channel) SELECT * FROM channel_status WHERE event_id = ? AND channel = ?; ``` **진행 중인 배포 목록 조회**: ```sql -- 인덱스 활용: overall_status SELECT * FROM distribution_status WHERE overall_status = 'IN_PROGRESS' ORDER BY started_at DESC; ``` ### 5.2 캐시 전략 **조회 우선순위**: 1. Redis 캐시 조회 시도 2. 캐시 미스 시 PostgreSQL 조회 3. 조회 결과를 Redis에 캐싱 **캐시 무효화**: - 배포 상태 업데이트 시 캐시 갱신 - 배포 완료 시 캐시 TTL 연장 (1시간 → 24시간) - 채널 상태 변경 시 해당 채널 캐시 갱신 --- ## 6. 데이터 보안 및 제약 ### 6.1 데이터 무결성 **NOT NULL 제약**: - 필수 정보: event_id, channel, status, overall_status - 시간 정보: started_at, update_timestamp **CHECK 제약**: - overall_status: 4가지 상태만 허용 - channel: 6개 채널 타입만 허용 - status: 4가지 배포 상태만 허용 - progress: 0-100 범위 제한 **UNIQUE 제약**: - event_id: 이벤트당 하나의 배포 상태 - (distribution_status_id, channel): 배포당 채널별 하나의 상태 ### 6.2 CASCADE 정책 **ON DELETE CASCADE**: - distribution_status 삭제 시 channel_status 자동 삭제 - 데이터 일관성 보장 --- ## 7. 마이그레이션 전략 ### 7.1 초기 데이터 마이그레이션 - 초기 배포 시 기본 데이터 없음 (운영 데이터만 존재) - 채널 타입 Enum 검증 데이터 확인 ### 7.2 스키마 변경 전략 - Flyway 또는 Liquibase를 통한 버전 관리 - 무중단 배포를 위한 Blue-Green 전략 - 인덱스 추가 시 CONCURRENTLY 옵션 사용 --- ## 8. 모니터링 및 유지보수 ### 8.1 성능 모니터링 지표 - 배포 상태 조회 응답 시간 (<100ms) - 채널별 배포 성공률 (>95%) - 재시도 횟수 평균 (<2회) - 캐시 히트율 (>80%) ### 8.2 데이터 정리 정책 - 완료된 배포 상태: 30일 후 아카이빙 - 실패한 배포 로그: 90일 보관 - Redis 캐시: TTL 자동 만료 --- ## 9. 참고 자료 ### 9.1 관련 문서 - 클래스 설계서: `design/backend/class/distribution-service.puml` - API 설계서: `design/backend/api/distribution-service-api.md` - 시퀀스 다이어그램: `design/backend/sequence/inner/distribution-service-*.puml` ### 9.2 외부 참조 - PostgreSQL 공식 문서: https://www.postgresql.org/docs/ - Redis 캐시 설계 가이드: https://redis.io/docs/manual/patterns/ --- **문서 버전**: v1.0 **작성일**: 2025-10-29 **작성자**: Backend Developer (최수연 "아키텍처")