{"id":"cmq4r7ykq0019o601ssyukzrk","docId":"cmq4p3x9c006ppl015jytx19g","version":1,"title":"ILSA → irosafe_shred 마이그 매핑","content":"# 좁힘 마이그 매핑 매트릭스 (v5)\n\n작성: 2026-06-06 KST · MVP 6/30 (D-24)\n선행: ERD v0.5 메인 (`01_신스키마_ERD_v0.5.md`) + 보강 (`02_ERD_v0.5_보강.md`)\n대상 데이터: 운영 DB `ILSA_SHREDDING` (system1472.sldb.iwinv.net) → 신모델 (자체 스키마)\n\n## 0. 마이그 정합 원칙\n\n1. **자연키 보존** — 레거시 PK/코드를 신모델 UNIQUE 컬럼 + `migration_legacy_ref` 매핑\n2. **변환 못 하면 격리** — `migration_legacy_ref.status='REVIEW_NEEDED'` + 운영자 staging 검토\n3. **마이그 범위 한정 (4 도메인)** — 계약 + 지점 + 일정 횟수 + 협력사 (B8)\n4. **레거시 보조 보존** — 신모델 운영 중에도 추적 가능\n\n## 1. 좁힘 마이그 범위\n\n| # | 신모델 도메인 | 레거시 테이블 (ILSA) | row 수 | 자연키 |\n|---|---|---|---|---|\n| 1 | partner (협력사) | SSF_SUBCONTRACTOR_MANAGEMENT | TBD | SUBCONTRACTOR_ID / business_no |\n| 2 | partner_branch (지점) | SSF_BRANCH_OFFICE_MANAGEMENT | TBD | BRANCH_OFFICE_ID code |\n| 3 | recurring_contract_group / one_call_contract / recurring_contract_site (계약) | SSF_CONTRACT_MANAGEMENT | TBD | CONTRACT_ID code |\n| 4 | recurring_schedule_rule (일정 횟수) | SSF_SCHEDULE_MANAGEMENT 정제 | 횟수만 | — |\n\n> **MVP 외** (Phase E 후 7월): 사용자(member), 콘솔, 증명서, 작업 이력 풀 마이그.\n\n## 2. 컬럼별 매핑 표\n\n### 2.1 협력사 — `SSF_SUBCONTRACTOR_MANAGEMENT` → `partner`\n\n| 레거시 컬럼 | 신모델 컬럼 | 변환 |\n|---|---|---|\n| SUBCONTRACTOR_SEQ | `partner.legacy_subcontractor_seq` | 그대로 |\n| SUBCONTRACTOR_ID | `partner.code` UNIQUE | 그대로 (자연키) |\n| SUBCONTRACTOR_NAME | `partner.name` | trim |\n| BUSINESS_NUMBER | `partner.business_no` UNIQUE | `999-99-99999` → `9999999999` (정규화 후 UNIQUE 보존) |\n| PHONE | `partner.phone` | `010-XXXX-XXXX` 형식 |\n| ADDRESS | `partner.address_main` | |\n| ZIPCODE | `partner.address_zip` | |\n| AREA_CODE | `partner.region_code` FK→system.code | category=`REGION` |\n| STATUS | `partner.status` | C-code → `ACTIVE`/`SUSPENDED`/`CLOSED` ENUM (mapping 표 §3) |\n| APPROVAL_STATUS | (마이그 X — 신모델 사용 X) | — |\n| INS_DATE / UPD_DATE | `created_at` / `updated_at` | KST → UTC |\n| INS_ID / UPD_ID | `created_by` / `updated_by` | login_id → account.id 매핑 (사용자 마이그 후) |\n| — | `partner.color_hex` | NULL 시 시스템 자동 할당 (palette 7색 round-robin) |\n\n### 2.2 지점 — `SSF_BRANCH_OFFICE_MANAGEMENT` → `partner_branch`\n\n| 레거시 | 신모델 | 변환 |\n|---|---|---|\n| BRANCH_OFFICE_SEQ | `partner_branch.legacy_branch_seq` | 그대로 |\n| BRANCH_OFFICE_ID | `partner_branch.code` (partner_id+code UNIQUE) | |\n| CONTRACT_ID | (정기) `partner_id` 매핑 시 사용 — 본사 SUBCONTRACTOR 추출 | |\n| BRANCH_OFFICE_NAME | `partner_branch.name` | |\n| MANAGER_NAME | `partner_contact.name` (별도 row 생성) | |\n| MANAGER_PHONE | `partner_contact.phone` | |\n| ADDRESS / ZIPCODE / AREA_CODE | 동일 패턴 | |\n| OPERATION_CYCLE_VALUE | `recurring_schedule_rule.month_count` (별도 row) | unit=MONTH 일 때 |\n| OPERATION_CYCLE_UNIT | (rule 생성 시 사용) | MONTH/WEEK 두 분리 |\n| REPETITION_FORM | (rule 의 preferred_weekdays/time 힌트 — 가능하면) | |\n| STATUS / APPROVAL_STATUS | C-code → ENUM | |\n| SUBCONTRACTOR_ID | `partner_id` FK | (legacy mapping ref 통해) |\n\n### 2.3 계약 — `SSF_CONTRACT_MANAGEMENT` → 트랙별 분리\n\n#### (a) 원콜 (`IS_ANNUAL=N`, `IS_BRANCH=N`)\n→ `one_call_contract`\n\n| 레거시 | 신모델 |\n|---|---|\n| CONTRACT_ID | `one_call_contract.contract_no` (`OC-` prefix 가능, 형식 변환) |\n| CONTRACT_NAME | `one_call_contract.name` (auto prefix `[원콜]`) |\n| COMPANY_NAME | `customer_name` |\n| BUSINESS_NUMBER | `business_no` |\n| STARTED_ON | `work_date` (원콜은 단일 일자) |\n| CRUSH_OPTION | `shred_option` (SITE→ON_SITE, WAREHOUSE→INTAKE) |\n| CERTIFICATE_TYPE | C-code → ENUM (`C1210000`→YEARLY 등, §3 mapping) |\n| STATUS | C-code → ENUM (DRAFT→/APPROVED→CONTRACT/TERMINATED→CANCELLED) |\n\n#### (b) 정기 본사 (`IS_ANNUAL=Y`, `IS_BRANCH=Y`)\n→ `recurring_contract_group`\n\n| 레거시 | 신모델 |\n|---|---|\n| CONTRACT_ID | `code` |\n| COMPANY_NAME | `name` |\n| BUSINESS_NUMBER | `business_no` |\n| ADDRESS / ZIPCODE | 본사 주소 |\n\n#### (c) 정기 지점 — `SSF_BRANCH_OFFICE_MANAGEMENT` 의 contract 연결 → `recurring_contract_site`\n\n| 레거시 | 신모델 |\n|---|---|\n| `BRANCH_OFFICE.CONTRACT_ID` | `recurring_contract_site.group_id` (legacy_ref 매핑 거침) |\n| `BRANCH_OFFICE_ID` | `contract_no` (자연키 보존, 형식 `RC-{group_code}-NNN`) |\n| SETUP_STARTED_ON | `contract_start_date` |\n| VISIT_ENDS_ON | `contract_end_date` (NULL 시 = `contract_start_date + 1년` default) |\n| — | `auto_extend=TRUE` (default, 회의 결정) |\n| SUBCONTRACTOR_ID | `partner_id` (legacy_ref 매핑) |\n\n### 2.4 일정 횟수 — `SSF_SCHEDULE_MANAGEMENT` → `recurring_schedule_rule` (정제)\n\nPDF/회의 결정: 세부 일정 마이그 X. **\"주 몇 회\" 횟수만 정제**.\n\n| 변환 | 설명 |\n|---|---|\n| 그룹화 | 같은 BRANCH_OFFICE_ID + 월 단위 작업 횟수 집계 |\n| `month_count` 계산 | 직전 12개월 평균 작업 횟수 |\n| `preferred_weekdays` | 가장 빈번한 요일 (TOP 2) |\n| `preferred_time_window` | VISIT_START_TIME 분포 → MORNING/AFTERNOON/EVENING |\n| `effective_from` | 마이그 시점 |\n\n→ 신모델 매월 25일 배치가 본 rule 기준으로 다음 달 schedule 생성. 사람이 SOP 화면에서 날짜 조정.\n\n## 3. 코드 마스터 매핑 (`SSF_CMMN_CODE` → 신모델 ENUM)\n\n| 레거시 코드 | 의미 | 신모델 ENUM |\n|---|---|---|\n| **자루상태 (CRUSHER_STATUS)** | | |\n| C1100000 | 자루상태 (UPPER) | (parent) — sub-code 만 사용 |\n| C1120000 | 수거 | `console_bag_history.event='COLLECTED'` 또는 status='IN_USE' |\n| (그 외 sub-code TBD) | | |\n| **파쇄증명서 종류 (CERTIFICATE_TYPE)** | | |\n| C1210000 | 연간계약용 | `certificate.type='YEARLY'` |\n| C1220000 | 단건계약용 | `certificate.type='ONE_TIME'` |\n| C1230000 | 코웨이전용 | `certificate.type='COWAY'` |\n| C1240000 | AH전용 | `certificate.type='AH'` |\n| C1250000 | HDD용 | `certificate.type='HDD'` |\n| **파쇄증명서 발급상태 (STATUS)** | | |\n| C9010000 | 발급 | `certificate.status='ISSUED'` |\n| C9020000 | 미발급 | `certificate.status='UNISSUED'` |\n| **콘솔 상태 (STATUS)** | | |\n| C7020000 | 배정 | `console.status='DEPLOYED'` |\n| (그 외 sub-code TBD) | | |\n| **승인 상태 (APPROVAL_STATUS)** | | |\n| C2010000 | 승인요청 | (마이그 X — 신모델 사용 X, 모두 APPROVED 변환) |\n| **계약 상태 (CONTRACT.STATUS)** | | |\n| DRAFT / APPROVED / ACTIVE | | `contract.status='CONTRACT'` |\n| TERMINATED / EXPIRED | | `contract.status='CANCELLED'`/`EXPIRED'` |\n\n## 4. 운영자 확인 5건 → 마이그 정책\n\n| # | 항목 | 결정 (마이그 시) |\n|---|---|---|\n| #1 | Crm1472 AWS IP 13.124.4.31 | 자체 CRM. 신규 시스템 `/crm/save` 호환 endpoint 유지. controller 위치는 `irosafe-shred-commons/api/crm` |\n| #2 | password_hash | bcrypt 확정 (BCryptPasswordEncoder). 해시 그대로 옮김 — 재설정 X |\n| #3 | CRUSHER_STATUS='C1100000' 1건 | 데이터 결함. `migration_legacy_ref.status='REVIEW_NEEDED'` — CS2207 격리 |\n| #4 | certificate 50% 미발급 | 운영 흐름 정상. ENUM `ISSUED/UNISSUED` 그대로 마이그 |\n| #5 | WORK_TYPE='kg' 687건 | 중량형 단위. `unit='kg', quantity=WORK_WEIGHT 값` 변환 |\n\n## 5. ETL 실행 순서\n\n```\nPhase E1 — partner (의존: 없음)\nPhase E2 — partner_branch + partner_contact (의존: partner)\nPhase E3 — recurring_contract_group (정기 본사)\nPhase E4 — recurring_contract_site (의존: group + partner + partner_branch)\nPhase E5 — one_call_contract\nPhase E6 — recurring_schedule_rule (의존: site, 12개월 집계)\nPhase E7 — 검증 (count·체크섬·샘플 비교)\n```\n\n각 단계마다 `migration_legacy_ref` row 동시 INSERT (entity_type 별).\n\n## 6. 검증 쿼리 (Phase E7)\n\n```sql\n-- 협력사 count 일치\nSELECT COUNT(*) AS legacy FROM SSF_SUBCONTRACTOR_MANAGEMENT WHERE STATUS != 'TERMINATED';\nSELECT COUNT(*) AS new FROM partner;\n-- ↑ 차이가 있으면 폐업 협력사 마이그 정책 재확인\n\n-- 지점 count 일치 + partner 연결 검증\nSELECT COUNT(*) FROM partner_branch pb\nJOIN migration_legacy_ref m ON m.entity_type='partner_branch' AND m.new_id=pb.id\nWHERE m.legacy_pk_value IS NOT NULL;\n\n-- 사업자번호 정합 (UNIQUE)\nSELECT business_no, COUNT(*) FROM partner GROUP BY business_no HAVING COUNT(*) > 1;\n\n-- 자연키 보존 검증 (legacy_ref 와 신모델 자연키)\nSELECT m.legacy_code, m.new_id, p.code\nFROM migration_legacy_ref m JOIN partner p ON p.id=m.new_id\nWHERE m.entity_type='partner' AND m.legacy_code != p.code;\n```\n\n## 7. Staging 격리 정책\n\n다음 row 는 `migration_staging_*` 로 격리 + 운영자 검토:\n\n| 케이스 | 격리 사유 |\n|---|---|\n| business_no 형식 잘못 | 정규화 실패 |\n| business_no 중복 | UNIQUE 위반 |\n| CRUSHER_STATUS='C1100000' | parent code 이상치 |\n| 폐업 협력사 (CLOSED) | B8: 운영자 검토 후 마이그 여부 결정 |\n| 작업 횟수 산정 불가 (지점 작업 0건) | 횟수 정제 결과 0 |\n\n각 격리 row → `migration_legacy_ref.status='REVIEW_NEEDED'` + note 명시.\n\n## 8. 다음 step\n\n- [ ] tui — `_data/migration/V_*.sql` ETL 스크립트 작성 (본 매핑 표 기반)\n- [ ] AI 어시스턴트 재검토 (본 매핑 매트릭스 + ERD v0.5.1 통합)\n- [ ] Phase E1~E7 실행 순서 확정 + 운영자 검토 staging 흐름 설계\n- [ ] 검증 쿼리 자동화 (Flyway repeatable migration 또는 별도 verify 스크립트)\n\n## 변경 이력\n\n- v5 (2026-06-06): 신규 작성. 좁힘 범위 (계약+지점+일정 횟수+협력사) + 자연키 보존 + 운영자 확인 5건 반영 + `SSF_CMMN_CODE` decoding 결과.\n","sourceHash":null,"archivedAt":"2026-06-08T14:12:16+09:00","archivedBy":"sync"}