feat: [contracts] 계약서 버전 관리 시스템 구축
- DOCX 4종 → Markdown 미러링 체계 구축 (Git diff 추적) - DOCX에 개정이력 테이블 삽입 (Pretendard 9pt, 파란 헤더) - 자동화 스크립트 3종 (추출/삽입/동기화 검증) - revisions.json, CHANGELOG.md, INDEX.md 업데이트 - .gitignore에 contracts 경로 allowlist 추가
This commit is contained in:
10
.gitignore
vendored
10
.gitignore
vendored
@@ -14,5 +14,15 @@
|
|||||||
!.claude/agents/
|
!.claude/agents/
|
||||||
!.claude/agents/**
|
!.claude/agents/**
|
||||||
|
|
||||||
|
# sam 문서
|
||||||
|
!sam/
|
||||||
|
sam/*
|
||||||
|
!sam/docs/
|
||||||
|
sam/docs/*
|
||||||
|
!sam/docs/contracts/
|
||||||
|
!sam/docs/contracts/**
|
||||||
|
sam/docs/contracts/docx/backup/
|
||||||
|
!sam/docs/INDEX.md
|
||||||
|
|
||||||
# 기타
|
# 기타
|
||||||
sam/sales
|
sam/sales
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ docs/
|
|||||||
├── features/ # 기능별 상세 문서
|
├── features/ # 기능별 상세 문서
|
||||||
├── projects/ # 프로젝트별 문서 (MES, Legacy)
|
├── projects/ # 프로젝트별 문서 (MES, Legacy)
|
||||||
├── history/ # 히스토리 및 로드맵
|
├── history/ # 히스토리 및 로드맵
|
||||||
|
├── contracts/ # 전자계약서 버전 관리
|
||||||
├── changes/ # 변경 이력
|
├── changes/ # 변경 이력
|
||||||
└── data/ # 데이터 분석
|
└── data/ # 데이터 분석
|
||||||
```
|
```
|
||||||
@@ -125,6 +126,19 @@ docs/
|
|||||||
|------|------|
|
|------|------|
|
||||||
| [analysis/item-db-analysis.md](data/analysis/item-db-analysis.md) | Item DB/API 분석 최종본 |
|
| [analysis/item-db-analysis.md](data/analysis/item-db-analysis.md) | Item DB/API 분석 최종본 |
|
||||||
|
|
||||||
|
### contracts/ - 전자계약서 버전 관리
|
||||||
|
> DOCX 배포본 + Markdown 추적본 + 자동화 스크립트
|
||||||
|
|
||||||
|
| 문서 | 설명 |
|
||||||
|
|------|------|
|
||||||
|
| [CHANGELOG.md](contracts/CHANGELOG.md) | 전체 개정이력 |
|
||||||
|
| [revisions.json](contracts/revisions.json) | 개정 데이터 (스크립트 입력) |
|
||||||
|
| [docx/](contracts/docx/) | DOCX 배포본 (전자서명용 4종) |
|
||||||
|
| [markdown/](contracts/markdown/) | Markdown 추적본 (Git diff용 4종) |
|
||||||
|
| [scripts/extract_to_markdown.py](contracts/scripts/extract_to_markdown.py) | DOCX → Markdown 추출 |
|
||||||
|
| [scripts/insert_revision_table.py](contracts/scripts/insert_revision_table.py) | DOCX 개정이력 테이블 삽입 |
|
||||||
|
| [scripts/sync_check.py](contracts/scripts/sync_check.py) | DOCX ↔ Markdown 동기화 검증 |
|
||||||
|
|
||||||
### features/ - 기능별 문서
|
### features/ - 기능별 문서
|
||||||
|
|
||||||
| 문서 | 설명 |
|
| 문서 | 설명 |
|
||||||
|
|||||||
28
sam/docs/contracts/CHANGELOG.md
Normal file
28
sam/docs/contracts/CHANGELOG.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# 계약서 개정이력
|
||||||
|
|
||||||
|
> **작성일**: 2026-02-22
|
||||||
|
> **관리 대상**: 전자계약 DOCX 4종
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v4.0 (2026-02-22)
|
||||||
|
|
||||||
|
**작성자**: 개발팀
|
||||||
|
|
||||||
|
- 계약서 버전 관리 시스템 도입
|
||||||
|
- DOCX → Markdown 미러링 체계 구축
|
||||||
|
- 4개 전자계약 문서에 개정이력 테이블 삽입
|
||||||
|
- 동기화 검증 스크립트 구축
|
||||||
|
|
||||||
|
### 대상 문서
|
||||||
|
|
||||||
|
| 파일 | 문서명 |
|
||||||
|
|------|--------|
|
||||||
|
| `01_고객_서비스이용계약서_v4_0_전자서명용.docx` | 고객사 서비스 이용계약서 |
|
||||||
|
| `비밀유지서약서.docx` | 비밀유지서약서 (NDA) |
|
||||||
|
| `영업파트너 위촉계약서.docx` | 영업파트너 위촉계약서 |
|
||||||
|
| `영업파트너 위촉계약서(단체용).docx` | 영업파트너 위촉계약서 (단체용) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**최종 업데이트**: 2026-02-22
|
||||||
BIN
sam/docs/contracts/docx/01_고객_서비스이용계약서_v4_0_전자서명용.docx
Executable file
BIN
sam/docs/contracts/docx/01_고객_서비스이용계약서_v4_0_전자서명용.docx
Executable file
Binary file not shown.
BIN
sam/docs/contracts/docx/비밀유지서약서.docx
Executable file
BIN
sam/docs/contracts/docx/비밀유지서약서.docx
Executable file
Binary file not shown.
BIN
sam/docs/contracts/docx/영업파트너 위촉계약서(단체용).docx
Executable file
BIN
sam/docs/contracts/docx/영업파트너 위촉계약서(단체용).docx
Executable file
Binary file not shown.
BIN
sam/docs/contracts/docx/영업파트너 위촉계약서.docx
Executable file
BIN
sam/docs/contracts/docx/영업파트너 위촉계약서.docx
Executable file
Binary file not shown.
424
sam/docs/contracts/markdown/01-service-agreement.md
Normal file
424
sam/docs/contracts/markdown/01-service-agreement.md
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
---
|
||||||
|
title: "고객사 서비스 이용계약서"
|
||||||
|
version: "v4.0"
|
||||||
|
date: "2026-02-22"
|
||||||
|
docx_file: "01_고객_서비스이용계약서_v4_0_전자서명용.docx"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 고객사 서비스 이용계약서
|
||||||
|
|
||||||
|
Customer Service Agreement
|
||||||
|
|
||||||
|
계약번호:
|
||||||
|
계약일:
|
||||||
|
|
||||||
|
본 계약은 주식회사 코드브릿지엑스(이하 “회사”)와 간에 SAM 서비스 제공과 관련하여 다음과 같이 계약을 체결합니다.
|
||||||
|
|
||||||
|
## 제1조 (계약의 목적)
|
||||||
|
|
||||||
|
본 계약은 회사가 고객에게 SAM(Smart MES/ERP Solution) 서비스를 제공함에 있어 필요한 사항을 규정하고, 양측의 권리와 의무를 명확히 함을 목적으로 합니다.
|
||||||
|
|
||||||
|
## 제2조 (용어의 정의)
|
||||||
|
|
||||||
|
- **서비스**: 회사가 제공하는 SAM 클라우드 기반 MES/ERP 솔루션
|
||||||
|
- **SaaS**: Software as a Service (서비스형 소프트웨어)
|
||||||
|
- **서비스 게시**: 개발 완료 후 고객이 서비스에 접근 가능하도록 제공하는 것
|
||||||
|
- **액세스 제공**: 고객에게 서비스 사용 권한을 부여하는 것
|
||||||
|
- **검수 기간**: 서비스 게시 전 고객이 완성도를 확인하는 기간 (최대 1개월)
|
||||||
|
- **하자**: 계약서에 명시된 기능의 오류, 미구현, 성능 미달 등
|
||||||
|
- **하자담보 책임**: 서비스 게시 후 1년간 하자를 무상으로 수정하는 의무
|
||||||
|
|
||||||
|
## 제3조 (서비스 내용)
|
||||||
|
|
||||||
|
### 3.1 서비스 범위
|
||||||
|
|
||||||
|
회사는 다음의 서비스를 제공합니다:
|
||||||
|
- **맞춤형 개발**:
|
||||||
|
- 고객 요구사항에 맞춘 SAM 시스템 개발
|
||||||
|
- 개발 범위: [별첨 기획서 참조]
|
||||||
|
- 개발 기간: 계약일로부터 [ 3 ]개월
|
||||||
|
- **클라우드 제공** (SaaS):
|
||||||
|
- 연중무휴 24시간 접근 가능
|
||||||
|
- 자동 백업 및 보안
|
||||||
|
- **기술 지원**:
|
||||||
|
- 고객센터 운영 (평일 09:00~18:00)
|
||||||
|
- 이메일 지원 (24시간)
|
||||||
|
- 긴급 장애 대응
|
||||||
|
- **하자담보 책임** (1년):
|
||||||
|
- 서비스 게시일로부터 1년간 무상 수정
|
||||||
|
- 버그, 미구현 기능, 성능 개선 등
|
||||||
|
|
||||||
|
### 3.2 제공 방식
|
||||||
|
|
||||||
|
- 회사는 서비스를 **SaaS 방식**으로 제공합니다.
|
||||||
|
- 고객은 서비스에 대한 **사용 권한**만을 부여받으며, 소유권은 회사에 귀속됩니다.
|
||||||
|
- 소스코드는 제공되지 않습니다.
|
||||||
|
|
||||||
|
## 제4조 (비용 및 납부)
|
||||||
|
|
||||||
|
### 4.1 개발비
|
||||||
|
|
||||||
|
| 구분 | 금액 (부가세 별도) | 지급 시기 | 비고 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1차 개발비 | 총 개발비의 50% | 계약 체결 시 | 착수금 |
|
||||||
|
| 2차 개발비 | 총 개발비의 50% | 서비스 게시일로부터 3일 이내 | 잔금 |
|
||||||
|
| 총 개발비 | [ ]원 | | |
|
||||||
|
|
||||||
|
### 4.2 월 구독료
|
||||||
|
|
||||||
|
| 구분 | 금액 (부가세 별도) | 지급 시기 | 비고 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 월 구독료 | 원 ~ | 매월 말일 | 후불제, 사용량 기준 청구 |
|
||||||
|
|
||||||
|
> ⚠️ 중요: - 월 구독료는 원이며, 영업 협상 및 개발 범위에 따라 증액될 수 있습니다.
|
||||||
|
|
||||||
|
- 계약 시 확정된 구독료: [ ]원/월
|
||||||
|
|
||||||
|
### 4.3 납부 방법
|
||||||
|
|
||||||
|
- **개발비**:
|
||||||
|
- 계좌이체 (세금계산서 발행)
|
||||||
|
- 입금 계좌: 기업은행 170-175519-04-011 (주)코드브릿지엑스
|
||||||
|
- **구독료**:
|
||||||
|
- CMS 자동이체 (권장)
|
||||||
|
- 또는 세금계산서 발행 후 계좌이체
|
||||||
|
|
||||||
|
### 4.4 잔금 지급 기한 [법률 검토 반영]
|
||||||
|
|
||||||
|
- **지급 기한**: 서비스 게시일로부터 **3일 이내**
|
||||||
|
- **사전 준비**: 회사는 영업 단계부터 납품 일정을 공유하여 고객이 미리 준비할 수 있도록 합니다.
|
||||||
|
- **미납 시 조치**: 제13조 참조
|
||||||
|
|
||||||
|
## 제5조 (마일스톤 및 진행 일정)
|
||||||
|
|
||||||
|
### 5.1 개발 단계 (5단계 통일)
|
||||||
|
|
||||||
|
| 단계 | 주요 활동 | 진행률 | 기간 | 납부 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| M1 | 요구사항 분석 및 기획 | 20% | [ 2 ]주 | 1차 개발비 (착수금 50%) |
|
||||||
|
| M2 | 설계 및 개발 착수 | 50% | [ 2 ]주 | - |
|
||||||
|
| M3 | 개발 진행 (50% 완료) | 60% | [ 2 ]주 | - |
|
||||||
|
| M4 | 개발 완료 및 테스트 | 80% | [ 2 ]주 | - |
|
||||||
|
| M5 | 검수 및 서비스 게시 | 100% | 최대 2주 | 2차 개발비 (잔금 50%) |
|
||||||
|
|
||||||
|
> ⚠️ 중요: - 5단계 마일스톤으로 통일 관리 - M5 검수 완료 후 서비스 게시 - 서비스 게시일로부터 3일 이내 잔금 납부
|
||||||
|
|
||||||
|
### 5.2 일정 조정
|
||||||
|
|
||||||
|
- 개발 일정은 고객의 협조에 따라 변동될 수 있습니다.
|
||||||
|
- 고객 귀책 사유로 인한 지연은 회사의 책임이 아닙니다.
|
||||||
|
- 불가항력으로 인한 지연 시 양측 협의하여 일정을 조정합니다.
|
||||||
|
|
||||||
|
## 제6조 (서비스 게시 및 검수)
|
||||||
|
|
||||||
|
### 6.1 서비스 게시
|
||||||
|
|
||||||
|
- 회사는 개발 완료 후 고객에게 **서비스 게시**를 통지합니다.
|
||||||
|
- **서비스 게시일**은 고객이 서비스에 접근 가능한 날짜를 의미합니다.
|
||||||
|
- 서비스 게시일부터 구독료가 발생합니다.
|
||||||
|
|
||||||
|
### 6.2 검수 기간
|
||||||
|
|
||||||
|
- 고객은 개발 완료 후 **최대 2주간 검수 기간**을 가집니다.
|
||||||
|
- 검수 기간은 서비스 게시 **전**에 이루어집니다.
|
||||||
|
- 검수 기간 중 발견된 하자는 회사가 무상으로 수정합니다.
|
||||||
|
|
||||||
|
### 6.3 검수 완료
|
||||||
|
|
||||||
|
- 고객이 서면으로 검수 완료를 통지하거나,
|
||||||
|
- 검수 기간 2주 종료 시점에 특별한 이의가 없으면 자동 승인으로 간주합니다.
|
||||||
|
- 검수 완료 후 서비스 게시일이 확정되고, 하자담보 책임 정책이 적용됩니다.
|
||||||
|
|
||||||
|
## 제7조 (하자담보 책임)
|
||||||
|
|
||||||
|
### 7.1 책임 기간
|
||||||
|
|
||||||
|
서비스 게시일로부터 1년 (소프트웨어산업진흥법 제16조, 민법 제667조)
|
||||||
|
|
||||||
|
### 7.2 하자담보 범위 (무상 처리)
|
||||||
|
|
||||||
|
| 항목 | 내용 | 예시 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 버그 수정 | 소프트웨어 오류 | 계산 오류, 기능 미작동 |
|
||||||
|
| 미구현 기능 | 계약서에 명시된 기능 누락 | 약속된 기능 미구현 |
|
||||||
|
| 성능 개선 | 명시된 성능 기준 미달 | 속도 저하, 응답 지연 |
|
||||||
|
| UI/UX 수정 | 사용성 문제 | 버튼 미작동, 화면 깨짐 |
|
||||||
|
| 데이터 오류 | 데이터 손실 또는 오류 | 데이터 삭제, 중복 생성 |
|
||||||
|
| 보안 패치 | 보안 취약점 수정 | 해킹 방지, 암호화 |
|
||||||
|
|
||||||
|
### 7.3 제외 사항 (별도 비용)
|
||||||
|
|
||||||
|
| 항목 | 내용 | 예시 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 신규 기능 개발 | 계약서에 없던 새 기능 | 새로운 모듈, 기능 확장 |
|
||||||
|
| 구조 변경 | 시스템 아키텍처 변경 | DB 구조, 프레임워크 교체 |
|
||||||
|
| 추가 모듈 | 새로운 모듈 개발 | 회계 모듈, 재고 모듈 |
|
||||||
|
| 기획 변경 | 초기 기획과 다른 요구사항 | 화면 구성, 프로세스 변경 |
|
||||||
|
| 교육/컨설팅 | 사용자 교육, 업무 컨설팅 | 직원 교육, 프로세스 개선 |
|
||||||
|
|
||||||
|
### 7.4 하자 처리 절차
|
||||||
|
|
||||||
|
| 단계 | 내용 | 기간 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1. 하자 신고 | 고객이 이메일로 하자 신고 | - |
|
||||||
|
| 2. 하자 확인 | 회사가 하자 여부 판정 | 3영업일 |
|
||||||
|
| 3. 수정 작업 | 하자 인정 시 무상 수정 | 7영업일 |
|
||||||
|
| 4. 검수 완료 | 고객이 수정 사항 확인 | - |
|
||||||
|
|
||||||
|
> ⚠️ 긴급 하자 (서비스 중단)는 24시간 이내 조치합니다.
|
||||||
|
|
||||||
|
### 7.5 책임 면제 사유
|
||||||
|
|
||||||
|
다음의 경우 하자담보 책임이 면제됩니다:
|
||||||
|
- **고객 귀책 사유**:
|
||||||
|
- 고객의 임의 수정 또는 변경
|
||||||
|
- 승인되지 않은 제3자 개입
|
||||||
|
- 사용 환경 미준수
|
||||||
|
- **불가항력**:
|
||||||
|
- 천재지변 (지진, 태풍 등)
|
||||||
|
- 전쟁, 테러, 전염병
|
||||||
|
- 정부 규제 또는 법령 변경
|
||||||
|
- **기간 만료**:
|
||||||
|
- 서비스 게시일로부터 1년 경과
|
||||||
|
|
||||||
|
## 제8조 (계약 해제 및 환불)
|
||||||
|
|
||||||
|
### 8.1 환불 정책 개요
|
||||||
|
|
||||||
|
고객의 임의 해제 권리와 회사의 투입 비용 보전의 균형을 고려하여 수립되었습니다.
|
||||||
|
|
||||||
|
### 8.2 단계별 환불
|
||||||
|
|
||||||
|
### Phase 1: 상담(인터뷰) 시작 전
|
||||||
|
|
||||||
|
- **환불율**: 100% (전액 환불)
|
||||||
|
- **조건**: 계약 후 상담(인터뷰) 배정 전
|
||||||
|
- **위약금**: 없음
|
||||||
|
- **임의 해제 가능**
|
||||||
|
|
||||||
|
### Phase 2: 상담(인터뷰) 시작 후, 개발 착수 전
|
||||||
|
|
||||||
|
| 진행 상황 | 환불율 | 공제 내역 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| M1: 기획안 작성 중 (50% 미만) | 80% | 상담매니저 및 기획/개발자 투입 비용 20% 공제 |
|
||||||
|
| M2: 기획안 완료 (50% 이상) | 50% | 상담매니저 및 기획/개발자 투입 비용 50% 공제 |
|
||||||
|
|
||||||
|
### Phase 3: 개발 진행 중 (5단계 마일스톤 기준)
|
||||||
|
|
||||||
|
| 마일스톤 | 진행률 | 청구 금액(개발비 대비) | 비고 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| M3: 개발 진행 중 (50%) | 70% | 70% | 30% 환불 |
|
||||||
|
| M4: 개발 완료 및 테스트 | 90% | 90% | 10% 환불 |
|
||||||
|
| M5: 서비스 개시 완료 | 100% | 100% | 환불 불가 |
|
||||||
|
|
||||||
|
> ⚠️ 중요: 5단계 마일스톤으로 통일 관리
|
||||||
|
|
||||||
|
### Phase 4: 서비스 게시 후
|
||||||
|
|
||||||
|
- **환불율**: 0% (환불 불가)
|
||||||
|
- **개발비**: 전액 확정, 환불 불가
|
||||||
|
- **구독료**: 매월 말일 후불제이므로 사용한 만큼만 청구 (환불 개념 없음)
|
||||||
|
- **대신 제공**: 하자담보 책임 (1년) + 유지보수 (구독 기간 전체)
|
||||||
|
|
||||||
|
### 8.3 환불 불가 사유
|
||||||
|
|
||||||
|
- **고객 귀책 사유**:
|
||||||
|
- 협조 지연으로 인한 개발 지연
|
||||||
|
- 요구사항 변경으로 인한 추가 개발
|
||||||
|
- 승인 거부 또는 회피
|
||||||
|
- **약관 위반**:
|
||||||
|
- 허위 정보 제공
|
||||||
|
- 부정 사용 또는 재판매
|
||||||
|
- 회사 명예 훼손
|
||||||
|
|
||||||
|
## 제9조 (구독 및 해지)
|
||||||
|
|
||||||
|
### 9.1 구독 시작
|
||||||
|
|
||||||
|
- **시작일**: 서비스 게시일 (검수 완료 후)
|
||||||
|
- **결제일**: 매월 말일
|
||||||
|
- **청구 방식**: 후불제 (해당 월 사용량 기준)
|
||||||
|
- **일할 계산**: (사용 일수 / 해당 월 일수) × 구독료
|
||||||
|
|
||||||
|
> ⚠️ 중요: - 계약 시 확정된 구독료 금액은 [ ]원/월입니다.
|
||||||
|
|
||||||
|
- 매월 말일에 해당 월 사용일수만큼만 후불 청구됩니다.
|
||||||
|
|
||||||
|
### 9.2 구독 해지
|
||||||
|
|
||||||
|
- 고객은 언제든지 구독을 해지할 수 있습니다. (위약금 없음)
|
||||||
|
- 해지 신청 후 30일간 데이터 백업 기간 제공
|
||||||
|
- 해지일로부터 30일 후 모든 데이터 완전 삭제
|
||||||
|
|
||||||
|
## 제10조 (유지보수 정책)
|
||||||
|
|
||||||
|
### 10.1 유지보수 개요
|
||||||
|
|
||||||
|
- **적용 대상**: 구독료를 정상 납부하는 고객
|
||||||
|
- **적용 기간**: 구독 기간 전체 (하자담보 책임 1년 이후에도 구독 중이면 계속 제공)
|
||||||
|
- **비용**: 월 구독료(500,000원)에 포함
|
||||||
|
|
||||||
|
### 10.2 하자담보 책임과의 차이
|
||||||
|
|
||||||
|
| 구분 | 하자담보 책임 (제7조) | 유지보수 (제9조의2) |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 기간 | 서비스 게시일로부터 1년 | 구독 기간 전체 |
|
||||||
|
| 근거 | 법적 의무 (소프트웨어산업진흥법) | 계약 조건 |
|
||||||
|
| 비용 | 무상 | 구독료에 포함 |
|
||||||
|
| 범위 | 하자(버그, 미구현 등) | 하자 + 일반 유지보수 |
|
||||||
|
|
||||||
|
### 10.3 유지보수 범위 (구독료에 포함)
|
||||||
|
|
||||||
|
> ✅ 무상 제공: - 모든 버그 수정 및 오류 처리 - 보안 패치 및 업데이트 - 성능 최적화 - 긴급 장애 대응 (24시간 이내) - 데이터 백업 및 복구 - 기술 지원 (고객센터, 이메일) - 플랫폼 업데이트 (프레임워크, 브라우저 호환성)
|
||||||
|
|
||||||
|
> ❌ 별도 비용: - 신규 기능 개발 - 커스터마이징 및 추가 개발 - 기획 변경 (화면 구성, 프로세스 변경) - 외부 시스템 연동 - 추가 교육 및 컨설팅
|
||||||
|
|
||||||
|
### 10.4 서비스 레벨 (SLA)
|
||||||
|
|
||||||
|
| 심각도 | 상황 | 응답 시간 | 해결 목표 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 긴급 (P0) | 서비스 완전 중단 | 1시간 | 24시간 |
|
||||||
|
| 높음 (P1) | 주요 기능 장애 | 4시간 | 3영업일 |
|
||||||
|
| 보통 (P2) | 일반 버그 | 1영업일 | 7영업일 |
|
||||||
|
| 낮음 (P3) | 문의/안내 | 1영업일 | 3영업일 |
|
||||||
|
|
||||||
|
### 10.5 정기 유지보수
|
||||||
|
|
||||||
|
- **월간**: 보안 패치, 백업 점검 (매월 첫째 주 일요일 새벽)
|
||||||
|
- **분기**: 성능 최적화 (분기 말 일요일 새벽)
|
||||||
|
- **반기**: 시스템 점검 (6월/12월 일요일 새벽)
|
||||||
|
|
||||||
|
> ⚠️ 모든 정기 점검은 최소 7일 전 사전 공지됩니다.
|
||||||
|
|
||||||
|
### 10.6 유지보수 신청
|
||||||
|
|
||||||
|
- **고객센터**: 02-6347-0005 (평일 09:00~18:00 )
|
||||||
|
- **이메일**: support@codebridge-x.com (24시간)
|
||||||
|
- **시스템 내**: SAM 시스템 내 고객지원 메뉴
|
||||||
|
|
||||||
|
### 10.7 유지보수 종료
|
||||||
|
|
||||||
|
다음의 경우 유지보수 서비스가 종료됩니다: 1. 구독 해지 시 2. 구독료 3개월 연속 미납 시 3. 중대한 약관 위반 시
|
||||||
|
|
||||||
|
## 제11조 (고객의 의무)
|
||||||
|
|
||||||
|
고객은 다음 사항을 준수해야 합니다:
|
||||||
|
- **정확한 정보 제공**: 허위 정보 제공 금지
|
||||||
|
- **협조 의무**: 개발에 필요한 자료 및 정보 제공
|
||||||
|
- **부정 사용 금지**: 서비스의 재판매, 재배포 금지
|
||||||
|
- **지적재산권 존중**: 무단 복제, 역설계 금지
|
||||||
|
|
||||||
|
## 제12조 (회사의 의무)
|
||||||
|
|
||||||
|
회사는 다음 사항을 준수합니다:
|
||||||
|
- **서비스 제공**: 계약서에 명시된 서비스 제공
|
||||||
|
- **하자담보 책임**: 1년간 하자 무상 수정
|
||||||
|
- **개인정보 보호**: 개인정보보호법 준수
|
||||||
|
- **기술 지원**: 고객센터 운영 및 기술 지원
|
||||||
|
|
||||||
|
## 제13조 (미입금 시 법적 조치)
|
||||||
|
|
||||||
|
### 13.1 개발비 미입금 절차
|
||||||
|
|
||||||
|
| 단계 | 시점 | 조치 내용 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1차 독촉 | 기한 경과 후 3일 | 이메일 및 SMS 발송 |
|
||||||
|
| 내용증명 | 기한 경과 후 7일 | 우편 발송, 7일 내 입금 요청 |
|
||||||
|
| 추심등 | 기한 경과 후 14일 | 신용정보사 연체 등록, 법률대리인 위임 |
|
||||||
|
| 법적 조치 | 기한 경과 후 30일 | 지급명령 신청 또는 소송 제기 |
|
||||||
|
|
||||||
|
### 13.2 구독료 미입금 절차
|
||||||
|
|
||||||
|
| 단계 | 시점 | 조치 내용 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1차 실패 | 익일 | 재출금 |
|
||||||
|
| 2차 실패 | 기한 경과 후 3일 | 재출금 |
|
||||||
|
| 3차 실패 | 미수금 처리 | 서비스 접근 제한, 1차 독촉 |
|
||||||
|
| 내용증명 | 기한 경과 후 7일 | 우편 발송, 7일 내 입금 요청 |
|
||||||
|
| 서비스 중단 | 기한 경과 후 14일 | 로그인 불가, 데이터 격리 |
|
||||||
|
| 강제 해지 | 기한 경과 후 30일 | 계약 해지, 법적 조치 검토 |
|
||||||
|
|
||||||
|
## 제14조 (개인정보 보호)
|
||||||
|
|
||||||
|
- 회사는 「개인정보 보호법」을 준수합니다.
|
||||||
|
- 고객의 개인정보는 서비스 제공 목적으로만 사용됩니다.
|
||||||
|
- 제3자에게 제공하지 않습니다. (법령 제외)
|
||||||
|
- 계약 종료 시 개인정보는 즉시 삭제됩니다. (법정 보관 의무 제외)
|
||||||
|
|
||||||
|
## 제15조 (지적재산권)
|
||||||
|
|
||||||
|
- **소유권**: 서비스에 대한 모든 지적재산권은 회사에 귀속됩니다.
|
||||||
|
- **사용 권한**: 고객은 서비스 사용 권한만을 부여받습니다.
|
||||||
|
- **금지 사항**: 복제, 배포, 역설계, 재판매 금지
|
||||||
|
|
||||||
|
## 제16조 (손해배상)
|
||||||
|
|
||||||
|
- 회사 또는 고객이 본 계약을 위반하여 상대방에게 손해를 입힌 경우 배상 책임이 있습니다.
|
||||||
|
- 다만, 불가항력으로 인한 손해는 배상 책임에서 제외됩니다.
|
||||||
|
|
||||||
|
## 제17조 (불가항력)
|
||||||
|
|
||||||
|
다음의 사유로 서비스 제공이 불가능한 경우 회사는 책임을 지지 않습니다:
|
||||||
|
- 천재지변 (지진, 태풍, 홍수 등)
|
||||||
|
- 전쟁, 테러, 전염병
|
||||||
|
- 정부 규제 또는 법령 변경
|
||||||
|
- 제3자의 불법 행위 (해킹 등)
|
||||||
|
|
||||||
|
## 제18조 (분쟁 해결)
|
||||||
|
|
||||||
|
- 본 계약과 관련한 분쟁은 상호 협의하여 해결합니다.
|
||||||
|
- 협의가 이루어지지 않을 경우, **서울중앙지방법원**을 관할 법원으로 합니다.
|
||||||
|
|
||||||
|
## 제19조 (계약의 효력)
|
||||||
|
|
||||||
|
- 본 계약은 계약일로부터 효력이 발생합니다.
|
||||||
|
- 본 계약은 구독 해지 시까지 유효합니다.
|
||||||
|
|
||||||
|
## 제20조 (기타)
|
||||||
|
|
||||||
|
- 본 계약서는 2부 작성하여 회사와 고객이 각 1부씩 보관합니다.
|
||||||
|
- 본 계약의 해석 및 적용은 대한민국 법률을 준거법으로 합니다.
|
||||||
|
|
||||||
|
## 계약 당사자
|
||||||
|
|
||||||
|
### [회사]
|
||||||
|
|
||||||
|
상호: 주식회사 코드브릿지엑스
|
||||||
|
대표자: 이의찬
|
||||||
|
사업자등록번호: 664-86-03713
|
||||||
|
주소: 서울특별시 강서구 양천로 583, 우림블루나인 B동 1602호
|
||||||
|
이메일: contact@codebridge-x.com
|
||||||
|
전화: 02-6347-0005
|
||||||
|
서명:
|
||||||
|
날짜:
|
||||||
|
|
||||||
|
### [고객]
|
||||||
|
|
||||||
|
상호:
|
||||||
|
대표자:
|
||||||
|
사업자등록번호:
|
||||||
|
주소:
|
||||||
|
이메일:
|
||||||
|
전화:
|
||||||
|
서명:
|
||||||
|
날짜:
|
||||||
|
|
||||||
|
## 별첨
|
||||||
|
|
||||||
|
### 별첨 1: 기획서
|
||||||
|
|
||||||
|
[별도 첨부]
|
||||||
|
|
||||||
|
### 별첨 2: 개발 일정표
|
||||||
|
|
||||||
|
[별도 첨부]
|
||||||
|
|
||||||
|
### 별첨 3: 기능 명세서
|
||||||
|
|
||||||
|
[별도 첨부]
|
||||||
|
|
||||||
|
주식회사 코드브릿지엑스
|
||||||
|
이메일: contact@codebridge-x.com
|
||||||
|
전화: 02-6347-0005
|
||||||
|
주소: 서울특별시 강서구 양천로 583, 우림블루나인 B동 1602호
|
||||||
|
|
||||||
198
sam/docs/contracts/markdown/02-nda.md
Normal file
198
sam/docs/contracts/markdown/02-nda.md
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
---
|
||||||
|
title: "비밀유지서약서 (NDA)"
|
||||||
|
version: "v4.0"
|
||||||
|
date: "2026-02-22"
|
||||||
|
docx_file: "비밀유지서약서.docx"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 비밀유지서약서 (NDA)
|
||||||
|
|
||||||
|
- **작성일**:
|
||||||
|
|
||||||
|
- **서약인 정보**
|
||||||
|
- **구분**:
|
||||||
|
|
||||||
|
- **인적 사항:**
|
||||||
|
상호(성명): _______________
|
||||||
|
대표자(본인): _______________
|
||||||
|
사업자등록번호(주민등록번호): ____________________
|
||||||
|
주소: ______________________________________________________________________
|
||||||
|
연락처: _______________
|
||||||
|
이메일: _______________
|
||||||
|
|
||||||
|
## 제1조 (목적)
|
||||||
|
|
||||||
|
본 서약서는 주식회사 코드브릿지(이하 “회사”)와의 업무 관계에서 알게 된 기밀 정보를 보호하기 위해 작성되었습니다.
|
||||||
|
|
||||||
|
## 제2조 (기밀 정보의 정의)
|
||||||
|
|
||||||
|
- 다음 각 호의 정보는 회사의 기밀 정보로 간주됩니다:
|
||||||
|
|
||||||
|
### 2.1 고객 정보
|
||||||
|
|
||||||
|
- 고객사 명단 (법인명, 대표자명, 연락처)
|
||||||
|
- 고객사 담당자 정보 (성명, 부서, 연락처, 이메일)
|
||||||
|
- 계약 내역 (가입비, 할인율, 구독료, 특약 사항)
|
||||||
|
- 고객사의 사업 정보 (매출, 직원 수, 거래처 등)
|
||||||
|
- 고객사가 회사에 요구한 개발 내역 및 기획 문서
|
||||||
|
|
||||||
|
### 2.2 영업 정보
|
||||||
|
|
||||||
|
- 가격 정책 (정가, 할인 정책, 최소 가입비)
|
||||||
|
- 수수료 정책 (비율, 지급 기준, 상계 방식)
|
||||||
|
- 영업 전략 및 마케팅 계획
|
||||||
|
- 잠재 고객 리스트
|
||||||
|
- 계약 체결 노하우 및 제안서 템플릿
|
||||||
|
|
||||||
|
### 2.3 기술 정보
|
||||||
|
|
||||||
|
- SAM 시스템의 소스코드
|
||||||
|
- 데이터베이스 구조 및 설계 문서
|
||||||
|
- 개발 프로세스 및 방법론
|
||||||
|
- 서버 인프라 구성 및 보안 정책
|
||||||
|
- API 키, 접속 정보, 관리자 권한
|
||||||
|
|
||||||
|
### 2.4 경영 정보
|
||||||
|
|
||||||
|
- 회사의 재무 정보 (매출, 이익, 원가)
|
||||||
|
- 조직도 및 인사 정보
|
||||||
|
- 사업 계획 및 전략
|
||||||
|
- 투자 유치 및 M&A 관련 정보
|
||||||
|
|
||||||
|
### 2.5 기타
|
||||||
|
|
||||||
|
- 회사가 **“기밀(Confidential)”** 또는 **“대외비”**로 표시한 모든 문서 및 정보
|
||||||
|
|
||||||
|
## 제3조 (기밀 유지 의무)
|
||||||
|
|
||||||
|
### 3.1 기본 의무
|
||||||
|
|
||||||
|
- 본인은 업무 수행 중 알게 된 모든 기밀 정보를:
|
||||||
|
- **외부에 누설하지 않습니다**
|
||||||
|
- **업무 목적 외에 사용하지 않습니다**
|
||||||
|
- **무단으로 복사, 복제, 전송하지 않습니다**
|
||||||
|
- **제3자에게 제공하거나 공개하지 않습니다**
|
||||||
|
|
||||||
|
### 3.2 정보 관리
|
||||||
|
|
||||||
|
- 기밀 문서는 안전한 장소에 보관
|
||||||
|
- 이메일, 메신저 등 전송 시 암호화
|
||||||
|
- 업무 종료 시 모든 기밀 자료 반환 또는 파기
|
||||||
|
- 개인 디바이스에 기밀 정보 저장 금지
|
||||||
|
|
||||||
|
### 3.3 제3자 접근 차단
|
||||||
|
|
||||||
|
- 가족, 친구 등 타인이 기밀 정보에 접근하지 못하도록 조치
|
||||||
|
- 공공장소(카페, 도서관 등)에서 기밀 정보 취급 금지
|
||||||
|
- 비밀번호 및 접속 정보 타인 공유 금지
|
||||||
|
|
||||||
|
## 제4조 (예외 사항)
|
||||||
|
|
||||||
|
- 다음의 정보는 기밀 정보에서 제외됩니다:
|
||||||
|
- 본인이 알기 전에 이미 공개된 정보
|
||||||
|
- 본인의 귀책사유 없이 공개된 정보
|
||||||
|
- 제3자로부터 적법하게 취득한 정보
|
||||||
|
- 본인이 독자적으로 개발한 정보
|
||||||
|
- 법원, 정부기관의 법적 요구에 따라 공개해야 하는 정보 (단, 회사에 사전 통지 필수)
|
||||||
|
|
||||||
|
## 제5조 (의무 기간)
|
||||||
|
|
||||||
|
### 5.1 기간
|
||||||
|
|
||||||
|
- 본 서약서의 기밀 유지 의무는:
|
||||||
|
- **계약 체결일로부터 효력 발생**
|
||||||
|
- **계약 종료 후 2년간 유지**
|
||||||
|
|
||||||
|
### 5.2 영구 보호
|
||||||
|
|
||||||
|
- 단, 다음 정보는 **영구적으로** 보호됩니다:
|
||||||
|
- 고객사 개인정보
|
||||||
|
- 회사의 영업 비밀 (부정경쟁방지법상 영업 비밀)
|
||||||
|
- 기술 정보 (특허, 저작권 대상)
|
||||||
|
|
||||||
|
## 제6조 (위반 시 책임)
|
||||||
|
|
||||||
|
### 6.1 민사 책임
|
||||||
|
|
||||||
|
- 본인이 본 서약을 위반하여 회사 또는 고객에게 손해를 입힌 경우:
|
||||||
|
- **실손해**** 배상**: 실제 발생한 손해 전액
|
||||||
|
- **징벌적 손해배상**: 실손해의 최대 3배 (악의적 유출 시)
|
||||||
|
- **법률 비용**: 소송 비용, 변호사 비용 등
|
||||||
|
|
||||||
|
### 6.2 형사 책임
|
||||||
|
|
||||||
|
- 다음의 경우 형사 고발 대상이 됩니다:
|
||||||
|
- **부정경쟁방지법** 위반 (영업 비밀 침해)
|
||||||
|
- **개인정보보호법** 위반 (고객 정보 유출)
|
||||||
|
- **정보통신망법** 위반 (기술 정보 침해)
|
||||||
|
- **형법** 위반 (업무상 배임)
|
||||||
|
- **※ 형사 처벌: 5년 이하 징역 또는 5천만원 이하 벌금**
|
||||||
|
|
||||||
|
### 6.3 계약 해지
|
||||||
|
|
||||||
|
- 회사는 본 서약 위반 시 즉시 계약을 해지할 수 있으며, 이미 지급한 수수료 또는
|
||||||
|
- 대금을 환수할 수 있습니다.
|
||||||
|
|
||||||
|
## 제7조 (자료 반환)
|
||||||
|
|
||||||
|
### 7.1 반환 대상
|
||||||
|
|
||||||
|
- 계약 종료 또는 요청 시 다음을 즉시 반환해야 합니다:
|
||||||
|
- 회사로부터 제공받은 모든 문서 (종이, 파일)
|
||||||
|
- 고객사 계약서 및 개인정보
|
||||||
|
- 가격표, 제안서, 템플릿 등 영업 자료
|
||||||
|
- USB, 하드디스크 등 저장 매체
|
||||||
|
|
||||||
|
### 7.2 파기 확인
|
||||||
|
|
||||||
|
- 반환 불가능한 파일(이메일, 클라우드 등)은 즉시 삭제하고, **삭제 확인서**를 회사에
|
||||||
|
- 제출해야 합니다.
|
||||||
|
|
||||||
|
## 제8조 (경업 금지)
|
||||||
|
|
||||||
|
### 8.1 경업 금지 기간
|
||||||
|
|
||||||
|
- 계약 종료 후 **6개월간** 다음 행위를 금지합니다:
|
||||||
|
- 회사의 고객에게 경쟁 제품 판매
|
||||||
|
- 회사의 기밀 정보를 이용한 유사 사업
|
||||||
|
- 회사 직원 또는 영업파트너를 스카우트
|
||||||
|
|
||||||
|
### 8.2 예외
|
||||||
|
|
||||||
|
- 단순히 경쟁사 제품을 판매하는 것은 허용되나, 회사의 기밀 정보를 활용해서는
|
||||||
|
- 안 됩니다.
|
||||||
|
|
||||||
|
## 제9조 (분쟁 해결)
|
||||||
|
|
||||||
|
### 9.1 관할 법원
|
||||||
|
|
||||||
|
- 본 서약과 관련된 분쟁은 회사 본사 소재지 관할 법원으로 합니다.
|
||||||
|
|
||||||
|
### 9.2 준거법
|
||||||
|
|
||||||
|
- 본 서약은 대한민국 법률에 따라 해석됩니다.
|
||||||
|
|
||||||
|
- **서약 확인**
|
||||||
|
- 본인은 위 내용을 충분히 이해하였으며, 이를 성실히 준수할 것을 서약합니다.
|
||||||
|
- **서약일**: ___________________
|
||||||
|
- **서약인**
|
||||||
|
상호(성명): _______________
|
||||||
|
대표자(본인): _______________
|
||||||
|
주민등록번호(또는 사업자등록번호): _______________
|
||||||
|
- **서명 또는 인**: _______________
|
||||||
|
|
||||||
|
- **수령인 (주식회사 ****코드브릿지엑스****)**
|
||||||
|
- 대표이사: 이의찬
|
||||||
|
- **확인****일**: ___________________
|
||||||
|
- **서명 또는 인**: _______________
|
||||||
|
|
||||||
|
- **참고: 관련 법률**
|
||||||
|
- **부정경쟁방지법 제2조 (영업비밀)**
|
||||||
|
- “영업비밀”이란 공공연히 알려져 있지 아니하고 독립된 경제적 가치를 가지는 것으로서,
|
||||||
|
- 비밀로 관리된 생산방법, 판매방법, 그 밖에 영업활동에 유용한 기술상 또는 경영상의
|
||||||
|
- 정보를 말한다.
|
||||||
|
- **부정경쟁방지법 제18조 (벌칙)**
|
||||||
|
- 영업비밀을 외국에서 사용하거나 외국에서 사용되게 할 목적으로 취득·사용 또는 제3자에게 누설한 자는 **15년 이하의 징역** 또는 **15억원 이하의 벌금**에 처한다.
|
||||||
|
|
||||||
|
- **※ 본 서약서는 2부를 작성하여 회사와 서약인이 각 1부씩 보관합니다.**
|
||||||
|
- **※ 서약 위반 시 민·형사상 책임을 질 수 있습니다.**
|
||||||
275
sam/docs/contracts/markdown/03-partner-agreement.md
Normal file
275
sam/docs/contracts/markdown/03-partner-agreement.md
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
---
|
||||||
|
title: "영업파트너 위촉계약서"
|
||||||
|
version: "v4.0"
|
||||||
|
date: "2026-02-22"
|
||||||
|
docx_file: "영업파트너 위촉계약서.docx"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 영업파트너 위촉계약서
|
||||||
|
|
||||||
|
*Sales Partner Engagement Agreement*
|
||||||
|
|
||||||
|
- 본 계약은 주식회사 코드브릿지엑스(이하 “회사”)와 (이하 “파트너)간에 SAM 서비스 영업 활동과 관련하여 다음과 같이 위촉계약을 체결합니다.
|
||||||
|
|
||||||
|
## 제1조 (계약의 목적)
|
||||||
|
|
||||||
|
본 계약은 회사와 파트너 간의 영업파트너 위촉 관계를 규정하고, 상호 권리와 의무를 명확히 함을 목적으로 합니다.
|
||||||
|
|
||||||
|
## 제2조 (용어의 정의)
|
||||||
|
|
||||||
|
- **판매자**: 고객을 발굴하고 계약 체결을 주도하는 영업파트너
|
||||||
|
- **관리자**: 판매자를 관리하고 지원하는 상급 영업파트너
|
||||||
|
- **개발비**: 고객이 SAM 서비스 개발을 위해 지급하는 비용
|
||||||
|
- **수수료**: 파트너가 영업 활동의 대가로 받는 보상
|
||||||
|
- **서비스 게시**: 개발 완료 후 고객이 서비스에 접근 가능하도록 제공하는 것
|
||||||
|
|
||||||
|
## 제3조 (파트너의 역할 및 업무)
|
||||||
|
|
||||||
|
### 3.1 판매자의 역할
|
||||||
|
|
||||||
|
- 잠재 고객 발굴 및 초기 접촉
|
||||||
|
- SAM 서비스 소개 및 제안
|
||||||
|
- 고객과의 계약 체결 지원
|
||||||
|
- 계약 후 고객 관리 및 사후 지원
|
||||||
|
|
||||||
|
### 3.2 관리자의 역할
|
||||||
|
|
||||||
|
- 판매자 모집 및 관리
|
||||||
|
- 판매자 교육 및 지원
|
||||||
|
- 영업 전략 수립 및 실행
|
||||||
|
- 회사와 판매자 간 소통 중재
|
||||||
|
|
||||||
|
### 3.3 공통 의무
|
||||||
|
|
||||||
|
- 회사의 브랜드 이미지 유지
|
||||||
|
- 정확한 정보 제공
|
||||||
|
- 윤리적 영업 활동 준수
|
||||||
|
- 비밀 유지 의무
|
||||||
|
|
||||||
|
## 제4조 (수수료 정책)
|
||||||
|
|
||||||
|
### 4.1 수수료 비율
|
||||||
|
|
||||||
|
| 역할 | 수수료 비율 | 산정 기준 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 판매자 | 개발비의 20% | 1차,2차 입금액 기준 |
|
||||||
|
| 관리자 | 개발비의 5% | 1차,2차 입금액 기준 |
|
||||||
|
|
||||||
|
### 4.2 수수료 산정 예시
|
||||||
|
|
||||||
|
- **총 개발비 80,000,000원 계약 시**
|
||||||
|
|
||||||
|
| 단계 | 고객 입금 | 판매자 수수료 (20%) | 관리자 수수료 (5%) |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1차 착수금 (50%) | 40,000,000원 | 8,000,000원 | 2,000,000원 |
|
||||||
|
| 2차 잔금 (50%) | 40,000,000원 | 8,000,000원 | 2,000,000원 |
|
||||||
|
| 총계 | 80,000,000원 | 16,000,000원 | 4,000,000원 |
|
||||||
|
|
||||||
|
- **⚠️ 중요**: 개발비만 수수료 산정 대상이며, 구독료는 수수료 대상이 아닙니다.
|
||||||
|
|
||||||
|
### 4.3 지급 시기
|
||||||
|
|
||||||
|
- **지급일**: 고객 입금일 **익월 10일**
|
||||||
|
- **지급 방식**: 계좌 이체
|
||||||
|
- **세금**: 3.3% 원천징수 (사업소득)
|
||||||
|
|
||||||
|
### 4.4 수수료 지급 조건
|
||||||
|
|
||||||
|
- 고객이 개발비를 실제로 입금한 경우에만 지급
|
||||||
|
- 계약 해지 또는 환불 시 수수료 미지급 또는 환수
|
||||||
|
- 파트너가 계약 위반 시 수수료 지급 보류
|
||||||
|
|
||||||
|
## 제5조 (수수료 정책 변경)
|
||||||
|
|
||||||
|
### 5.1 사전 고지 의무
|
||||||
|
|
||||||
|
- 회사는 수수료 정책을 변경할 경우 **최소 1개월 전** 서면 또는 이메일로 파트너에게 고지합니다.
|
||||||
|
- 수수료 정책을 완전히 폐지하는 경우에도 동일하게 1개월 전 고지합니다.
|
||||||
|
- 고지 기간 중 체결된 계약은 기존 수수료 정책을 적용합니다.
|
||||||
|
|
||||||
|
### 5.2 변경 효력
|
||||||
|
|
||||||
|
- 변경된 수수료 정책은 고지일로부터 **1개월 후** 새로 체결되는 계약부터 적용됩니다.
|
||||||
|
- 고지 기간 만료 전에 체결된 계약은 기존 정책을 따릅니다.
|
||||||
|
- 진행 중인 계약은 최초 약정 조건을 유지합니다.
|
||||||
|
|
||||||
|
### 5.3 변경 예시
|
||||||
|
|
||||||
|
#### 예시 1: 수수료율 변경
|
||||||
|
|
||||||
|
- 고지일: 2026년 2월 1일
|
||||||
|
- 변경 내용: 판매자 수수료 20% → 18%
|
||||||
|
- 적용일: 2026년 3월 1일 이후 체결 계약부터
|
||||||
|
|
||||||
|
#### 예시 2: 수수료 정책 폐지
|
||||||
|
|
||||||
|
- 고지일: 2026년 2월 1일
|
||||||
|
- 변경 내용: 수수료 정책 완전 폐지
|
||||||
|
- 적용일: 2026년 3월 1일 이후 체결 계약부터
|
||||||
|
|
||||||
|
## 제6조 (계약 기간)
|
||||||
|
|
||||||
|
- 본 계약은 계약일로부터 **1년간** 유효합니다.
|
||||||
|
- 양측이 계약 만료 **30일 전**까지 서면으로 해지 의사를 통지하지 않으면 자동으로 **1년 연장**됩니다.
|
||||||
|
- 자동 연장은 동일한 조건으로 반복됩니다.
|
||||||
|
|
||||||
|
## 제7조 (계약 해지)
|
||||||
|
|
||||||
|
### 7.1 일반 해지 (양방향)
|
||||||
|
|
||||||
|
- **통지 기간**: 양측은 **30일 전** 서면 통지로 계약을 해지할 수 있습니다.
|
||||||
|
- **통지 방법**: 이메일 또는 등기우편
|
||||||
|
- **효력 발생**: 통지일로부터 30일 후
|
||||||
|
- **미지급 수수료**: 해지일 이전에 발생한 수수료는 정산하여 지급
|
||||||
|
- **예시**:
|
||||||
|
- 통지일: 2026년 2월 1일
|
||||||
|
- 해지일: 2026년 3월 1일
|
||||||
|
- 2월 중 발생한 수수료는 3월 10일 정상 지급
|
||||||
|
|
||||||
|
### 7.2 즉시 해지 사유
|
||||||
|
|
||||||
|
- 회사는 다음의 경우 **즉시 계약을 해지**할 수 있습니다:
|
||||||
|
- **(1) 품위 유지 결격사유 발생 [신설]**
|
||||||
|
- 음주운전으로 적발된 경우
|
||||||
|
- 형사 범죄로 기소 또는 구속된 경우
|
||||||
|
- 사회적 물의를 일으킨 경우
|
||||||
|
- 기타 파트너로서의 품위를 훼손한 경우
|
||||||
|
- **(2) 계약 위반**
|
||||||
|
- 허위 정보 제공 또는 사기 행위
|
||||||
|
- 회사 명예 훼손 또는 영업 방해
|
||||||
|
- 비밀 유지 의무 위반
|
||||||
|
- 중대한 업무 태만
|
||||||
|
- **(3) 부정 행위**
|
||||||
|
- 고객으로부터 금품 수수
|
||||||
|
- 계약서 위조 또는 변조
|
||||||
|
- 회사 자산 횡령 또는 유용
|
||||||
|
|
||||||
|
### 7.3 즉시 해지 시 조치
|
||||||
|
|
||||||
|
- 미지급 수수료는 지급하지 않습니다.
|
||||||
|
- 이미 지급한 수수료는 환수하지 않습니다. (단, 사기 행위는 예외)
|
||||||
|
- 진행 중인 계약은 회사가 직접 관리합니다.
|
||||||
|
|
||||||
|
## 제8조 (비밀 유지)
|
||||||
|
|
||||||
|
### 8.1 비밀 정보
|
||||||
|
|
||||||
|
- 다음 정보는 비밀로 유지되어야 합니다:
|
||||||
|
- 회사의 영업 전략 및 계획
|
||||||
|
- 고객 정보 (회사명, 담당자, 연락처 등)
|
||||||
|
- 수수료 정책 및 계약 조건
|
||||||
|
- 기술 정보 및 노하우
|
||||||
|
- 회사 내부 자료
|
||||||
|
|
||||||
|
### 8.2 비밀 유지 의무
|
||||||
|
|
||||||
|
- 파트너는 업무 중 알게 된 비밀 정보를 외부에 누설하지 않습니다.
|
||||||
|
- 비밀 유지 의무는 계약 종료 후에도 **3년간** 유효합니다.
|
||||||
|
- 위반 시 손해배상 책임이 있습니다.
|
||||||
|
|
||||||
|
## 제9조 (지적재산권)
|
||||||
|
|
||||||
|
- SAM 서비스에 대한 모든 지적재산권은 회사에 귀속됩니다.
|
||||||
|
- 파트너는 회사의 사전 서면 동의 없이 회사의 상표, 로고, 브랜드를 무단으로 사용할 수 없습니다.
|
||||||
|
- 영업 활동에 필요한 자료는 회사가 제공합니다.
|
||||||
|
|
||||||
|
## 제10조 (세금 및 원천징수)
|
||||||
|
|
||||||
|
### 10.1 사업소득
|
||||||
|
|
||||||
|
- 파트너 수수료는 **사업소득**으로 간주됩니다.
|
||||||
|
|
||||||
|
### 10.2 원천징수
|
||||||
|
|
||||||
|
| 항목 | 비율 | 비고 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 소득세 | 3.0% | |
|
||||||
|
| 지방소득세 | 0.3% | 소득세의 10% |
|
||||||
|
| 합계 | 3.3% | |
|
||||||
|
|
||||||
|
### 10.3 지급명세서
|
||||||
|
|
||||||
|
- 회사는 매월 수수료를 지급한 후에 파트너에게 **지급명세서**를 발급합니다.
|
||||||
|
|
||||||
|
## 제11조 (손해배상)
|
||||||
|
|
||||||
|
### 11.1 파트너의 귀책 사유
|
||||||
|
|
||||||
|
- 파트너가 다음의 행위로 회사에 손해를 입힌 경우 배상 책임이 있습니다:
|
||||||
|
- 허위 정보 제공으로 계약 취소
|
||||||
|
- 고객과의 분쟁으로 회사 명예 훼손
|
||||||
|
- 비밀 유지 의무 위반
|
||||||
|
- 부정 행위
|
||||||
|
|
||||||
|
### 11.2 회사의 귀책 사유
|
||||||
|
|
||||||
|
- 회사가 정당한 사유 없이 수수료를 지급하지 않을 경우, 연체 이자를 더하여 지급합니다.
|
||||||
|
|
||||||
|
## 제12조 (분쟁 해결)
|
||||||
|
|
||||||
|
- 본 계약과 관련한 분쟁은 상호 협의하여 해결합니다.
|
||||||
|
- 협의가 이루어지지 않을 경우, **서울중앙지방법원**을 관할 법원으로 합니다.
|
||||||
|
|
||||||
|
## 제13조 (기타 사항)
|
||||||
|
|
||||||
|
### 13.1 계약서 교부
|
||||||
|
|
||||||
|
- 본 계약서는 2부 작성하여 회사와 파트너가 각 1부씩 보관합니다.
|
||||||
|
|
||||||
|
### 13.2 통지
|
||||||
|
|
||||||
|
- 모든 통지는 다음의 연락처로 발송됩니다:
|
||||||
|
- **회사**:
|
||||||
|
- 이메일: admin@codebridge-x.com
|
||||||
|
- 전화: 02-6347-0005
|
||||||
|
- **파트너**:
|
||||||
|
- 이메일:
|
||||||
|
- 전화:
|
||||||
|
|
||||||
|
### 13.3 준거법
|
||||||
|
|
||||||
|
- 본 계약은 대한민국 법률에 따라 해석되고 적용됩니다.
|
||||||
|
|
||||||
|
- **계약 당사자**
|
||||||
|
- **[회사]**
|
||||||
|
- **상호**: 주식회사 코드브릿지엑스
|
||||||
|
- **대표자**: 이의찬 (인)
|
||||||
|
- **사업자등록번호**: 664-86-03713
|
||||||
|
- **주소**: 서울특별시 강서구 양천로 583, 우림블루나인 B동 1602호
|
||||||
|
- **이메일**:
|
||||||
|
- **전화**: 02-6347-0005
|
||||||
|
- **날짜**:
|
||||||
|
|
||||||
|
- **[파트너]**
|
||||||
|
- **상호/성명**:
|
||||||
|
- **대표자/본인**: (서명)
|
||||||
|
- **사업자등록번호**:
|
||||||
|
- **주소**:
|
||||||
|
- **이메일**:
|
||||||
|
- **전화**:
|
||||||
|
- **날짜**:
|
||||||
|
|
||||||
|
- **별첨**
|
||||||
|
|
||||||
|
#### 별첨 1: 수수료 정산표
|
||||||
|
|
||||||
|
| 계약번호 | 고객사 | 입금일 | 입금액 | 수수료율 | 수수료 | 지급일 |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| | | | | | | |
|
||||||
|
|
||||||
|
#### 별첨 2: 영업 활동 보고서
|
||||||
|
|
||||||
|
| 날짜 | 활동내용 | 고객사 | 진행 상황 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| | | | |
|
||||||
|
|
||||||
|
- 첨부 서류
|
||||||
|
- 사업자등록증 사본 (사업자인 경우)
|
||||||
|
- 주민등록등본 사본 (개인인 경우)
|
||||||
|
- 통장 사본 (수수료 입금용)
|
||||||
|
- 비밀유지서약서
|
||||||
|
|
||||||
|
- **주식회사 코드브릿지엑스**
|
||||||
|
- 이메일: admin@codebridge-x.com
|
||||||
|
- 전화: 02-6347-0005
|
||||||
|
- 주소: 서울특별시 강서구 양천로 583, 우림블루나인 B동 1602호
|
||||||
275
sam/docs/contracts/markdown/04-partner-agreement-group.md
Normal file
275
sam/docs/contracts/markdown/04-partner-agreement-group.md
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
---
|
||||||
|
title: "영업파트너 위촉계약서 (단체용)"
|
||||||
|
version: "v4.0"
|
||||||
|
date: "2026-02-22"
|
||||||
|
docx_file: "영업파트너 위촉계약서(단체용).docx"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 영업파트너 위촉계약서
|
||||||
|
|
||||||
|
*Sales Partner Engagement Agreement*
|
||||||
|
|
||||||
|
- 본 계약은 주식회사 코드브릿지엑스(이하 “회사”)와 (이하 “파트너)간에 SAM 서비스 영업 활동과 관련하여 다음과 같이 위촉계약을 체결합니다.
|
||||||
|
|
||||||
|
## 제1조 (계약의 목적)
|
||||||
|
|
||||||
|
본 계약은 회사와 파트너 간의 영업파트너 위촉 관계를 규정하고, 상호 권리와 의무를 명확히 함을 목적으로 합니다.
|
||||||
|
|
||||||
|
## 제2조 (용어의 정의)
|
||||||
|
|
||||||
|
- **판매자**: 고객을 발굴하고 계약 체결을 주도하는 영업파트너
|
||||||
|
- **관리자**: 판매자를 관리하고 지원하는 상급 영업파트너
|
||||||
|
- **개발비**: 고객이 SAM 서비스 개발을 위해 지급하는 비용
|
||||||
|
- **수수료**: 파트너가 영업 활동의 대가로 받는 보상
|
||||||
|
- **서비스 게시**: 개발 완료 후 고객이 서비스에 접근 가능하도록 제공하는 것
|
||||||
|
|
||||||
|
## 제3조 (파트너의 역할 및 업무)
|
||||||
|
|
||||||
|
### 3.1 판매자의 역할
|
||||||
|
|
||||||
|
- 잠재 고객 발굴 및 초기 접촉
|
||||||
|
- SAM 서비스 소개 및 제안
|
||||||
|
- 고객과의 계약 체결 지원
|
||||||
|
- 계약 후 고객 관리 및 사후 지원
|
||||||
|
|
||||||
|
### 3.2 관리자의 역할
|
||||||
|
|
||||||
|
- 판매자 모집 및 관리
|
||||||
|
- 판매자 교육 및 지원
|
||||||
|
- 영업 전략 수립 및 실행
|
||||||
|
- 회사와 판매자 간 소통 중재
|
||||||
|
|
||||||
|
### 3.3 공통 의무
|
||||||
|
|
||||||
|
- 회사의 브랜드 이미지 유지
|
||||||
|
- 정확한 정보 제공
|
||||||
|
- 윤리적 영업 활동 준수
|
||||||
|
- 비밀 유지 의무
|
||||||
|
|
||||||
|
## 제4조 (수수료 정책)
|
||||||
|
|
||||||
|
### 4.1 수수료 비율
|
||||||
|
|
||||||
|
| 역할 | 수수료 비율 | 산정 기준 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 판매자 | 개발비의 30% | 1차,2차 입금액 기준 |
|
||||||
|
| 관리자 | 개발비의 3% | 1차,2차 입금액 기준 |
|
||||||
|
|
||||||
|
### 4.2 수수료 산정 예시
|
||||||
|
|
||||||
|
- **총 개발비 80,000,000원 계약 시**
|
||||||
|
|
||||||
|
| 단계 | 고객 입금 | 판매자 수수료 (30%) | 관리자 수수료 (3%) |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1차 착수금 (50%) | 40,000,000원 | 12,000,000원 | 1,200,000원 |
|
||||||
|
| 2차 잔금 (50%) | 40,000,000원 | 12,000,000원 | 1,200,000원 |
|
||||||
|
| 총계 | 80,000,000원 | 24,000,000원 | 2,400,000원 |
|
||||||
|
|
||||||
|
- **⚠️ 중요**: 개발비만 수수료 산정 대상이며, 구독료는 수수료 대상이 아닙니다.
|
||||||
|
|
||||||
|
### 4.3 지급 시기
|
||||||
|
|
||||||
|
- **지급일**: 고객 입금일 **익월 10일**
|
||||||
|
- **지급 방식**: 계좌 이체
|
||||||
|
- **세금**: 사업소득일 경우 3.3% 원천징수
|
||||||
|
|
||||||
|
### 4.4 수수료 지급 조건
|
||||||
|
|
||||||
|
- 고객이 개발비를 실제로 입금한 경우에만 지급
|
||||||
|
- 계약 해지 또는 환불 시 수수료 미지급 또는 환수
|
||||||
|
- 파트너가 계약 위반 시 수수료 지급 보류
|
||||||
|
|
||||||
|
## 제5조 (수수료 정책 변경)
|
||||||
|
|
||||||
|
### 5.1 사전 고지 의무
|
||||||
|
|
||||||
|
- 회사는 수수료 정책을 변경할 경우 **최소 1개월 전** 서면 또는 이메일로 파트너에게 고지합니다.
|
||||||
|
- 수수료 정책을 완전히 폐지하는 경우에도 동일하게 1개월 전 고지합니다.
|
||||||
|
- 고지 기간 중 체결된 계약은 기존 수수료 정책을 적용합니다.
|
||||||
|
|
||||||
|
### 5.2 변경 효력
|
||||||
|
|
||||||
|
- 변경된 수수료 정책은 고지일로부터 **1개월 후** 새로 체결되는 계약부터 적용됩니다.
|
||||||
|
- 고지 기간 만료 전에 체결된 계약은 기존 정책을 따릅니다.
|
||||||
|
- 진행 중인 계약은 최초 약정 조건을 유지합니다.
|
||||||
|
|
||||||
|
### 5.3 변경 예시
|
||||||
|
|
||||||
|
#### 예시 1: 수수료율 변경
|
||||||
|
|
||||||
|
- 고지일: 2026년 2월 1일
|
||||||
|
- 변경 내용: 판매자 수수료 20% → 18%
|
||||||
|
- 적용일: 2026년 3월 1일 이후 체결 계약부터
|
||||||
|
|
||||||
|
#### 예시 2: 수수료 정책 폐지
|
||||||
|
|
||||||
|
- 고지일: 2026년 2월 1일
|
||||||
|
- 변경 내용: 수수료 정책 완전 폐지
|
||||||
|
- 적용일: 2026년 3월 1일 이후 체결 계약부터
|
||||||
|
|
||||||
|
## 제6조 (계약 기간)
|
||||||
|
|
||||||
|
- 본 계약은 계약일로부터 **1년간** 유효합니다.
|
||||||
|
- 양측이 계약 만료 **30일 전**까지 서면으로 해지 의사를 통지하지 않으면 자동으로 **1년 연장**됩니다.
|
||||||
|
- 자동 연장은 동일한 조건으로 반복됩니다.
|
||||||
|
|
||||||
|
## 제7조 (계약 해지)
|
||||||
|
|
||||||
|
### 7.1 일반 해지 (양방향)
|
||||||
|
|
||||||
|
- **통지 기간**: 양측은 **30일 전** 서면 통지로 계약을 해지할 수 있습니다.
|
||||||
|
- **통지 방법**: 이메일 또는 등기우편
|
||||||
|
- **효력 발생**: 통지일로부터 30일 후
|
||||||
|
- **미지급 수수료**: 해지일 이전에 발생한 수수료는 정산하여 지급
|
||||||
|
- **예시**:
|
||||||
|
- 통지일: 2026년 2월 1일
|
||||||
|
- 해지일: 2026년 3월 1일
|
||||||
|
- 2월 중 발생한 수수료는 3월 10일 정상 지급
|
||||||
|
|
||||||
|
### 7.2 즉시 해지 사유
|
||||||
|
|
||||||
|
- 회사는 다음의 경우 **즉시 계약을 해지**할 수 있습니다:
|
||||||
|
- **(1) 품위 유지 결격사유 발생 [신설]**
|
||||||
|
- 음주운전으로 적발된 경우
|
||||||
|
- 형사 범죄로 기소 또는 구속된 경우
|
||||||
|
- 사회적 물의를 일으킨 경우
|
||||||
|
- 기타 파트너로서의 품위를 훼손한 경우
|
||||||
|
- **(2) 계약 위반**
|
||||||
|
- 허위 정보 제공 또는 사기 행위
|
||||||
|
- 회사 명예 훼손 또는 영업 방해
|
||||||
|
- 비밀 유지 의무 위반
|
||||||
|
- 중대한 업무 태만
|
||||||
|
- **(3) 부정 행위**
|
||||||
|
- 고객으로부터 금품 수수
|
||||||
|
- 계약서 위조 또는 변조
|
||||||
|
- 회사 자산 횡령 또는 유용
|
||||||
|
|
||||||
|
### 7.3 즉시 해지 시 조치
|
||||||
|
|
||||||
|
- 미지급 수수료는 지급하지 않습니다.
|
||||||
|
- 이미 지급한 수수료는 환수하지 않습니다. (단, 사기 행위는 예외)
|
||||||
|
- 진행 중인 계약은 회사가 직접 관리합니다.
|
||||||
|
|
||||||
|
## 제8조 (비밀 유지)
|
||||||
|
|
||||||
|
### 8.1 비밀 정보
|
||||||
|
|
||||||
|
- 다음 정보는 비밀로 유지되어야 합니다:
|
||||||
|
- 회사의 영업 전략 및 계획
|
||||||
|
- 고객 정보 (회사명, 담당자, 연락처 등)
|
||||||
|
- 수수료 정책 및 계약 조건
|
||||||
|
- 기술 정보 및 노하우
|
||||||
|
- 회사 내부 자료
|
||||||
|
|
||||||
|
### 8.2 비밀 유지 의무
|
||||||
|
|
||||||
|
- 파트너는 업무 중 알게 된 비밀 정보를 외부에 누설하지 않습니다.
|
||||||
|
- 비밀 유지 의무는 계약 종료 후에도 **3년간** 유효합니다.
|
||||||
|
- 위반 시 손해배상 책임이 있습니다.
|
||||||
|
|
||||||
|
## 제9조 (지적재산권)
|
||||||
|
|
||||||
|
- SAM 서비스에 대한 모든 지적재산권은 회사에 귀속됩니다.
|
||||||
|
- 파트너는 회사의 사전 서면 동의 없이 회사의 상표, 로고, 브랜드를 무단으로 사용할 수 없습니다.
|
||||||
|
- 영업 활동에 필요한 자료는 회사가 제공합니다.
|
||||||
|
|
||||||
|
## 제10조 (세금 및 원천징수)
|
||||||
|
|
||||||
|
### 10.1 사업소득
|
||||||
|
|
||||||
|
- 파트너 수수료는 **사업소득**으로 간주됩니다.
|
||||||
|
|
||||||
|
### 10.2 원천징수
|
||||||
|
|
||||||
|
| 항목 | 비율 | 비고 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 소득세 | 3.0% | |
|
||||||
|
| 지방소득세 | 0.3% | 소득세의 10% |
|
||||||
|
| 합계 | 3.3% | |
|
||||||
|
|
||||||
|
### 10.3 지급명세서
|
||||||
|
|
||||||
|
- 회사는 매월 수수료를 지급한 후에 파트너에게 **지급명세서**를 발급합니다.
|
||||||
|
|
||||||
|
## 제11조 (손해배상)
|
||||||
|
|
||||||
|
### 11.1 파트너의 귀책 사유
|
||||||
|
|
||||||
|
- 파트너가 다음의 행위로 회사에 손해를 입힌 경우 배상 책임이 있습니다:
|
||||||
|
- 허위 정보 제공으로 계약 취소
|
||||||
|
- 고객과의 분쟁으로 회사 명예 훼손
|
||||||
|
- 비밀 유지 의무 위반
|
||||||
|
- 부정 행위
|
||||||
|
|
||||||
|
### 11.2 회사의 귀책 사유
|
||||||
|
|
||||||
|
- 회사가 정당한 사유 없이 수수료를 지급하지 않을 경우, 연체 이자를 더하여 지급합니다.
|
||||||
|
|
||||||
|
## 제12조 (분쟁 해결)
|
||||||
|
|
||||||
|
- 본 계약과 관련한 분쟁은 상호 협의하여 해결합니다.
|
||||||
|
- 협의가 이루어지지 않을 경우, **서울중앙지방법원**을 관할 법원으로 합니다.
|
||||||
|
|
||||||
|
## 제13조 (기타 사항)
|
||||||
|
|
||||||
|
### 13.1 계약서 교부
|
||||||
|
|
||||||
|
- 본 계약서는 2부 작성하여 회사와 파트너가 각 1부씩 보관합니다.
|
||||||
|
|
||||||
|
### 13.2 통지
|
||||||
|
|
||||||
|
- 모든 통지는 다음의 연락처로 발송됩니다:
|
||||||
|
- **회사**:
|
||||||
|
- 이메일: admin@codebridge-x.com
|
||||||
|
- 전화: 02-6347-0005
|
||||||
|
- **파트너**:
|
||||||
|
- 이메일:
|
||||||
|
- 전화:
|
||||||
|
|
||||||
|
### 13.3 준거법
|
||||||
|
|
||||||
|
- 본 계약은 대한민국 법률에 따라 해석되고 적용됩니다.
|
||||||
|
|
||||||
|
- **계약 당사자**
|
||||||
|
- **[회사]**
|
||||||
|
- **상호**: 주식회사 코드브릿지엑스
|
||||||
|
- **대표자**: 이의찬 (인)
|
||||||
|
- **사업자등록번호**: 664-86-03713
|
||||||
|
- **주소**: 서울특별시 강서구 양천로 583, 우림블루나인 B동 1602호
|
||||||
|
- **이메일**:
|
||||||
|
- **전화**: 02-6347-0005
|
||||||
|
- **날짜**:
|
||||||
|
|
||||||
|
- **[파트너]**
|
||||||
|
- **상호/성명**:
|
||||||
|
- **대표자/본인**: (서명)
|
||||||
|
- **사업자등록번호**:
|
||||||
|
- **주소**:
|
||||||
|
- **이메일**:
|
||||||
|
- **전화**:
|
||||||
|
- **날짜**:
|
||||||
|
|
||||||
|
- **별첨**
|
||||||
|
|
||||||
|
#### 별첨 1: 수수료 정산표
|
||||||
|
|
||||||
|
| 계약번호 | 고객사 | 입금일 | 입금액 | 수수료율 | 수수료 | 지급일 |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| | | | | | | |
|
||||||
|
|
||||||
|
#### 별첨 2: 영업 활동 보고서
|
||||||
|
|
||||||
|
| 날짜 | 활동내용 | 고객사 | 진행 상황 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| | | | |
|
||||||
|
|
||||||
|
- 첨부 서류
|
||||||
|
- 사업자등록증 사본 (사업자인 경우)
|
||||||
|
- 주민등록등본 사본 (개인인 경우)
|
||||||
|
- 통장 사본 (수수료 입금용)
|
||||||
|
- 비밀유지서약서
|
||||||
|
|
||||||
|
- **주식회사 코드브릿지엑스**
|
||||||
|
- 이메일: admin@codebridge-x.com
|
||||||
|
- 전화: 02-6347-0005
|
||||||
|
- 주소: 서울특별시 강서구 양천로 583, 우림블루나인 B동 1602호
|
||||||
52
sam/docs/contracts/revisions.json
Normal file
52
sam/docs/contracts/revisions.json
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"documents": {
|
||||||
|
"01-service-agreement": {
|
||||||
|
"title": "고객사 서비스 이용계약서",
|
||||||
|
"docx_file": "01_고객_서비스이용계약서_v4_0_전자서명용.docx",
|
||||||
|
"revisions": [
|
||||||
|
{
|
||||||
|
"version": "v4.0",
|
||||||
|
"date": "2026-02-22",
|
||||||
|
"author": "개발팀",
|
||||||
|
"description": "버전 관리 시스템 도입, 개정이력 추적 시작"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"02-nda": {
|
||||||
|
"title": "비밀유지서약서 (NDA)",
|
||||||
|
"docx_file": "비밀유지서약서.docx",
|
||||||
|
"revisions": [
|
||||||
|
{
|
||||||
|
"version": "v4.0",
|
||||||
|
"date": "2026-02-22",
|
||||||
|
"author": "개발팀",
|
||||||
|
"description": "버전 관리 시스템 도입, 개정이력 추적 시작"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"03-partner-agreement": {
|
||||||
|
"title": "영업파트너 위촉계약서",
|
||||||
|
"docx_file": "영업파트너 위촉계약서.docx",
|
||||||
|
"revisions": [
|
||||||
|
{
|
||||||
|
"version": "v4.0",
|
||||||
|
"date": "2026-02-22",
|
||||||
|
"author": "개발팀",
|
||||||
|
"description": "버전 관리 시스템 도입, 개정이력 추적 시작"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"04-partner-agreement-group": {
|
||||||
|
"title": "영업파트너 위촉계약서 (단체용)",
|
||||||
|
"docx_file": "영업파트너 위촉계약서(단체용).docx",
|
||||||
|
"revisions": [
|
||||||
|
{
|
||||||
|
"version": "v4.0",
|
||||||
|
"date": "2026-02-22",
|
||||||
|
"author": "개발팀",
|
||||||
|
"description": "버전 관리 시스템 도입, 개정이력 추적 시작"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
334
sam/docs/contracts/scripts/extract_to_markdown.py
Normal file
334
sam/docs/contracts/scripts/extract_to_markdown.py
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
DOCX → Markdown 추출 스크립트
|
||||||
|
|
||||||
|
4개 전자계약 DOCX 파일을 Markdown으로 변환한다.
|
||||||
|
- 서비스이용계약서: Heading 스타일 기반 매핑
|
||||||
|
- 나머지 3개: Bold 런 + 패턴 매칭으로 구조 유추
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from datetime import date
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from docx import Document
|
||||||
|
|
||||||
|
# 경로 설정
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
DOCX_DIR = BASE_DIR / "docx"
|
||||||
|
MD_DIR = BASE_DIR / "markdown"
|
||||||
|
|
||||||
|
# DOCX → Markdown 매핑
|
||||||
|
FILE_MAP = {
|
||||||
|
"01_고객_서비스이용계약서_v4_0_전자서명용.docx": {
|
||||||
|
"output": "01-service-agreement.md",
|
||||||
|
"title": "고객사 서비스 이용계약서",
|
||||||
|
"type": "styled",
|
||||||
|
},
|
||||||
|
"비밀유지서약서.docx": {
|
||||||
|
"output": "02-nda.md",
|
||||||
|
"title": "비밀유지서약서 (NDA)",
|
||||||
|
"type": "pattern",
|
||||||
|
},
|
||||||
|
"영업파트너 위촉계약서.docx": {
|
||||||
|
"output": "03-partner-agreement.md",
|
||||||
|
"title": "영업파트너 위촉계약서",
|
||||||
|
"type": "pattern",
|
||||||
|
},
|
||||||
|
"영업파트너 위촉계약서(단체용).docx": {
|
||||||
|
"output": "04-partner-agreement-group.md",
|
||||||
|
"title": "영업파트너 위촉계약서 (단체용)",
|
||||||
|
"type": "pattern",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def table_to_markdown(table):
|
||||||
|
"""DOCX 테이블을 Markdown 테이블로 변환"""
|
||||||
|
rows = []
|
||||||
|
for row in table.rows:
|
||||||
|
cells = [cell.text.strip().replace("\n", " ") for cell in row.cells]
|
||||||
|
rows.append(cells)
|
||||||
|
|
||||||
|
if not rows:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
# 헤더
|
||||||
|
lines.append("| " + " | ".join(rows[0]) + " |")
|
||||||
|
lines.append("| " + " | ".join(["---"] * len(rows[0])) + " |")
|
||||||
|
# 본문
|
||||||
|
for row in rows[1:]:
|
||||||
|
# 셀 개수 맞추기
|
||||||
|
while len(row) < len(rows[0]):
|
||||||
|
row.append("")
|
||||||
|
lines.append("| " + " | ".join(row[: len(rows[0])]) + " |")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def get_paragraph_heading_level_styled(para):
|
||||||
|
"""스타일 기반 문서의 헤딩 레벨 판별 (서비스이용계약서)"""
|
||||||
|
style = para.style.name if para.style else ""
|
||||||
|
|
||||||
|
if style == "Heading 1":
|
||||||
|
return 1
|
||||||
|
elif style == "Heading 2":
|
||||||
|
return 2
|
||||||
|
elif style == "Heading 3":
|
||||||
|
return 3
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def get_paragraph_heading_level_pattern(para):
|
||||||
|
"""패턴 매칭 기반 문서의 헤딩 레벨 판별 (비밀유지서약서, 영업파트너 위촉계약서)"""
|
||||||
|
text = para.text.strip()
|
||||||
|
has_bold = any(r.bold for r in para.runs if r.bold)
|
||||||
|
|
||||||
|
if not text or not has_bold:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# "제X조" 패턴 → ## (h2)
|
||||||
|
if re.match(r"^<?[ ]*제\d+조", text):
|
||||||
|
return 2
|
||||||
|
|
||||||
|
# "X.X " 패턴 (소제목) → ### (h3)
|
||||||
|
if re.match(r"^\d+\.\d+\s", text):
|
||||||
|
return 3
|
||||||
|
|
||||||
|
# 문서 제목 (첫 번째 bold 텍스트)
|
||||||
|
if re.match(r"^<?\s*(영업파트너|비밀유지서약서|Sales Partner)", text):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def is_list_item(para, doc_type):
|
||||||
|
"""리스트 아이템인지 판별"""
|
||||||
|
text = para.text.strip()
|
||||||
|
if not text:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if doc_type == "styled":
|
||||||
|
style = para.style.name if para.style else ""
|
||||||
|
return style == "Compact"
|
||||||
|
|
||||||
|
# pattern 기반: bold가 아닌 일반 텍스트이면서 제X조나 X.X 패턴이 아닌 것
|
||||||
|
has_bold = any(r.bold for r in para.runs if r.bold)
|
||||||
|
if not has_bold and not re.match(r"^(제\d+조|<?|계약 당사자|\[)", text):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def extract_styled_doc(doc, file_info):
|
||||||
|
"""스타일 기반 문서 추출 (서비스이용계약서)"""
|
||||||
|
lines = []
|
||||||
|
table_positions = {}
|
||||||
|
|
||||||
|
# 테이블 위치 매핑: 문단 인덱스 기준으로 테이블이 어디에 삽입되는지 추적
|
||||||
|
body = doc.element.body
|
||||||
|
table_idx = 0
|
||||||
|
para_idx = 0
|
||||||
|
for child in body:
|
||||||
|
tag = child.tag.split("}")[-1] if "}" in child.tag else child.tag
|
||||||
|
if tag == "p":
|
||||||
|
para_idx += 1
|
||||||
|
elif tag == "tbl":
|
||||||
|
table_positions[para_idx] = table_idx
|
||||||
|
table_idx += 1
|
||||||
|
|
||||||
|
para_idx = 0
|
||||||
|
for child in body:
|
||||||
|
tag = child.tag.split("}")[-1] if "}" in child.tag else child.tag
|
||||||
|
|
||||||
|
if tag == "p":
|
||||||
|
para = doc.paragraphs[para_idx]
|
||||||
|
para_idx += 1
|
||||||
|
text = para.text.strip()
|
||||||
|
|
||||||
|
if not text:
|
||||||
|
lines.append("")
|
||||||
|
continue
|
||||||
|
|
||||||
|
style = para.style.name if para.style else ""
|
||||||
|
level = get_paragraph_heading_level_styled(para)
|
||||||
|
|
||||||
|
if level > 0:
|
||||||
|
lines.append("")
|
||||||
|
lines.append(f"{'#' * level} {text}")
|
||||||
|
lines.append("")
|
||||||
|
elif style == "Compact":
|
||||||
|
# Bold 런이 있으면 강조 리스트
|
||||||
|
has_bold = any(r.bold for r in para.runs if r.bold)
|
||||||
|
if has_bold:
|
||||||
|
# Bold 부분과 일반 부분 분리
|
||||||
|
parts = []
|
||||||
|
for run in para.runs:
|
||||||
|
if run.bold:
|
||||||
|
parts.append(f"**{run.text}**")
|
||||||
|
else:
|
||||||
|
parts.append(run.text)
|
||||||
|
combined = "".join(parts)
|
||||||
|
lines.append(f"- {combined}")
|
||||||
|
else:
|
||||||
|
# 들여쓰기된 하위 항목
|
||||||
|
lines.append(f" - {text}")
|
||||||
|
elif style in ("Body Text", "First Paragraph"):
|
||||||
|
# 본문 텍스트
|
||||||
|
if text.startswith("⚠️") or text.startswith("✅") or text.startswith("❌"):
|
||||||
|
lines.append("")
|
||||||
|
lines.append(f"> {text}")
|
||||||
|
lines.append("")
|
||||||
|
else:
|
||||||
|
lines.append(text)
|
||||||
|
else:
|
||||||
|
lines.append(text)
|
||||||
|
|
||||||
|
elif tag == "tbl":
|
||||||
|
if table_idx <= len(doc.tables):
|
||||||
|
current_table_idx = sum(
|
||||||
|
1
|
||||||
|
for c in list(body)[: list(body).index(child)]
|
||||||
|
if (c.tag.split("}")[-1] if "}" in c.tag else c.tag) == "tbl"
|
||||||
|
)
|
||||||
|
if current_table_idx < len(doc.tables):
|
||||||
|
lines.append("")
|
||||||
|
lines.append(table_to_markdown(doc.tables[current_table_idx]))
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_pattern_doc(doc, file_info):
|
||||||
|
"""패턴 매칭 기반 문서 추출 (비밀유지서약서, 영업파트너 위촉계약서)"""
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
body = doc.element.body
|
||||||
|
para_idx = 0
|
||||||
|
|
||||||
|
for child in body:
|
||||||
|
tag = child.tag.split("}")[-1] if "}" in child.tag else child.tag
|
||||||
|
|
||||||
|
if tag == "p":
|
||||||
|
para = doc.paragraphs[para_idx]
|
||||||
|
para_idx += 1
|
||||||
|
text = para.text.strip()
|
||||||
|
|
||||||
|
if not text:
|
||||||
|
lines.append("")
|
||||||
|
continue
|
||||||
|
|
||||||
|
level = get_paragraph_heading_level_pattern(para)
|
||||||
|
has_bold = any(r.bold for r in para.runs if r.bold)
|
||||||
|
|
||||||
|
if level > 0:
|
||||||
|
lines.append("")
|
||||||
|
# 제목에서 < > 제거
|
||||||
|
clean_text = re.sub(r"^<\s*|\s*>$", "", text).strip()
|
||||||
|
lines.append(f"{'#' * level} {clean_text}")
|
||||||
|
lines.append("")
|
||||||
|
elif has_bold:
|
||||||
|
# Bold 텍스트는 강조 처리
|
||||||
|
parts = []
|
||||||
|
for run in para.runs:
|
||||||
|
if run.bold:
|
||||||
|
parts.append(f"**{run.text}**")
|
||||||
|
else:
|
||||||
|
parts.append(run.text)
|
||||||
|
combined = "".join(parts)
|
||||||
|
|
||||||
|
# (1), (2) 같은 번호 패턴
|
||||||
|
if re.match(r"^\*\*\(\d+\)", combined):
|
||||||
|
lines.append(f"- {combined}")
|
||||||
|
# "예시 N:", "Phase N:" 같은 패턴
|
||||||
|
elif re.match(r"^\*\*(예시|Phase|별첨)\s", combined):
|
||||||
|
lines.append("")
|
||||||
|
lines.append(f"#### {text}")
|
||||||
|
lines.append("")
|
||||||
|
else:
|
||||||
|
lines.append(f"- {combined}")
|
||||||
|
else:
|
||||||
|
# 일반 텍스트
|
||||||
|
# 빈칸 양식 (___) 유지
|
||||||
|
if "___" in text:
|
||||||
|
lines.append(text)
|
||||||
|
elif re.match(r"^(이메일|전화|주소|상호|대표|사업자|주민|연락처|날짜):", text):
|
||||||
|
lines.append(f"- {text}")
|
||||||
|
else:
|
||||||
|
lines.append(f" - {text}")
|
||||||
|
|
||||||
|
elif tag == "tbl":
|
||||||
|
current_table_idx = sum(
|
||||||
|
1
|
||||||
|
for c in list(body)[: list(body).index(child)]
|
||||||
|
if (c.tag.split("}")[-1] if "}" in c.tag else c.tag) == "tbl"
|
||||||
|
)
|
||||||
|
if current_table_idx < len(doc.tables):
|
||||||
|
lines.append("")
|
||||||
|
lines.append(table_to_markdown(doc.tables[current_table_idx]))
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def add_frontmatter(content, file_info, docx_name):
|
||||||
|
"""YAML 프론트매터 추가"""
|
||||||
|
frontmatter = f"""---
|
||||||
|
title: "{file_info['title']}"
|
||||||
|
version: "v4.0"
|
||||||
|
date: "{date.today().isoformat()}"
|
||||||
|
docx_file: "{docx_name}"
|
||||||
|
---
|
||||||
|
"""
|
||||||
|
return frontmatter + "\n" + content
|
||||||
|
|
||||||
|
|
||||||
|
def extract_file(docx_name, file_info):
|
||||||
|
"""단일 DOCX 파일 추출"""
|
||||||
|
docx_path = DOCX_DIR / docx_name
|
||||||
|
if not docx_path.exists():
|
||||||
|
print(f" [SKIP] {docx_name} - 파일 없음")
|
||||||
|
return False
|
||||||
|
|
||||||
|
doc = Document(str(docx_path))
|
||||||
|
|
||||||
|
if file_info["type"] == "styled":
|
||||||
|
content = extract_styled_doc(doc, file_info)
|
||||||
|
else:
|
||||||
|
content = extract_pattern_doc(doc, file_info)
|
||||||
|
|
||||||
|
# 프론트매터 추가
|
||||||
|
content = add_frontmatter(content, file_info, docx_name)
|
||||||
|
|
||||||
|
# 연속 빈 줄 정리 (3줄 이상 → 2줄로)
|
||||||
|
content = re.sub(r"\n{3,}", "\n\n", content)
|
||||||
|
|
||||||
|
# 파일 저장
|
||||||
|
output_path = MD_DIR / file_info["output"]
|
||||||
|
output_path.write_text(content, encoding="utf-8")
|
||||||
|
print(f" [OK] {docx_name} → {file_info['output']}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("DOCX → Markdown 추출 시작")
|
||||||
|
print(f" DOCX 디렉토리: {DOCX_DIR}")
|
||||||
|
print(f" 출력 디렉토리: {MD_DIR}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
MD_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
success = 0
|
||||||
|
for docx_name, file_info in FILE_MAP.items():
|
||||||
|
if extract_file(docx_name, file_info):
|
||||||
|
success += 1
|
||||||
|
|
||||||
|
print(f"\n완료: {success}/{len(FILE_MAP)} 파일 변환됨")
|
||||||
|
return 0 if success == len(FILE_MAP) else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
348
sam/docs/contracts/scripts/insert_revision_table.py
Normal file
348
sam/docs/contracts/scripts/insert_revision_table.py
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
DOCX 개정이력 테이블 삽입 스크립트
|
||||||
|
|
||||||
|
revisions.json을 읽어 각 DOCX 문서의 제목 직후에 개정이력 테이블을 삽입한다.
|
||||||
|
- 삽입 위치: 문서 제목(첫 번째 Heading 또는 Bold 텍스트) 직후
|
||||||
|
- 스타일: Pretendard 9pt, 연한 파란 헤더, 회색 테두리
|
||||||
|
- 원본 백업 후 삽입
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from docx import Document
|
||||||
|
from docx.enum.table import WD_TABLE_ALIGNMENT
|
||||||
|
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||||
|
from docx.oxml import parse_xml
|
||||||
|
from docx.oxml.ns import nsdecls, qn
|
||||||
|
from docx.shared import Pt, RGBColor
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
DOCX_DIR = BASE_DIR / "docx"
|
||||||
|
BACKUP_DIR = BASE_DIR / "docx" / "backup"
|
||||||
|
REVISIONS_FILE = BASE_DIR / "revisions.json"
|
||||||
|
|
||||||
|
# 스타일 설정
|
||||||
|
FONT_NAME = "Pretendard"
|
||||||
|
FONT_NAME_FALLBACK = "맑은 고딕"
|
||||||
|
FONT_SIZE = Pt(9)
|
||||||
|
HEADER_BG_COLOR = "D6E4F0" # 연한 파란색
|
||||||
|
BORDER_COLOR = "999999" # 회색 테두리
|
||||||
|
HEADER_FONT_COLOR = RGBColor(0x2B, 0x47, 0x6B) # 진한 파란 텍스트
|
||||||
|
|
||||||
|
|
||||||
|
def set_cell_border(cell, **kwargs):
|
||||||
|
"""셀 테두리 설정"""
|
||||||
|
tc = cell._tc
|
||||||
|
tcPr = tc.get_or_add_tcPr()
|
||||||
|
|
||||||
|
tcBorders = parse_xml(
|
||||||
|
f'<w:tcBorders {nsdecls("w")}>'
|
||||||
|
f' <w:top w:val="single" w:sz="4" w:color="{BORDER_COLOR}"/>'
|
||||||
|
f' <w:left w:val="single" w:sz="4" w:color="{BORDER_COLOR}"/>'
|
||||||
|
f' <w:bottom w:val="single" w:sz="4" w:color="{BORDER_COLOR}"/>'
|
||||||
|
f' <w:right w:val="single" w:sz="4" w:color="{BORDER_COLOR}"/>'
|
||||||
|
f"</w:tcBorders>"
|
||||||
|
)
|
||||||
|
tcPr.append(tcBorders)
|
||||||
|
|
||||||
|
|
||||||
|
def set_cell_shading(cell, color):
|
||||||
|
"""셀 배경색 설정"""
|
||||||
|
tc = cell._tc
|
||||||
|
tcPr = tc.get_or_add_tcPr()
|
||||||
|
shading = parse_xml(
|
||||||
|
f'<w:shd {nsdecls("w")} w:fill="{color}" w:val="clear"/>'
|
||||||
|
)
|
||||||
|
tcPr.append(shading)
|
||||||
|
|
||||||
|
|
||||||
|
def set_run_font(run, bold=False):
|
||||||
|
"""런의 폰트 설정"""
|
||||||
|
run.font.size = FONT_SIZE
|
||||||
|
run.font.bold = bold
|
||||||
|
|
||||||
|
# Pretendard 설정 (없으면 맑은 고딕 폴백)
|
||||||
|
run.font.name = FONT_NAME
|
||||||
|
r = run._element
|
||||||
|
rPr = r.get_or_add_rPr()
|
||||||
|
rFonts = parse_xml(
|
||||||
|
f'<w:rFonts {nsdecls("w")} '
|
||||||
|
f'w:ascii="{FONT_NAME}" '
|
||||||
|
f'w:hAnsi="{FONT_NAME}" '
|
||||||
|
f'w:eastAsia="{FONT_NAME}" '
|
||||||
|
f'w:cs="{FONT_NAME_FALLBACK}"/>'
|
||||||
|
)
|
||||||
|
# 기존 rFonts 제거
|
||||||
|
for existing in rPr.findall(qn("w:rFonts")):
|
||||||
|
rPr.remove(existing)
|
||||||
|
rPr.insert(0, rFonts)
|
||||||
|
|
||||||
|
|
||||||
|
def create_revision_table(doc, revisions):
|
||||||
|
"""개정이력 테이블 생성 (Document에 직접 추가하지 않고 XML 요소만 생성)"""
|
||||||
|
# 테이블 생성
|
||||||
|
headers = ["버전", "날짜", "작성자", "변경 내용"]
|
||||||
|
num_cols = len(headers)
|
||||||
|
num_rows = 1 + len(revisions)
|
||||||
|
|
||||||
|
table = doc.add_table(rows=num_rows, cols=num_cols)
|
||||||
|
table.alignment = WD_TABLE_ALIGNMENT.CENTER
|
||||||
|
|
||||||
|
# 헤더 행 설정
|
||||||
|
header_row = table.rows[0]
|
||||||
|
for i, header_text in enumerate(headers):
|
||||||
|
cell = header_row.cells[i]
|
||||||
|
cell.text = ""
|
||||||
|
paragraph = cell.paragraphs[0]
|
||||||
|
paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||||
|
run = paragraph.add_run(header_text)
|
||||||
|
set_run_font(run, bold=True)
|
||||||
|
run.font.color.rgb = HEADER_FONT_COLOR
|
||||||
|
set_cell_shading(cell, HEADER_BG_COLOR)
|
||||||
|
set_cell_border(cell)
|
||||||
|
|
||||||
|
# 데이터 행 설정 (최신 순)
|
||||||
|
sorted_revisions = sorted(revisions, key=lambda r: r["date"], reverse=True)
|
||||||
|
for row_idx, rev in enumerate(sorted_revisions):
|
||||||
|
row = table.rows[row_idx + 1]
|
||||||
|
values = [rev["version"], rev["date"], rev["author"], rev["description"]]
|
||||||
|
for col_idx, value in enumerate(values):
|
||||||
|
cell = row.cells[col_idx]
|
||||||
|
cell.text = ""
|
||||||
|
paragraph = cell.paragraphs[0]
|
||||||
|
paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||||
|
run = paragraph.add_run(value)
|
||||||
|
set_run_font(run)
|
||||||
|
set_cell_border(cell)
|
||||||
|
|
||||||
|
return table
|
||||||
|
|
||||||
|
|
||||||
|
def find_title_paragraph_index(doc, doc_type="pattern"):
|
||||||
|
"""문서 제목 문단의 인덱스를 찾는다"""
|
||||||
|
for i, para in enumerate(doc.paragraphs):
|
||||||
|
text = para.text.strip()
|
||||||
|
if not text:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if doc_type == "styled":
|
||||||
|
# Heading 1 스타일의 첫 번째 문단
|
||||||
|
if para.style and para.style.name == "Heading 1":
|
||||||
|
return i
|
||||||
|
else:
|
||||||
|
# 첫 번째 Bold 텍스트 (제목)
|
||||||
|
has_bold = any(r.bold for r in para.runs if r.bold)
|
||||||
|
if has_bold:
|
||||||
|
return i
|
||||||
|
|
||||||
|
return 0 # 찾지 못하면 맨 앞
|
||||||
|
|
||||||
|
|
||||||
|
def find_subtitle_index(doc, title_idx):
|
||||||
|
"""제목 다음의 부제목(영문 제목 등) 인덱스를 찾는다"""
|
||||||
|
# 제목 바로 다음 문단이 영문 부제목이면 그 다음에 삽입
|
||||||
|
if title_idx + 1 < len(doc.paragraphs):
|
||||||
|
next_para = doc.paragraphs[title_idx + 1]
|
||||||
|
text = next_para.text.strip()
|
||||||
|
if text and any(
|
||||||
|
text.startswith(prefix)
|
||||||
|
for prefix in ["Customer Service", "Sales Partner", "Non-Disclosure"]
|
||||||
|
):
|
||||||
|
return title_idx + 1
|
||||||
|
return title_idx
|
||||||
|
|
||||||
|
|
||||||
|
def insert_table_after_paragraph(doc, para_idx, table):
|
||||||
|
"""특정 문단 인덱스 다음에 테이블을 이동"""
|
||||||
|
body = doc.element.body
|
||||||
|
|
||||||
|
# 빈 문단 추가 (테이블 전 여백)
|
||||||
|
spacer_before = parse_xml(
|
||||||
|
f'<w:p {nsdecls("w")}>'
|
||||||
|
f" <w:pPr><w:spacing w:before=\"120\" w:after=\"120\"/></w:pPr>"
|
||||||
|
f"</w:p>"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 빈 문단 추가 (테이블 후 여백)
|
||||||
|
spacer_after = parse_xml(
|
||||||
|
f'<w:p {nsdecls("w")}>'
|
||||||
|
f' <w:pPr><w:spacing w:before="120" w:after="120"/></w:pPr>'
|
||||||
|
f"</w:p>"
|
||||||
|
)
|
||||||
|
|
||||||
|
# "개정이력" 라벨 문단
|
||||||
|
label_para = parse_xml(
|
||||||
|
f'<w:p {nsdecls("w")}>'
|
||||||
|
f" <w:pPr>"
|
||||||
|
f" <w:jc w:val=\"center\"/>"
|
||||||
|
f' <w:spacing w:before="200" w:after="80"/>'
|
||||||
|
f" </w:pPr>"
|
||||||
|
f" <w:r>"
|
||||||
|
f" <w:rPr>"
|
||||||
|
f' <w:rFonts w:ascii="{FONT_NAME}" w:hAnsi="{FONT_NAME}" '
|
||||||
|
f' w:eastAsia="{FONT_NAME}" w:cs="{FONT_NAME_FALLBACK}"/>'
|
||||||
|
f' <w:sz w:val="18"/>'
|
||||||
|
f' <w:szCs w:val="18"/>'
|
||||||
|
f" <w:b/>"
|
||||||
|
f' <w:color w:val="666666"/>'
|
||||||
|
f" </w:rPr>"
|
||||||
|
f" <w:t>[ 개정이력 ]</w:t>"
|
||||||
|
f" </w:r>"
|
||||||
|
f"</w:p>"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 대상 문단의 XML 요소 찾기
|
||||||
|
para_elements = body.findall(qn("w:p"))
|
||||||
|
if para_idx >= len(para_elements):
|
||||||
|
para_idx = len(para_elements) - 1
|
||||||
|
|
||||||
|
target_para = para_elements[para_idx]
|
||||||
|
|
||||||
|
# 테이블 XML 요소 (이미 doc에 추가되어 body 끝에 있음)
|
||||||
|
table_element = table._tbl
|
||||||
|
|
||||||
|
# body에서 테이블 제거 (끝에서)
|
||||||
|
body.remove(table_element)
|
||||||
|
|
||||||
|
# 대상 문단 다음에 삽입 (역순으로 삽입)
|
||||||
|
target_para.addnext(spacer_after)
|
||||||
|
target_para.addnext(table_element)
|
||||||
|
target_para.addnext(label_para)
|
||||||
|
target_para.addnext(spacer_before)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_existing_revision_table(doc):
|
||||||
|
"""기존 개정이력 테이블이 있으면 제거"""
|
||||||
|
body = doc.element.body
|
||||||
|
|
||||||
|
# "[ 개정이력 ]" 라벨 문단 찾기
|
||||||
|
for para in body.findall(qn("w:p")):
|
||||||
|
texts = para.findall(f".//{qn('w:t')}")
|
||||||
|
full_text = "".join(t.text or "" for t in texts)
|
||||||
|
if "개정이력" in full_text:
|
||||||
|
# 이 문단과 바로 다음의 테이블, 그리고 전후 spacer 제거
|
||||||
|
siblings = list(body)
|
||||||
|
idx = siblings.index(para)
|
||||||
|
|
||||||
|
# 이전 spacer (빈 문단)
|
||||||
|
if idx > 0:
|
||||||
|
prev = siblings[idx - 1]
|
||||||
|
prev_tag = prev.tag.split("}")[-1] if "}" in prev.tag else prev.tag
|
||||||
|
if prev_tag == "p":
|
||||||
|
prev_texts = prev.findall(f".//{qn('w:t')}")
|
||||||
|
prev_full = "".join(t.text or "" for t in prev_texts)
|
||||||
|
if not prev_full.strip():
|
||||||
|
body.remove(prev)
|
||||||
|
siblings = list(body)
|
||||||
|
idx = siblings.index(para)
|
||||||
|
|
||||||
|
# 라벨 문단 다음의 테이블
|
||||||
|
if idx + 1 < len(siblings):
|
||||||
|
next_elem = siblings[idx + 1]
|
||||||
|
next_tag = (
|
||||||
|
next_elem.tag.split("}")[-1]
|
||||||
|
if "}" in next_elem.tag
|
||||||
|
else next_elem.tag
|
||||||
|
)
|
||||||
|
if next_tag == "tbl":
|
||||||
|
body.remove(next_elem)
|
||||||
|
siblings = list(body)
|
||||||
|
|
||||||
|
# 테이블 다음 spacer
|
||||||
|
if idx + 1 < len(siblings):
|
||||||
|
after = siblings[idx + 1]
|
||||||
|
after_tag = (
|
||||||
|
after.tag.split("}")[-1]
|
||||||
|
if "}" in after.tag
|
||||||
|
else after.tag
|
||||||
|
)
|
||||||
|
if after_tag == "p":
|
||||||
|
after_texts = after.findall(f".//{qn('w:t')}")
|
||||||
|
after_full = "".join(t.text or "" for t in after_texts)
|
||||||
|
if not after_full.strip():
|
||||||
|
body.remove(after)
|
||||||
|
|
||||||
|
# 라벨 문단 제거
|
||||||
|
body.remove(para)
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def process_document(docx_name, doc_info):
|
||||||
|
"""단일 DOCX에 개정이력 테이블 삽입"""
|
||||||
|
docx_path = DOCX_DIR / docx_name
|
||||||
|
if not docx_path.exists():
|
||||||
|
print(f" [SKIP] {docx_name} - 파일 없음")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 백업
|
||||||
|
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
backup_path = BACKUP_DIR / docx_name
|
||||||
|
shutil.copy2(docx_path, backup_path)
|
||||||
|
print(f" [BACKUP] {docx_name} → backup/")
|
||||||
|
|
||||||
|
doc = Document(str(docx_path))
|
||||||
|
|
||||||
|
# 기존 개정이력 테이블 제거
|
||||||
|
if remove_existing_revision_table(doc):
|
||||||
|
print(f" [INFO] 기존 개정이력 테이블 제거됨")
|
||||||
|
|
||||||
|
# 문서 유형 판별
|
||||||
|
has_heading_styles = any(
|
||||||
|
p.style and p.style.name.startswith("Heading")
|
||||||
|
for p in doc.paragraphs
|
||||||
|
)
|
||||||
|
doc_type = "styled" if has_heading_styles else "pattern"
|
||||||
|
|
||||||
|
# 제목 위치 찾기
|
||||||
|
title_idx = find_title_paragraph_index(doc, doc_type)
|
||||||
|
# 부제목(영문 제목) 확인
|
||||||
|
insert_after_idx = find_subtitle_index(doc, title_idx)
|
||||||
|
|
||||||
|
# 테이블 생성
|
||||||
|
table = create_revision_table(doc, doc_info["revisions"])
|
||||||
|
|
||||||
|
# 테이블 삽입
|
||||||
|
insert_table_after_paragraph(doc, insert_after_idx, table)
|
||||||
|
|
||||||
|
# 저장
|
||||||
|
doc.save(str(docx_path))
|
||||||
|
print(f" [OK] {docx_name} - 개정이력 테이블 삽입 완료")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("DOCX 개정이력 테이블 삽입 시작")
|
||||||
|
print(f" DOCX 디렉토리: {DOCX_DIR}")
|
||||||
|
print(f" 개정 데이터: {REVISIONS_FILE}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# revisions.json 로드
|
||||||
|
if not REVISIONS_FILE.exists():
|
||||||
|
print(f"[ERROR] {REVISIONS_FILE} 파일을 찾을 수 없습니다.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
with open(REVISIONS_FILE, "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
documents = data.get("documents", {})
|
||||||
|
|
||||||
|
success = 0
|
||||||
|
for doc_key, doc_info in documents.items():
|
||||||
|
docx_name = doc_info["docx_file"]
|
||||||
|
print(f"처리 중: {doc_info['title']}")
|
||||||
|
if process_document(docx_name, doc_info):
|
||||||
|
success += 1
|
||||||
|
print()
|
||||||
|
|
||||||
|
print(f"완료: {success}/{len(documents)} 파일 처리됨")
|
||||||
|
return 0 if success == len(documents) else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
255
sam/docs/contracts/scripts/sync_check.py
Normal file
255
sam/docs/contracts/scripts/sync_check.py
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
DOCX ↔ Markdown 동기화 검증 스크립트
|
||||||
|
|
||||||
|
DOCX에서 텍스트를 추출하고 Markdown 파일의 텍스트와 비교하여
|
||||||
|
불일치 항목을 리포트한다.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import difflib
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from docx import Document
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
DOCX_DIR = BASE_DIR / "docx"
|
||||||
|
MD_DIR = BASE_DIR / "markdown"
|
||||||
|
|
||||||
|
# DOCX → Markdown 파일 매핑
|
||||||
|
FILE_MAP = {
|
||||||
|
"01_고객_서비스이용계약서_v4_0_전자서명용.docx": "01-service-agreement.md",
|
||||||
|
"비밀유지서약서.docx": "02-nda.md",
|
||||||
|
"영업파트너 위촉계약서.docx": "03-partner-agreement.md",
|
||||||
|
"영업파트너 위촉계약서(단체용).docx": "04-partner-agreement-group.md",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def extract_text_from_docx(docx_path):
|
||||||
|
"""DOCX에서 순수 텍스트만 추출 (개정이력 테이블 제외, 인터리빙 방식)"""
|
||||||
|
doc = Document(str(docx_path))
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
from docx.oxml.ns import qn as _qn
|
||||||
|
|
||||||
|
body = doc.element.body
|
||||||
|
para_idx = 0
|
||||||
|
table_idx = 0
|
||||||
|
skip_revision = False
|
||||||
|
|
||||||
|
for child in body:
|
||||||
|
tag = child.tag.split("}")[-1] if "}" in child.tag else child.tag
|
||||||
|
|
||||||
|
if tag == "p":
|
||||||
|
if para_idx < len(doc.paragraphs):
|
||||||
|
text = doc.paragraphs[para_idx].text.strip()
|
||||||
|
para_idx += 1
|
||||||
|
|
||||||
|
if "개정이력" in text:
|
||||||
|
skip_revision = True
|
||||||
|
continue
|
||||||
|
if text:
|
||||||
|
skip_revision = False
|
||||||
|
lines.append(text)
|
||||||
|
|
||||||
|
elif tag == "tbl":
|
||||||
|
if table_idx < len(doc.tables):
|
||||||
|
table = doc.tables[table_idx]
|
||||||
|
table_idx += 1
|
||||||
|
|
||||||
|
# 개정이력 테이블 건너뛰기
|
||||||
|
if len(table.rows) > 0:
|
||||||
|
first_row_text = [cell.text.strip() for cell in table.rows[0].cells]
|
||||||
|
if "버전" in first_row_text and "날짜" in first_row_text:
|
||||||
|
skip_revision = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
if skip_revision:
|
||||||
|
skip_revision = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
for row in table.rows:
|
||||||
|
row_text = " | ".join(cell.text.strip() for cell in row.cells)
|
||||||
|
if row_text.strip():
|
||||||
|
lines.append(row_text)
|
||||||
|
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def extract_text_from_markdown(md_path):
|
||||||
|
"""Markdown에서 순수 텍스트만 추출 (프론트매터, 마크업 제거)"""
|
||||||
|
content = md_path.read_text(encoding="utf-8")
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
in_frontmatter = False
|
||||||
|
in_table = False
|
||||||
|
|
||||||
|
for line in content.split("\n"):
|
||||||
|
stripped = line.strip()
|
||||||
|
|
||||||
|
# YAML 프론트매터 건너뛰기
|
||||||
|
if stripped == "---":
|
||||||
|
in_frontmatter = not in_frontmatter
|
||||||
|
continue
|
||||||
|
if in_frontmatter:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 빈 줄 건너뛰기
|
||||||
|
if not stripped:
|
||||||
|
in_table = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Markdown 마크업 제거
|
||||||
|
text = stripped
|
||||||
|
|
||||||
|
# 헤딩 마크업 제거
|
||||||
|
text = re.sub(r"^#{1,6}\s+", "", text)
|
||||||
|
|
||||||
|
# 리스트 마크업 제거
|
||||||
|
text = re.sub(r"^\s*[-*+]\s+", "", text)
|
||||||
|
|
||||||
|
# Bold/Italic 마크업 제거
|
||||||
|
text = re.sub(r"\*\*(.+?)\*\*", r"\1", text)
|
||||||
|
text = re.sub(r"\*(.+?)\*", r"\1", text)
|
||||||
|
|
||||||
|
# 블록인용 제거
|
||||||
|
text = re.sub(r"^>\s*", "", text)
|
||||||
|
|
||||||
|
# 테이블 구분선 건너뛰기
|
||||||
|
if re.match(r"^\|[\s\-|]+\|$", text):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 테이블 행
|
||||||
|
if text.startswith("|") and text.endswith("|"):
|
||||||
|
# 파이프 제거하고 셀 텍스트 추출
|
||||||
|
cells = [c.strip() for c in text.strip("|").split("|")]
|
||||||
|
text = " | ".join(cells)
|
||||||
|
|
||||||
|
text = text.strip()
|
||||||
|
if text:
|
||||||
|
lines.append(text)
|
||||||
|
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_text(text):
|
||||||
|
"""비교를 위한 텍스트 정규화"""
|
||||||
|
# 공백 정규화
|
||||||
|
text = re.sub(r"\s+", " ", text).strip()
|
||||||
|
# 특수문자 정규화
|
||||||
|
text = text.replace("\u00a0", " ") # non-breaking space
|
||||||
|
text = text.replace("\u3000", " ") # ideographic space
|
||||||
|
# 언더스코어 빈칸 정규화
|
||||||
|
text = re.sub(r"_{3,}", "___", text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def compare_documents(docx_name, md_name):
|
||||||
|
"""두 문서의 텍스트를 비교"""
|
||||||
|
docx_path = DOCX_DIR / docx_name
|
||||||
|
md_path = MD_DIR / md_name
|
||||||
|
|
||||||
|
if not docx_path.exists():
|
||||||
|
return {"status": "error", "message": f"DOCX 파일 없음: {docx_name}"}
|
||||||
|
if not md_path.exists():
|
||||||
|
return {"status": "error", "message": f"Markdown 파일 없음: {md_name}"}
|
||||||
|
|
||||||
|
docx_lines = [normalize_text(l) for l in extract_text_from_docx(docx_path) if l.strip()]
|
||||||
|
md_lines = [normalize_text(l) for l in extract_text_from_markdown(md_path) if l.strip()]
|
||||||
|
|
||||||
|
# difflib로 비교
|
||||||
|
matcher = difflib.SequenceMatcher(None, docx_lines, md_lines)
|
||||||
|
ratio = matcher.ratio()
|
||||||
|
|
||||||
|
# 차이점 추출
|
||||||
|
diffs = []
|
||||||
|
for tag, i1, i2, j1, j2 in matcher.get_opcodes():
|
||||||
|
if tag == "equal":
|
||||||
|
continue
|
||||||
|
elif tag == "replace":
|
||||||
|
for idx in range(max(i2 - i1, j2 - j1)):
|
||||||
|
docx_text = docx_lines[i1 + idx] if i1 + idx < i2 else "(없음)"
|
||||||
|
md_text = md_lines[j1 + idx] if j1 + idx < j2 else "(없음)"
|
||||||
|
diffs.append({
|
||||||
|
"type": "변경",
|
||||||
|
"docx": docx_text[:80],
|
||||||
|
"markdown": md_text[:80],
|
||||||
|
})
|
||||||
|
elif tag == "delete":
|
||||||
|
for idx in range(i1, i2):
|
||||||
|
diffs.append({
|
||||||
|
"type": "DOCX에만 존재",
|
||||||
|
"docx": docx_lines[idx][:80],
|
||||||
|
"markdown": "-",
|
||||||
|
})
|
||||||
|
elif tag == "insert":
|
||||||
|
for idx in range(j1, j2):
|
||||||
|
diffs.append({
|
||||||
|
"type": "Markdown에만 존재",
|
||||||
|
"docx": "-",
|
||||||
|
"markdown": md_lines[idx][:80],
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "ok",
|
||||||
|
"similarity": round(ratio * 100, 1),
|
||||||
|
"docx_lines": len(docx_lines),
|
||||||
|
"md_lines": len(md_lines),
|
||||||
|
"diff_count": len(diffs),
|
||||||
|
"diffs": diffs[:20], # 상위 20개만
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("=" * 70)
|
||||||
|
print("DOCX ↔ Markdown 동기화 검증")
|
||||||
|
print("=" * 70)
|
||||||
|
|
||||||
|
all_ok = True
|
||||||
|
|
||||||
|
for docx_name, md_name in FILE_MAP.items():
|
||||||
|
print(f"\n{'─' * 50}")
|
||||||
|
print(f"문서: {docx_name}")
|
||||||
|
print(f" ↔ {md_name}")
|
||||||
|
print(f"{'─' * 50}")
|
||||||
|
|
||||||
|
result = compare_documents(docx_name, md_name)
|
||||||
|
|
||||||
|
if result["status"] == "error":
|
||||||
|
print(f" [ERROR] {result['message']}")
|
||||||
|
all_ok = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
similarity = result["similarity"]
|
||||||
|
status_icon = "OK" if similarity >= 80 else "WARN" if similarity >= 60 else "FAIL"
|
||||||
|
|
||||||
|
print(f" 유사도: {similarity}% [{status_icon}]")
|
||||||
|
print(f" DOCX 라인: {result['docx_lines']}")
|
||||||
|
print(f" Markdown 라인: {result['md_lines']}")
|
||||||
|
print(f" 차이점: {result['diff_count']}개")
|
||||||
|
|
||||||
|
if result["diffs"]:
|
||||||
|
print(f"\n 주요 차이점 (상위 {min(len(result['diffs']), 10)}개):")
|
||||||
|
for i, diff in enumerate(result["diffs"][:10]):
|
||||||
|
print(f" [{diff['type']}]")
|
||||||
|
if diff["docx"] != "-":
|
||||||
|
print(f" DOCX: {diff['docx']}")
|
||||||
|
if diff["markdown"] != "-":
|
||||||
|
print(f" MD: {diff['markdown']}")
|
||||||
|
|
||||||
|
if similarity < 80:
|
||||||
|
all_ok = False
|
||||||
|
|
||||||
|
print(f"\n{'=' * 70}")
|
||||||
|
if all_ok:
|
||||||
|
print("결과: 모든 문서 동기화 상태 양호")
|
||||||
|
else:
|
||||||
|
print("결과: 일부 문서에서 불일치 발견 - 확인 필요")
|
||||||
|
print(f"{'=' * 70}")
|
||||||
|
|
||||||
|
return 0 if all_ok else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
Reference in New Issue
Block a user