2024-12-20-히스토리테이블-마이그레이션-가이드.md 7.8 KB

히스토리 테이블 기반 STATUS 관리 시스템 구축 가이드

작성일: 2024-12-20
목적: UNIQUE 제약조건 문제 근본 해결을 위한 히스토리 테이블 분리 시스템 구축

🎯 목표

  • 근본 문제 해결: unique_vendor_influencer_status 중복 키 오류 완전 해결
  • 확장 가능한 설계: 상태 변경 이력 완전 추적 가능
  • 기존 기능 보호: 모든 기존 API 정상 작동 보장
  • 데이터 무결성: 트랜잭션 기반 안전한 상태 관리

📋 구현 단계

1단계: 데이터베이스 스키마 변경

1.1 히스토리 테이블 생성

-- DDL 실행
mysql -u root -p influence < ddl/007_create_status_history_table.sql

1.2 기존 데이터 마이그레이션

-- 기존 STATUS 데이터를 히스토리 테이블로 이전
INSERT INTO VENDOR_INFLUENCER_STATUS_HISTORY 
(MAPPING_SEQ, STATUS, STATUS_MESSAGE, CHANGED_BY, CHANGED_DATE, IS_CURRENT)
SELECT 
    SEQ as MAPPING_SEQ,
    COALESCE(STATUS, 'PENDING') as STATUS,
    COALESCE(REQUEST_MESSAGE, '') as STATUS_MESSAGE,
    REQUESTED_BY as CHANGED_BY,
    REG_DATE as CHANGED_DATE,
    'Y' as IS_CURRENT
FROM VENDOR_INFLUENCER_MAPPING 
WHERE IS_ACT = 'Y';

1.3 메인 테이블에서 STATUS 컬럼 제거

-- STATUS 컬럼 제거 (백업 후 실행)
ALTER TABLE VENDOR_INFLUENCER_MAPPING DROP COLUMN STATUS;

2단계: 새로운 모델 및 컨트롤러 배포

2.1 새 모델 파일 배포

  • VendorInfluencerStatusHistoryModel.php - 상태 히스토리 관리
  • VendorInfluencerMappingModel.php - STATUS 컬럼 제거된 메인 모델

2.2 새 컨트롤러 배포

  • InfluencerControllerV2.php - 히스토리 테이블 기반 새 컨트롤러

3단계: 라우팅 설정 변경

3.1 새 API 엔드포인트 추가

// app/Config/Routes.php에 추가
$routes->group('api/v2', function($routes) {
    $routes->group('influencer', function($routes) {
        $routes->post('search-vendors', 'InfluencerControllerV2::searchVendors');
        $routes->post('create-request', 'InfluencerControllerV2::createApprovalRequest');
        $routes->post('reapply-request', 'InfluencerControllerV2::createReapplyRequest');
        $routes->post('my-partnerships', 'InfluencerControllerV2::getMyPartnerships');
        $routes->post('terminate', 'InfluencerControllerV2::terminatePartnership');
    });
});

3.2 기존 API를 새 컨트롤러로 점진적 이전

// 기존 API를 새 컨트롤러로 리다이렉트 (점진적 이전)
$routes->post('vendor-influencer/reapply-request', 'InfluencerControllerV2::createReapplyRequest');

4단계: 프론트엔드 연동

4.1 API 엔드포인트 변경

// 재승인 요청 API 변경
const endpoint = requestModal.value.isReapply
  ? "/api/v2/influencer/reapply-request"  // 새 엔드포인트
  : "/api/v2/influencer/create-request";

4.2 응답 데이터 구조 업데이트

// 상태 정보는 CURRENT_STATUS 필드로 변경
vendor.PARTNERSHIP_STATUS = response.CURRENT_STATUS;
vendor.PARTNERSHIP_MESSAGE = response.CURRENT_STATUS_MESSAGE;

🔧 주요 개선사항

1. 완전한 UNIQUE 제약조건 해결

-- 기존 문제: (VENDOR_SEQ, INFLUENCER_SEQ, STATUS) 중복 불가
-- 해결책: STATUS를 별도 테이블로 분리, 메인 테이블에는 매핑 정보만

-- 히스토리 테이블 UNIQUE 제약조건
UNIQUE INDEX unique_current_mapping (MAPPING_SEQ, IS_CURRENT)
-- 하나의 매핑에 대해 하나의 현재 상태만 존재

2. 완전한 상태 변경 이력 추적

-- 모든 상태 변경이 히스토리로 기록됨
SELECT 
    STATUS, 
    PREVIOUS_STATUS, 
    STATUS_MESSAGE, 
    CHANGED_BY, 
    CHANGED_DATE 
FROM VENDOR_INFLUENCER_STATUS_HISTORY 
WHERE MAPPING_SEQ = 1 
ORDER BY CHANGED_DATE DESC;

3. 트랜잭션 기반 안전한 상태 관리

// VendorInfluencerStatusHistoryModel::changeStatus()
// 1. 기존 현재 상태를 이전 상태로 변경 (IS_CURRENT = 'N')
// 2. 새로운 상태 히스토리 추가 (IS_CURRENT = 'Y')
// 3. 메인 테이블 MOD_DATE 업데이트
// 모든 과정이 트랜잭션으로 보장됨

4. 기존 API 호환성 유지

// 기존 코드에서 STATUS 조회하던 부분
$partnership['STATUS']  // 기존 방식

// 새로운 방식 (JOIN으로 현재 상태 조회)
$partnership['CURRENT_STATUS']  // 히스토리 테이블 JOIN

🧪 테스트 시나리오

1. 기본 기능 테스트

  • 새 승인 요청: PENDING 상태로 정상 생성
  • 중복 요청 방지: 동일 조합에서 PENDING 상태 중복 방지
  • 승인/거부 처리: 상태 변경 시 히스토리 정상 기록
  • 재승인 요청: REJECTED/TERMINATED → PENDING 정상 처리

2. 상태 히스토리 테스트

  • 이력 추적: 모든 상태 변경이 히스토리에 기록됨
  • 현재 상태 조회: IS_CURRENT='Y'인 레코드만 조회됨
  • 이전 상태 보존: 변경 전 상태가 PREVIOUS_STATUS에 기록됨

3. 데이터 무결성 테스트

  • 트랜잭션 보장: 상태 변경 중 오류 시 롤백 정상 작동
  • 외래키 제약조건: 매핑 삭제 시 히스토리도 연쇄 삭제
  • UNIQUE 제약조건: 동일 매핑에 현재 상태 중복 불가

4. 성능 테스트

  • 조회 성능: JOIN 쿼리 성능 확인
  • 인덱스 효과: 상태별, 매핑별 조회 성능 확인
  • 대용량 데이터: 히스토리 데이터 증가 시 성능 영향 확인

🚨 주의사항

1. 데이터 백업

# 마이그레이션 전 필수 백업
mysqldump -u root -p influence > backup_before_migration_$(date +%Y%m%d_%H%M%S).sql

2. 점진적 배포

# 1단계: 히스토리 테이블 생성 (기존 시스템 영향 없음)
# 2단계: 새 API 배포 (기존 API와 병행 운영)
# 3단계: 프론트엔드 점진적 이전
# 4단계: 기존 API 제거 (충분한 검증 후)

3. 모니터링

-- 상태 불일치 모니터링
SELECT 
    MAPPING_SEQ, 
    COUNT(*) as current_status_count
FROM VENDOR_INFLUENCER_STATUS_HISTORY 
WHERE IS_CURRENT = 'Y' 
GROUP BY MAPPING_SEQ 
HAVING COUNT(*) > 1;
-- 결과가 0이어야 정상

4. 성능 최적화

-- 자주 사용되는 조회 패턴에 대한 복합 인덱스
CREATE INDEX idx_mapping_current_status 
ON VENDOR_INFLUENCER_STATUS_HISTORY (MAPPING_SEQ, IS_CURRENT, STATUS);

-- 파티셔닝 고려 (대용량 히스토리 데이터 시)
-- 월별 또는 연도별 파티셔닝 검토

📈 예상 효과

1. 문제 해결

  • 중복 키 오류 완전 해결: 더 이상 unique_vendor_influencer_status 오류 발생하지 않음
  • 재승인 요청 안정성: 모든 상태에서 재승인 요청 가능
  • 데이터 일관성: 트랜잭션 기반 상태 관리로 데이터 무결성 보장

2. 기능 향상

  • 📊 완전한 이력 추적: 모든 상태 변경 이력 추적 가능
  • 🔄 유연한 상태 관리: 복잡한 상태 변경 시나리오 지원
  • 📈 확장성: 새로운 상태 추가 시 기존 코드 영향 최소화

3. 운영 개선

  • 🐛 디버깅 향상: 상태 변경 이력으로 문제 원인 추적 용이
  • 📊 분석 기능: 상태 변경 패턴 분석 가능
  • 🛠️ 유지보수성: 명확한 책임 분리로 코드 유지보수 용이

🎉 배포 완료 체크리스트

  • 데이터베이스 백업 완료
  • DDL 스크립트 실행 완료
  • 새 모델/컨트롤러 배포 완료
  • 라우팅 설정 업데이트 완료
  • 기존 기능 회귀 테스트 완료
  • 새 기능 테스트 완료
  • 성능 테스트 완료
  • 모니터링 설정 완료
  • 문서 업데이트 완료

✅ 히스토리 테이블 기반 STATUS 관리 시스템 구축 완료