# 히스토리 테이블 기반 STATUS 관리 시스템 구축 가이드 **작성일**: 2024-12-20 **목적**: UNIQUE 제약조건 문제 근본 해결을 위한 히스토리 테이블 분리 시스템 구축 ## 🎯 목표 - **근본 문제 해결**: `unique_vendor_influencer_status` 중복 키 오류 완전 해결 - **확장 가능한 설계**: 상태 변경 이력 완전 추적 가능 - **기존 기능 보호**: 모든 기존 API 정상 작동 보장 - **데이터 무결성**: 트랜잭션 기반 안전한 상태 관리 ## 📋 구현 단계 ### 1단계: 데이터베이스 스키마 변경 #### 1.1 히스토리 테이블 생성 ```sql -- DDL 실행 mysql -u root -p influence < ddl/007_create_status_history_table.sql ``` #### 1.2 기존 데이터 마이그레이션 ```sql -- 기존 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 컬럼 제거 ```sql -- 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 엔드포인트 추가 ```php // 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를 새 컨트롤러로 점진적 이전 ```php // 기존 API를 새 컨트롤러로 리다이렉트 (점진적 이전) $routes->post('vendor-influencer/reapply-request', 'InfluencerControllerV2::createReapplyRequest'); ``` ### 4단계: 프론트엔드 연동 #### 4.1 API 엔드포인트 변경 ```javascript // 재승인 요청 API 변경 const endpoint = requestModal.value.isReapply ? "/api/v2/influencer/reapply-request" // 새 엔드포인트 : "/api/v2/influencer/create-request"; ``` #### 4.2 응답 데이터 구조 업데이트 ```javascript // 상태 정보는 CURRENT_STATUS 필드로 변경 vendor.PARTNERSHIP_STATUS = response.CURRENT_STATUS; vendor.PARTNERSHIP_MESSAGE = response.CURRENT_STATUS_MESSAGE; ``` ## 🔧 주요 개선사항 ### 1. 완전한 UNIQUE 제약조건 해결 ```sql -- 기존 문제: (VENDOR_SEQ, INFLUENCER_SEQ, STATUS) 중복 불가 -- 해결책: STATUS를 별도 테이블로 분리, 메인 테이블에는 매핑 정보만 -- 히스토리 테이블 UNIQUE 제약조건 UNIQUE INDEX unique_current_mapping (MAPPING_SEQ, IS_CURRENT) -- 하나의 매핑에 대해 하나의 현재 상태만 존재 ``` ### 2. 완전한 상태 변경 이력 추적 ```sql -- 모든 상태 변경이 히스토리로 기록됨 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. 트랜잭션 기반 안전한 상태 관리 ```php // VendorInfluencerStatusHistoryModel::changeStatus() // 1. 기존 현재 상태를 이전 상태로 변경 (IS_CURRENT = 'N') // 2. 새로운 상태 히스토리 추가 (IS_CURRENT = 'Y') // 3. 메인 테이블 MOD_DATE 업데이트 // 모든 과정이 트랜잭션으로 보장됨 ``` ### 4. 기존 API 호환성 유지 ```php // 기존 코드에서 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. 데이터 백업 ```bash # 마이그레이션 전 필수 백업 mysqldump -u root -p influence > backup_before_migration_$(date +%Y%m%d_%H%M%S).sql ``` ### 2. 점진적 배포 ```bash # 1단계: 히스토리 테이블 생성 (기존 시스템 영향 없음) # 2단계: 새 API 배포 (기존 API와 병행 운영) # 3단계: 프론트엔드 점진적 이전 # 4단계: 기존 API 제거 (충분한 검증 후) ``` ### 3. 모니터링 ```sql -- 상태 불일치 모니터링 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. 성능 최적화 ```sql -- 자주 사용되는 조회 패턴에 대한 복합 인덱스 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 관리 시스템 구축 완료**