diff --git a/dev/dev_plans/local-to-dev-data-sync-plan.md b/dev/dev_plans/local-to-dev-data-sync-plan.md new file mode 100644 index 0000000..2c47dce --- /dev/null +++ b/dev/dev_plans/local-to-dev-data-sync-plan.md @@ -0,0 +1,282 @@ +# 로컬 → 개발서버 데이터 동기화 계획 + +> **작성일**: 2026-03-10 +> **목적**: 로컬 DB(tenant_id=287)의 MES 관련 데이터 + 파일을 개발서버로 반복 이관 +> **상태**: ⏳ 실행 대기 + +--- + +## 📍 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | 문서 점검 및 단순화 완료 | +| **다음 작업** | 스크립트 작성 + 테스트 | +| **진행률** | 0/2 (0%) | +| **마지막 업데이트** | 2026-03-10 | + +--- + +## 1. 개요 + +### 1.1 배경 + +로컬 Docker 환경에서 개발/테스트한 MES 데이터를 개발서버에 주기적으로 동기화한다. +셸 스크립트 1개로 DB + 파일을 한번에 처리한다. + +### 1.2 환경 정보 + +| 항목 | 로컬 (Docker) | 개발서버 (sam-dev) | +|------|--------------|-------------------| +| IP | localhost | **114.203.209.83** | +| SSH 사용자 | - | hskwon | +| DB명 | samdb | sam | +| DB 사용자 | samuser / sampass | codebridge | +| DB 포트 (외부) | 3306 | 3306 (localhost only) | +| MySQL 컨테이너 | sam-mysql-1 | - (bare metal) | +| API 경로 | /home/webservice/api/ (없음, Docker) | /home/webservice/api/ | +| 파일 경로 | api/storage/app/tenants/287/ | /home/webservice/api/storage/app/tenants/287/ | +| 테넌트 ID | 287 | 287 | + +> **참고**: 개발서버는 releases/shared 구조가 아닌 직접 디렉토리 구조. +> 출처: `docs/dev/deploys/ops-manual/01-server-overview.md` + +### 1.3 실행 방식 + +```bash +# Mac 터미널 (프로젝트 루트)에서 실행 +./scripts/data-sync.sh + +# 옵션 +./scripts/data-sync.sh --db-only # DB만 +./scripts/data-sync.sh --files-only # 파일만 +./scripts/data-sync.sh --dry-run # 미리보기 +``` + +- **mysqldump**: sam-mysql-1 Docker 컨테이너 내부에서 실행 +- **SSH/rsync**: Mac 호스트에서 직접 실행 (로컬에 ssh, rsync 있음) +- **향후 확장**: 필요시 mng 웹 UI 추가 가능 (현재는 스크립트로 충분) + +--- + +## 2. 대상 테이블 (35개) + +### 2.1 데이터 현황 (tenant_id=287, 2026-03-10 기준) + +| # | 카테고리 | 테이블 | 건수 | tenant_id | 비고 | +|---|---------|--------|------|-----------|------| +| | **품목기준** | | | | | +| 1 | 품목 | items | 893 | ✅ direct | | +| 2 | 카테고리 | categories | 72 | ✅ direct | | +| | **공정관리** | | | | | +| 3 | 공정 | processes | 4 | ✅ direct | | +| 4 | 공정단계 | process_steps | 19 | ❌ FK | process_id → processes | +| 5 | 분류규칙 | process_classification_rules | 0 | ❌ FK | process_id → processes | +| | **견적** | | | | | +| 6 | 견적 | quotes | 49 | ✅ direct | | +| 7 | 견적품목 | quote_items | 2,018 | ✅ direct | | +| 8 | 견적수정 | quote_revisions | 75 | ✅ direct | | +| | **수주** | | | | | +| 9 | 수주 | orders | 41 | ✅ direct | | +| 10 | 수주품목 | order_items | 2,475 | ✅ direct | | +| 11 | 수주노드 | order_nodes | 143 | ✅ direct | 자체참조 (parent_id) | +| | **생산/작업지시** | | | | | +| 12 | 작업지시 | work_orders | 120 | ✅ direct | | +| 13 | 작업품목 | work_order_items | 545 | ❌ FK | work_order_id → work_orders | +| 14 | 단계진행 | work_order_step_progress | 1,092 | ✅ direct | | +| 15 | 담당자 | work_order_assignees | 9 | ✅ direct | | +| 16 | 원자재투입 | work_order_material_inputs | 72 | ✅ direct | | +| 17 | 이슈 | work_order_issues | 1 | ❌ FK | work_order_id → work_orders | +| 18 | 벤딩상세 | work_order_bending_details | 0 | ❌ FK | work_order_id → work_orders | +| | **출하** | | | | | +| 19 | 출하 | shipments | 8 | ✅ direct | | +| 20 | 출하품목 | shipment_items | 14 | ❌ FK | shipment_id → shipments | +| 21 | 배차 | shipment_vehicle_dispatches | 2 | ✅ direct | | +| | **재고** | | | | | +| 22 | 재고현황 | stocks | 8,611 | ✅ direct | | +| 23 | LOT | stock_lots | 191 | ✅ direct | | +| 24 | 입고 | receivings | 60 | ✅ direct | | +| 25 | 거래이력 | stock_transactions | 420 | ✅ direct | | +| | **품질** | | | | | +| 26 | 검사 | inspections | 0 | ✅ direct | IQC/PQC/FQC | +| 27 | 품질관리서 | quality_documents | 2 | ✅ direct | | +| 28 | 품질-수주연결 | quality_document_orders | 1 | ❌ FK | quality_document_id | +| 29 | 품질-현장 | quality_document_locations | 4 | ❌ FK | quality_document_id | +| 30 | 성능리포트 | performance_reports | 1 | ❌ FK | quality_document_id | +| | **넘버링** | | | | | +| 31 | 넘버링규칙 | numbering_rules | 2 | ✅ direct | | +| 32 | 넘버링시퀀스 | numbering_sequences | 14 | ✅ direct | 독립 테이블 (FK 없음) | +| | **파일** | | | | | +| 33 | 파일 | files | 51 | ✅ direct | | +| 34 | 폴더 | folders | 5 | ✅ direct | | +| | **매출** | | | | | +| 35 | 매출 | sales | 81 | ✅ direct | | +| | **합계** | **35개** | **~17,840** | | | + +### 2.2 파일 저장소 + +| 항목 | 값 | +|------|-----| +| 로컬 경로 | `api/storage/app/tenants/287/` | +| 개발서버 경로 | `/home/webservice/api/storage/app/tenants/287/` | +| 파일 수 | 47개 | +| 총 크기 | 8.9MB | +| 하위 구조 | `items/`, `temp/`, `logo_*.jpeg` | + +### 2.3 제외 대상 + +| 테이블 | 제외 사유 | +|--------|----------| +| users, tenants, departments | 계정/조직 별도 관리 | +| clients | 거래처 별도 관리 (필요시 추가) | +| audit_logs | 감사 로그는 환경별 독립 | +| file_share_links, file_deletion_logs | 환경별 독립 | +| storage_usage_history | 모니터링 환경별 독립 | +| schedules, equipments 등 | 현재 데이터 0건 (향후 데이터 생기면 추가) | + +--- + +## 3. 스크립트 설계 + +### 3.1 파일 위치 + +``` +scripts/data-sync.sh # 메인 스크립트 (이것만 실행하면 됨) +``` + +### 3.2 실행 흐름 + +``` +1. 환경 검증 (SSH 접속, Docker 컨테이너 확인) +2. 로컬 DB dump (Docker 컨테이너 내부에서 mysqldump) +3. 개발서버 해당 테넌트 DELETE (SSH → mysql) +4. dump 파일 전송 + import (scp → SSH mysql) +5. 파일 동기화 (rsync) +6. 검증 (건수 비교) +7. 임시 파일 정리 +``` + +### 3.3 핵심 로직 + +#### DB dump (sam-mysql-1 컨테이너 내부) + +```bash +# tenant_id 있는 테이블 (25개) +docker exec sam-mysql-1 mysqldump -u samuser -psampass \ + --no-create-info --complete-insert --skip-triggers \ + --where="tenant_id=287" \ + samdb items quotes orders ... > /tmp/sam-sync/direct_tables.sql + +# tenant_id 없는 테이블 (10개) — FK 경유 +# 예: work_order_items는 work_orders에서 ID 조회 후 IN 조건 +docker exec sam-mysql-1 bash -c " + WO_IDS=\$(mysql -u samuser -psampass -N -e \"SELECT GROUP_CONCAT(id) FROM work_orders WHERE tenant_id=287\" samdb) + mysqldump -u samuser -psampass --no-create-info --complete-insert --skip-triggers \ + --where=\"work_order_id IN (\$WO_IDS)\" samdb work_order_items +" >> /tmp/sam-sync/fk_tables.sql +``` + +#### 개발서버 DELETE (SSH) + +```bash +ssh hskwon@114.203.209.83 "mysql -u codebridge -p'...' sam" << 'SQL' +SET FOREIGN_KEY_CHECKS = 0; + +-- FK 경유 테이블 (부모 JOIN 삭제) +DELETE t FROM work_order_items t JOIN work_orders p ON t.work_order_id=p.id WHERE p.tenant_id=287; +DELETE t FROM work_order_bending_details t JOIN work_orders p ON t.work_order_id=p.id WHERE p.tenant_id=287; +DELETE t FROM work_order_issues t JOIN work_orders p ON t.work_order_id=p.id WHERE p.tenant_id=287; +DELETE t FROM shipment_items t JOIN shipments p ON t.shipment_id=p.id WHERE p.tenant_id=287; +DELETE t FROM process_steps t JOIN processes p ON t.process_id=p.id WHERE p.tenant_id=287; +DELETE t FROM process_classification_rules t JOIN processes p ON t.process_id=p.id WHERE p.tenant_id=287; +DELETE t FROM quality_document_orders t JOIN quality_documents p ON t.quality_document_id=p.id WHERE p.tenant_id=287; +DELETE t FROM quality_document_locations t JOIN quality_documents p ON t.quality_document_id=p.id WHERE p.tenant_id=287; +DELETE t FROM performance_reports t JOIN quality_documents p ON t.quality_document_id=p.id WHERE p.tenant_id=287; + +-- direct 테이블 (tenant_id 직접) +DELETE FROM work_order_material_inputs WHERE tenant_id=287; +DELETE FROM work_order_step_progress WHERE tenant_id=287; +DELETE FROM work_order_assignees WHERE tenant_id=287; +DELETE FROM shipment_vehicle_dispatches WHERE tenant_id=287; +DELETE FROM quote_items WHERE tenant_id=287; +DELETE FROM quote_revisions WHERE tenant_id=287; +DELETE FROM order_items WHERE tenant_id=287; +DELETE FROM order_nodes WHERE tenant_id=287; +DELETE FROM stock_lots WHERE tenant_id=287; +DELETE FROM stock_transactions WHERE tenant_id=287; +DELETE FROM numbering_sequences WHERE tenant_id=287; +DELETE FROM files WHERE tenant_id=287; +DELETE FROM work_orders WHERE tenant_id=287; +DELETE FROM shipments WHERE tenant_id=287; +DELETE FROM inspections WHERE tenant_id=287; +DELETE FROM quality_documents WHERE tenant_id=287; +DELETE FROM quotes WHERE tenant_id=287; +DELETE FROM receivings WHERE tenant_id=287; +DELETE FROM sales WHERE tenant_id=287; +DELETE FROM orders WHERE tenant_id=287; +DELETE FROM stocks WHERE tenant_id=287; +DELETE FROM processes WHERE tenant_id=287; +DELETE FROM numbering_rules WHERE tenant_id=287; +DELETE FROM folders WHERE tenant_id=287; +DELETE FROM items WHERE tenant_id=287; +DELETE FROM categories WHERE tenant_id=287; + +SET FOREIGN_KEY_CHECKS = 1; +SQL +``` + +#### 파일 동기화 + +```bash +rsync -avz --delete \ + api/storage/app/tenants/287/ \ + hskwon@114.203.209.83:/home/webservice/api/storage/app/tenants/287/ + +# 권한 복구 +ssh hskwon@114.203.209.83 \ + "sudo chown -R www-data:develop /home/webservice/api/storage/app/tenants/287/" +``` + +--- + +## 4. 주의사항 + +### 4.1 SoftDeletes 처리 + +대상 35개 중 **19개+ 테이블에 SoftDeletes 적용** (Item, Order, WorkOrder, Quote 등). + +- **dump**: `--where="tenant_id=287"`은 soft deleted 포함 → **올바름** (상태 보존) +- **DELETE**: SQL DELETE는 deleted_at과 무관하게 모두 삭제 → **올바름** +- 결과: 로컬의 soft deleted 데이터도 그대로 개발서버에 반영됨 + +### 4.2 안전장치 + +- **FOREIGN_KEY_CHECKS = 0**: DELETE/INSERT 시 FK 제약 임시 해제 +- **tenant_id 필터**: 모든 DELETE에 `WHERE tenant_id = 287` → 다른 테넌트 보호 +- **complete-insert**: ID 값 포함 dump → auto_increment 충돌 방지 +- **order_nodes 자체참조**: FK_CHECKS=0이므로 삽입 순서 무관 + +### 4.3 반복 실행 시 주의 + +- **삭제 → 삽입**: 개발서버에서 직접 추가한 287 데이터는 사라짐 +- 동기화 전 개발서버 보존 필요시 별도 백업 +- 개발서버 DB 비밀번호는 스크립트 내 변수로 관리 (git 제외) + +--- + +## 5. 향후 확장 + +필요시 다음을 추가 가능: +- **mng 웹 UI**: Artisan 커맨드 + Blade 화면 (Docker에 ssh/mysqldump 설치 필요) +- **대상 테이블 추가**: schedules, equipments 등 (데이터 생기면) +- **다중 테넌트**: 287 외 다른 테넌트도 동기화 +- **자동 실행**: cron으로 주기적 동기화 + +--- + +## 변경 로그 + +| 날짜 | 작업 | 비고 | +|------|------|------| +| 2026-03-10 | 최초 작성 | 대상 35개 테이블, 47개 파일 | +| 2026-03-10 | 단순화 | Artisan+웹UI → 셸 스크립트 1개. IP 수정 (211.117.60.189→114.203.209.83). numbering_sequences FK 오류 수정. SoftDeletes 처리 명시. 제외 테이블 보완 | \ No newline at end of file