jhbkjh 3075a5d49f 물리아키텍처 설계 완료
 주요 기능
- 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>
2025-10-29 15:13:01 +09:00

17 KiB

Event Service 데이터베이스 설계서

📋 데이터설계 요약

개요

  • 서비스명: Event Service
  • 데이터베이스: PostgreSQL 15.x
  • 캐시 시스템: Redis 7.x
  • 아키텍처 패턴: Clean Architecture
  • 설계 일자: 2025-10-29

데이터베이스 역할

  • 핵심 도메인: 이벤트 생명주기 관리 (DRAFT → PUBLISHED → ENDED)
  • 상태 머신: EventStatus enum 기반 상태 전환
  • 비동기 작업: Job 엔티티로 장시간 작업 추적
  • AI 추천: AiRecommendation 엔티티로 AI 생성 결과 저장
  • 이미지 관리: GeneratedImage 엔티티로 생성 이미지 저장

테이블 구성

테이블명 설명 주요 컬럼 비고
events 이벤트 기본 정보 event_id, user_id, store_id, status 핵심 도메인
ai_recommendations AI 추천 결과 recommendation_id, event_id Event 1:N
generated_images 생성 이미지 정보 image_id, event_id Event 1:N
jobs 비동기 작업 추적 job_id, event_id, job_type, status 작업 모니터링

Redis 캐시 설계

키 패턴 설명 TTL 비고
event:session:{userId} 이벤트 생성 세션 정보 3600s 임시 데이터
event:draft:{eventId} DRAFT 상태 이벤트 캐시 1800s 빈번한 수정
job:status:{jobId} 작업 상태 실시간 조회 600s 진행률 캐싱

1. PostgreSQL 테이블 설계

1.1 events (이벤트 기본 정보)

설명: 이벤트 핵심 도메인 엔티티. 상태 머신 패턴으로 생명주기 관리.

컬럼 정의:

컬럼명 데이터 타입 제약조건 설명
event_id UUID PK 이벤트 고유 ID
user_id UUID NOT NULL, INDEX 사용자 ID (소상공인)
store_id UUID NOT NULL, INDEX 매장 ID
event_name VARCHAR(200) NULL 이벤트 명칭
description TEXT NULL 이벤트 설명
objective VARCHAR(100) NOT NULL 이벤트 목적
start_date DATE NULL 이벤트 시작일
end_date DATE NULL 이벤트 종료일
status VARCHAR(20) NOT NULL, DEFAULT 'DRAFT' 이벤트 상태 (DRAFT, PUBLISHED, ENDED)
selected_image_id UUID NULL 선택된 이미지 ID
selected_image_url VARCHAR(500) NULL 선택된 이미지 URL
channels TEXT NULL 배포 채널 목록 (JSON Array)
created_at TIMESTAMP NOT NULL, DEFAULT CURRENT_TIMESTAMP 생성 일시
updated_at TIMESTAMP NOT NULL, DEFAULT CURRENT_TIMESTAMP 수정 일시

인덱스:

  • PK_events: event_id (Primary Key)
  • IDX_events_user_id: user_id (사용자별 이벤트 조회 최적화)
  • IDX_events_store_id: store_id (매장별 이벤트 조회)
  • IDX_events_status: status (상태별 필터링)
  • IDX_events_user_status: (user_id, status) (복합 인덱스 - 사용자별 상태 조회)

비즈니스 규칙:

  • DRAFT 상태에서만 수정 가능
  • PUBLISHED 상태에서 수정 불가, END만 가능
  • ENDED 상태는 최종 상태 (수정/삭제 불가)
  • selected_image_id는 generated_images 테이블 참조
  • channels는 JSON 배열 형태로 저장 (예: ["SMS", "EMAIL"])

데이터 예시:

{
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "user_id": "123e4567-e89b-12d3-a456-426614174000",
  "store_id": "789e0123-e45b-67c8-d901-234567890abc",
  "event_name": "여름 시즌 특별 할인",
  "description": "7월 한 달간 전 품목 20% 할인",
  "objective": "고객 유치",
  "start_date": "2025-07-01",
  "end_date": "2025-07-31",
  "status": "PUBLISHED",
  "selected_image_id": "abc12345-e67d-89ef-0123-456789abcdef",
  "selected_image_url": "https://cdn.example.com/images/abc12345.jpg",
  "channels": "[\"SMS\", \"EMAIL\", \"KAKAO\"]",
  "created_at": "2025-06-15T10:00:00",
  "updated_at": "2025-06-20T14:30:00"
}

1.2 ai_recommendations (AI 추천 결과)

설명: AI 서비스로부터 받은 이벤트 추천 결과 저장.

컬럼 정의:

컬럼명 데이터 타입 제약조건 설명
recommendation_id UUID PK 추천 고유 ID
event_id UUID NOT NULL, FK(events) 이벤트 ID
event_name VARCHAR(200) NOT NULL AI 추천 이벤트명
description TEXT NOT NULL AI 추천 설명
promotion_type VARCHAR(50) NOT NULL 프로모션 유형
target_audience VARCHAR(100) NOT NULL 타겟 고객층
is_selected BOOLEAN NOT NULL, DEFAULT FALSE 선택 여부
created_at TIMESTAMP NOT NULL, DEFAULT CURRENT_TIMESTAMP 생성 일시
updated_at TIMESTAMP NOT NULL, DEFAULT CURRENT_TIMESTAMP 수정 일시

인덱스:

  • PK_ai_recommendations: recommendation_id (Primary Key)
  • FK_recommendations_event: event_id (Foreign Key)
  • IDX_recommendations_event_id: event_id (이벤트별 추천 조회)
  • IDX_recommendations_selected: (event_id, is_selected) (선택된 추천 조회)

비즈니스 규칙:

  • 하나의 이벤트당 최대 3개의 AI 추천 생성
  • is_selected=true는 이벤트당 최대 1개만 가능
  • 선택 시 해당 이벤트의 다른 추천들은 is_selected=false 처리

데이터 예시:

{
  "recommendation_id": "111e2222-e33b-44d4-a555-666677778888",
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_name": "여름 시즌 특별 할인",
  "description": "7월 한 달간 전 품목 20% 할인 이벤트",
  "promotion_type": "DISCOUNT",
  "target_audience": "기존 고객",
  "is_selected": true,
  "created_at": "2025-06-15T10:05:00",
  "updated_at": "2025-06-15T10:10:00"
}

1.3 generated_images (생성 이미지 정보)

설명: Content Service로부터 생성된 이미지 정보 저장.

컬럼 정의:

컬럼명 데이터 타입 제약조건 설명
image_id UUID PK 이미지 고유 ID
event_id UUID NOT NULL, FK(events) 이벤트 ID
image_url VARCHAR(500) NOT NULL 이미지 URL (CDN)
style VARCHAR(50) NOT NULL 이미지 스타일 (MODERN, VINTAGE 등)
platform VARCHAR(50) NOT NULL 플랫폼 (INSTAGRAM, FACEBOOK 등)
is_selected BOOLEAN NOT NULL, DEFAULT FALSE 선택 여부
created_at TIMESTAMP NOT NULL, DEFAULT CURRENT_TIMESTAMP 생성 일시
updated_at TIMESTAMP NOT NULL, DEFAULT CURRENT_TIMESTAMP 수정 일시

인덱스:

  • PK_generated_images: image_id (Primary Key)
  • FK_images_event: event_id (Foreign Key)
  • IDX_images_event_id: event_id (이벤트별 이미지 조회)
  • IDX_images_selected: (event_id, is_selected) (선택된 이미지 조회)

비즈니스 규칙:

  • 하나의 이벤트당 여러 스타일/플랫폼 조합 이미지 생성 가능
  • is_selected=true는 이벤트당 최대 1개만 가능
  • 선택 시 해당 이벤트의 다른 이미지들은 is_selected=false 처리
  • 선택된 이미지의 image_id와 image_url은 events 테이블에도 저장

데이터 예시:

{
  "image_id": "abc12345-e67d-89ef-0123-456789abcdef",
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "image_url": "https://cdn.example.com/images/abc12345.jpg",
  "style": "MODERN",
  "platform": "INSTAGRAM",
  "is_selected": true,
  "created_at": "2025-06-15T11:00:00",
  "updated_at": "2025-06-15T11:05:00"
}

1.4 jobs (비동기 작업 추적)

설명: AI 추천 생성, 이미지 생성 등 장시간 작업 추적.

컬럼 정의:

컬럼명 데이터 타입 제약조건 설명
job_id UUID PK 작업 고유 ID
event_id UUID NOT NULL 이벤트 ID
job_type VARCHAR(50) NOT NULL 작업 유형 (AI_RECOMMENDATION, IMAGE_GENERATION)
status VARCHAR(20) NOT NULL, DEFAULT 'PENDING' 작업 상태 (PENDING, PROCESSING, COMPLETED, FAILED)
progress INT NOT NULL, DEFAULT 0 진행률 (0-100)
result_key VARCHAR(200) NULL 결과 저장 키 (Redis 또는 S3)
error_message TEXT NULL 오류 메시지
completed_at TIMESTAMP NULL 완료 일시
created_at TIMESTAMP NOT NULL, DEFAULT CURRENT_TIMESTAMP 생성 일시
updated_at TIMESTAMP NOT NULL, DEFAULT CURRENT_TIMESTAMP 수정 일시

인덱스:

  • PK_jobs: job_id (Primary Key)
  • IDX_jobs_event_id: event_id (이벤트별 작업 조회)
  • IDX_jobs_type_status: (job_type, status) (작업 유형별 상태 조회)
  • IDX_jobs_status: status (상태별 작업 모니터링)

비즈니스 규칙:

  • PENDING → PROCESSING → COMPLETED/FAILED 순차 진행
  • progress는 0에서 100 사이 값 (PROCESSING 상태에서만 업데이트)
  • COMPLETED 시 completed_at 자동 설정
  • FAILED 시 error_message 필수

데이터 예시:

{
  "job_id": "999e8888-e77b-66d6-a555-444433332222",
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "job_type": "AI_RECOMMENDATION",
  "status": "COMPLETED",
  "progress": 100,
  "result_key": "ai-recommendation:550e8400-e29b-41d4-a716-446655440000",
  "error_message": null,
  "completed_at": "2025-06-15T10:10:00",
  "created_at": "2025-06-15T10:00:00",
  "updated_at": "2025-06-15T10:10:00"
}

2. Redis 캐시 설계

2.1 이벤트 세션 정보

키 패턴: event:session:{userId}

데이터 구조: Hash

필드:

  • eventId: UUID - 임시 이벤트 ID
  • objective: String - 선택한 목적
  • storeId: UUID - 매장 ID
  • createdAt: Timestamp - 세션 생성 시각

TTL: 3600초 (1시간)

사용 목적:

  • 이벤트 생성 프로세스의 임시 데이터 저장
  • 사용자가 이벤트 생성 중 페이지 이동 시 데이터 유지
  • 1시간 후 자동 삭제로 메모리 최적화

예시:

HSET event:session:123e4567-e89b-12d3-a456-426614174000
  eventId "550e8400-e29b-41d4-a716-446655440000"
  objective "고객 유치"
  storeId "789e0123-e45b-67c8-d901-234567890abc"
  createdAt "2025-06-15T10:00:00"
EXPIRE event:session:123e4567-e89b-12d3-a456-426614174000 3600

2.2 DRAFT 이벤트 캐시

키 패턴: event:draft:{eventId}

데이터 구조: Hash

필드:

  • eventName: String - 이벤트명
  • description: String - 설명
  • objective: String - 목적
  • status: String - 상태
  • userId: UUID - 사용자 ID
  • storeId: UUID - 매장 ID

TTL: 1800초 (30분)

사용 목적:

  • DRAFT 상태 이벤트의 빈번한 조회/수정 성능 최적화
  • 사용자가 이벤트 편집 중 빠른 응답 제공
  • DB 부하 감소

예시:

HSET event:draft:550e8400-e29b-41d4-a716-446655440000
  eventName "여름 시즌 특별 할인"
  description "7월 한 달간 전 품목 20% 할인"
  objective "고객 유치"
  status "DRAFT"
  userId "123e4567-e89b-12d3-a456-426614174000"
  storeId "789e0123-e45b-67c8-d901-234567890abc"
EXPIRE event:draft:550e8400-e29b-41d4-a716-446655440000 1800

2.3 작업 상태 캐시

키 패턴: job:status:{jobId}

데이터 구조: Hash

필드:

  • jobType: String - 작업 유형
  • status: String - 작업 상태
  • progress: Integer - 진행률 (0-100)
  • eventId: UUID - 이벤트 ID

TTL: 600초 (10분)

사용 목적:

  • 비동기 작업 진행 상태 실시간 조회
  • 폴링 방식의 진행률 체크 시 DB 부하 방지
  • AI 추천/이미지 생성 작업의 빠른 상태 확인

예시:

HSET job:status:999e8888-e77b-66d6-a555-444433332222
  jobType "AI_RECOMMENDATION"
  status "PROCESSING"
  progress "45"
  eventId "550e8400-e29b-41d4-a716-446655440000"
EXPIRE job:status:999e8888-e77b-66d6-a555-444433332222 600

3. 데이터베이스 제약조건

3.1 외래 키 (Foreign Key)

-- ai_recommendations 테이블
ALTER TABLE ai_recommendations
  ADD CONSTRAINT FK_recommendations_event
  FOREIGN KEY (event_id) REFERENCES events(event_id)
  ON DELETE CASCADE;

-- generated_images 테이블
ALTER TABLE generated_images
  ADD CONSTRAINT FK_images_event
  FOREIGN KEY (event_id) REFERENCES events(event_id)
  ON DELETE CASCADE;

설명:

  • ON DELETE CASCADE: 이벤트 삭제 시 관련 추천/이미지 자동 삭제
  • jobs 테이블은 FK 제약조건 없음 (이벤트 삭제 후에도 작업 이력 보존)

3.2 체크 제약조건 (Check Constraints)

-- events 테이블
ALTER TABLE events
  ADD CONSTRAINT CHK_events_status
  CHECK (status IN ('DRAFT', 'PUBLISHED', 'ENDED'));

ALTER TABLE events
  ADD CONSTRAINT CHK_events_dates
  CHECK (start_date IS NULL OR end_date IS NULL OR start_date <= end_date);

-- jobs 테이블
ALTER TABLE jobs
  ADD CONSTRAINT CHK_jobs_status
  CHECK (status IN ('PENDING', 'PROCESSING', 'COMPLETED', 'FAILED'));

ALTER TABLE jobs
  ADD CONSTRAINT CHK_jobs_type
  CHECK (job_type IN ('AI_RECOMMENDATION', 'IMAGE_GENERATION'));

ALTER TABLE jobs
  ADD CONSTRAINT CHK_jobs_progress
  CHECK (progress >= 0 AND progress <= 100);

3.3 유니크 제약조건 (Unique Constraints)

-- 이벤트당 하나의 선택된 추천만 허용 (애플리케이션 레벨에서 관리)
-- 이벤트당 하나의 선택된 이미지만 허용 (애플리케이션 레벨에서 관리)

설명:

  • is_selected=true 조건의 UNIQUE 제약은 DB 레벨에서 구현 어려움
  • 애플리케이션 레벨에서 트랜잭션으로 보장

4. 성능 최적화 전략

4.1 인덱스 전략

단일 컬럼 인덱스:

  • events.user_id: 사용자별 이벤트 조회 (가장 빈번한 쿼리)
  • events.status: 상태별 필터링
  • jobs.status: 작업 모니터링

복합 인덱스:

  • (user_id, status): 사용자별 상태 필터 조회 (API: GET /events?status=DRAFT)
  • (job_type, status): 작업 유형별 상태 조회 (배치 처리)
  • (event_id, is_selected): 선택된 추천/이미지 조회

4.2 파티셔닝 전략

events 테이블 파티셔닝 (향후 고려):

  • 파티션 키: created_at (월별)
  • 적용 시점: 이벤트 데이터 100만 건 이상
  • 이점: 과거 데이터 조회 성능 향상, 백업/삭제 효율화
-- 예시 (PostgreSQL 12+)
CREATE TABLE events (
  ...
) PARTITION BY RANGE (created_at);

CREATE TABLE events_2025_06 PARTITION OF events
  FOR VALUES FROM ('2025-06-01') TO ('2025-07-01');

4.3 캐시 전략

캐시 우선 조회:

  1. Redis에서 캐시 조회
  2. 캐시 미스 시 DB 조회 후 캐시 저장
  3. TTL 만료 시 자동 삭제

캐시 무효화:

  • 이벤트 수정 시: event:draft:{eventId} 삭제
  • 작업 완료 시: job:status:{jobId} 삭제
  • 이벤트 발행 시: event:draft:{eventId} 삭제

5. 데이터 일관성 보장

5.1 트랜잭션 전략

이벤트 생성:

BEGIN;
  INSERT INTO events (...) VALUES (...);
  INSERT INTO jobs (event_id, job_type, status) VALUES (?, 'AI_RECOMMENDATION', 'PENDING');
COMMIT;

추천 선택:

BEGIN;
  UPDATE ai_recommendations SET is_selected = FALSE WHERE event_id = ?;
  UPDATE ai_recommendations SET is_selected = TRUE WHERE recommendation_id = ?;
  UPDATE events SET event_name = ?, description = ?, start_date = ?, end_date = ? WHERE event_id = ?;
COMMIT;

5.2 낙관적 락 (Optimistic Locking)

updated_at 기반 버전 관리:

@Version
private LocalDateTime updatedAt;

충돌 감지:

UPDATE events
SET event_name = ?, updated_at = CURRENT_TIMESTAMP
WHERE event_id = ? AND updated_at = ?;

6. 백업 및 복구 전략

6.1 백업 주기

  • 전체 백업: 매일 02:00 (pg_dump)
  • 증분 백업: 6시간마다 (WAL 아카이빙)
  • 보관 기간: 30일

6.2 복구 시나리오

시나리오 1: 데이터 손실 (최근 1시간)

  • WAL 로그 기반 Point-in-Time Recovery (PITR)
  • 복구 시간: 약 15분

시나리오 2: 전체 데이터베이스 복구

  • 최근 전체 백업 복원 + WAL 로그 적용
  • 복구 시간: 약 30분

7. 모니터링 지표

7.1 성능 모니터링

지표 임계값 알림
평균 쿼리 응답 시간 > 200ms Warning
DB Connection Pool 사용률 > 80% Critical
Redis Cache Hit Rate < 70% Warning
느린 쿼리 (Slow Query) > 1초 Critical

7.2 데이터 모니터링

지표 확인 주기 비고
events 테이블 레코드 수 일일 증가 추이 분석
DRAFT 상태 30일 이상 주간 정리 대상 파악
FAILED 작업 누적 일일 재처리 필요
Redis 메모리 사용률 실시간 > 80% 경고

8. 데이터 보안

8.1 암호화

  • 전송 중 암호화: SSL/TLS (PostgreSQL + Redis)
  • 저장 암호화: Transparent Data Encryption (TDE) 고려
  • 민감 정보: 없음 (이미지 URL만 저장)

8.2 접근 제어

  • DB 사용자: event_service_user (최소 권한 원칙)
  • 권한: events, ai_recommendations, generated_images, jobs 테이블에 대한 CRUD
  • Redis: Password 인증 + 네트워크 격리

9. ERD 및 스키마 파일

  • ERD: event-service-erd.puml (PlantUML)
  • DDL 스크립트: event-service-schema.psql (PostgreSQL)

작성자: Backend Architect (최수연 "아키텍처") 작성일: 2025-10-29 검토자: Backend Developer, DevOps Engineer 승인일: 2025-10-29