Files
pbl02/scripts/generate_docs_and_samples.py
T
2026-10-05 19:47:55 +09:00

160 lines
9.0 KiB
Python

import os
import json
import yaml
base = r"d:/edunlab/milicontent2/uploads/DAT10"
# ==========================================
# 1. docs/dat10_data_spec.md
# ==========================================
data_spec_md = """# DAT10: 데이터 마이닝 기반 공급망 재난 식별 및 야전 군수 재고 관리 데이터/시스템 명세서
## 1. 개요 및 배경
- **프로젝트 ID:** DAT10
- **과제명:** 데이터 마이닝 기반 공급망 재난 식별 SaaS (방산 공급망 회복력 및 전술 통신 두절 환경 대응)
- **배경 환경:** 미국 방위산업기반(Defense Industrial Base, DIB) 공급망 회복력 분석 및 적 전자전(EW)/통신 두절 하 최전방 야전 부대 재고 자립 관리
- **목표:**
1. 통신 단절(오프라인) 상태에서 단말 간 독립적 군수 트랜잭션 처리 및 SHA-256 해시체인 무결성 보장
2. 네트워크 복구 시 CRDT (Conflict-free Replicated Data Types) 기반 무손실·무충돌 양방향 동기화
3. 다차원 데이터마이닝(비지도 이상치 탐지 및 다변량 규칙 앙상블)을 통한 방산 공급망 재난 조기 식별
4. 군수관/지휘관 개입(HITL) 3단계 수동 병합 결심 체계 및 전술 모바일/웹 SaaS 대시보드 구축
---
## 2. 시스템 아키텍처 및 데이터 흐름
```
[전방 야전 단말 (Offline)] ──(P2P / USB 동기화)──▶ [인접 단말 (Offline)]
│
(해시체인 무결성 기록)
│
[네트워크 복구 (EW 해제)]
│
▼
[CRDT 동기화 엔진 (LWW-Element-Set)] ──▶ [신뢰도 평가 & 위변조 검증 엔진 (SHA-256 / Merkle)]
│
▼
[데이터마이닝 공급망 재난 탐지기] ────▶ [Streamlit 전술 대시보드 UI]
│ │
▼ ▼
[이상 징후 / 동기화 충돌] ──────────────▶ [군수관 HITL 승인 및 사후 AAR 튜닝]
```
---
## 3. 로컬 SQLite 데이터베이스 명세
### 3.1 `inventory_items` (마스터 재고)
| 필드명 | 타입 | 제약조건 | 설명 |
| :--- | :--- | :--- | :--- |
| `nsn_code` | TEXT | PRIMARY KEY | 국가재고번호 (예: 1005-01-123-4567) |
| `item_name` | TEXT | NOT NULL | 품목명 (예: 5.56mm K2 보통탄, K9 유압밸브) |
| `supply_class` | TEXT | NOT NULL | 보급분류 (Class I ~ Class IX) |
| `criticality_level` | TEXT | CHECK | 전략 중요도 (CRITICAL, HIGH, NORMAL, LOW) |
| `unit_cost` | REAL | NOT NULL | 조달 단가 (USD) |
| `safety_stock_threshold` | INTEGER | NOT NULL | 안전 재고 기준선 |
| `total_local_stock` | INTEGER | NOT NULL | 로컬 현재 재고 |
| `crdt_clock` | INTEGER | NOT NULL | CRDT 상태 버전 클록 |
| `updated_at_utc` | TEXT | NOT NULL | 갱신 일시 (ISO-8601) |
### 3.2 `offline_transactions` (오프라인 수불 로그 & 해시체인)
| 필드명 | 타입 | 제약조건 | 설명 |
| :--- | :--- | :--- | :--- |
| `transaction_id` | TEXT | PRIMARY KEY | 고유 트랜잭션 번호 (TX-XXXX) |
| `terminal_id` | TEXT | NOT NULL | 단말 식별자 (TERM-XXXX) |
| `unit_id` | TEXT | NOT NULL | 부대 기호 (BN-01, BDE-03 등) |
| `nsn_code` | TEXT | FOREIGN KEY | 재고 품목 코드 |
| `tx_type` | TEXT | NOT NULL | 수불유형 (RECEIPT, ISSUE, TRANSFER 등) |
| `quantity` | INTEGER | > 0 | 변동 수량 |
| `stock_after` | INTEGER | >= 0 | 변동 후 잔여 수량 |
| `comms_status` | TEXT | NOT NULL | OFFLINE_LOCAL, DEGRADED_EW, ONLINE |
| `grid_coords` | TEXT | - | MGRS 좌표 |
| `weather_condition` | TEXT | - | 야전 기상 환경 |
| `lamport_timestamp` | INTEGER | NOT NULL | 램포트 인과율 논리 시계 |
| `timestamp_utc` | TEXT | NOT NULL | 트랜잭션 기록 일시 |
| `prev_hash` | TEXT | NOT NULL | 직전 레코드 해시값 (초기값: 64자 0) |
| `record_hash` | TEXT | NOT NULL | 현재 레코드 SHA-256 해시값 |
| `sync_status` | TEXT | NOT NULL | PENDING, SYNCED_P2P, SYNCED_CLOUD, CONFLICT |
### 3.3 `sync_conflict_queue` (충돌 해결 큐)
- 단말 간 동일 품목에 대해 동시성 충돌 발생 시 LWW(Last-Write-Wins) 기본 처리 후, 허용 범위를 초과하는 불일치는 HITL 큐로 이관.
---
## 4. 데이터마이닝 공급망 위협 지표 정의
1. **리드타임 이상 급증 (Lead Time Anomaly Index):** 협력업체 조달 납기 급증 탐지
2. **부품 단종 및 희토류/원자재 고갈 위험도 (DIB Obsolescence Risk):** DIB 2~3차 벤더 공급망 단절 예측
3. **오프라인 급격 소모 지수 (Burn Rate Spike):** 작전 중 비인가 불출 및 이상 소모 감지
4. **해시 불일치 위변조 지수 (Integrity Violation Score):** 데이터 스푸핑 및 불법 변조 시도 차단
"""
with open(os.path.join(base, "docs/dat10_data_spec.md"), "w", encoding="utf-8") as f:
f.write(data_spec_md)
# ==========================================
# 2. Sample Datasets
# ==========================================
# (1) data/samples/raw_offline_inventory.csv
raw_csv = """transaction_id,terminal_id,unit_id,nsn_code,item_name,supply_class,tx_type,quantity,current_stock,unit_cost,comms_status,grid_coords,weather_condition,lamport_timestamp,timestamp_utc,prev_hash,record_hash
TX-20261001-001,TERM-A101,BN-01,1005-01-584-1234,5.56mm K2 보통탄,Class_V,RECEIPT,10000,25000,0.45,OFFLINE_LOCAL,52SDJ12345678,CLEAR,1,2026-10-01T08:00:00Z,0000000000000000000000000000000000000000000000000000000000000000,a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90
TX-20261001-002,TERM-A101,BN-01,1005-01-584-1234,5.56mm K2 보통탄,Class_V,ISSUE,2400,22600,0.45,OFFLINE_LOCAL,52SDJ12345678,CLEAR,2,2026-10-01T10:30:00Z,a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90,b2c3d4e5f6a10718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f91
TX-20261002-003,TERM-A102,BN-02,2530-01-450-8899,K9 유압 서보밸브,Class_IX,ISSUE,2,8,3400.0,DEGRADED_EW,52SDJ87654321,HEAVY_RAIN,1,2026-10-02T14:15:00Z,0000000000000000000000000000000000000000000000000000000000000000,c3d4e5f6a1b20718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f92
TX-20261003-004,TERM-A101,BN-01,8970-01-345-6789,전투식량 1형(소고기볶음밥),Class_I,ISSUE,350,1650,8.5,OFFLINE_LOCAL,52SDJ12345678,FOG,3,2026-10-03T09:00:00Z,b2c3d4e5f6a10718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f91,d4e5f6a1b2c30718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f93
TX-20261004-005,TERM-A103,BDE-03,9130-01-222-3333,JP-8 항공유 (드럼),Class_III,TRANSFER,50,450,180.0,OFFLINE_P2P,52SDJ55556666,CLEAR,1,2026-10-04T16:40:00Z,0000000000000000000000000000000000000000000000000000000000000000,e5f6a1b2c3d40718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f94
"""
with open(os.path.join(base, "data/samples/raw_offline_inventory.csv"), "w", encoding="utf-8") as f:
f.write(raw_csv.strip() + "\n")
# (2) data/samples/dib_supply_chain_disruptions.csv
dib_csv = """nsn_code,item_name,supplier_tier1,supplier_tier2,lead_time_days,baseline_lead_time,single_source_flag,geopolitical_risk_score,raw_material_criticality,failure_rate_monthly,disruption_label
1005-01-584-1234,5.56mm K2 보통탄,Poongsan Corp,Dong-Ah Raw Metals,18,15,0,0.15,0.20,0.01,NORMAL
2530-01-450-8899,K9 유압 서보밸브,Hanwha Aerospace,Moog Precision,145,45,1,0.85,0.92,0.18,CRITICAL_BOTTLENECK
8970-01-345-6789,전투식량 1형(소고기볶음밥),CJ CheilJedang,Local Farms,25,20,0,0.10,0.15,0.00,NORMAL
9130-01-222-3333,JP-8 항공유 (드럼),GS Caltex,MiddleEast Crude,40,30,0,0.65,0.80,0.05,WARNING_VOLATILITY
5998-01-777-8888,전술 통신용 FPGA 반도체 모듈,LIG Nex1,Xilinx/TSMC,320,60,1,0.95,0.98,0.25,DISASTER_OBSOLESCENCE
2920-01-111-2222,K2 전차 점화플러그,Hyundai Rotem,Denso Tech,75,30,1,0.70,0.60,0.12,WARNING_SUPPLY_DELAY
"""
with open(os.path.join(base, "data/samples/dib_supply_chain_disruptions.csv"), "w", encoding="utf-8") as f:
f.write(dib_csv.strip() + "\n")
# (3) data/samples/crdt_sync_events.json
crdt_json = [
{
"event_id": "CRDT-EVT-001",
"peer_id": "TERM-A101",
"nsn_code": "1005-01-584-1234",
"operation": "DECREMENT",
"delta": 2400,
"resulting_stock": 22600,
"lamport_clock": 2,
"origin_timestamp": "2026-10-01T10:30:00Z",
"signature": "sig_term_a101_valid_hash"
},
{
"event_id": "CRDT-EVT-002",
"peer_id": "TERM-B202",
"nsn_code": "1005-01-584-1234",
"operation": "DECREMENT",
"delta": 1000,
"resulting_stock": 24000,
"lamport_clock": 2,
"origin_timestamp": "2026-10-01T10:35:00Z",
"signature": "sig_term_b202_valid_hash"
},
{
"event_id": "CRDT-EVT-003",
"peer_id": "TERM-C303",
"nsn_code": "2530-01-450-8899",
"operation": "DECREMENT",
"delta": 5,
"resulting_stock": 3,
"lamport_clock": 5,
"origin_timestamp": "2026-10-02T12:00:00Z",
"signature": "sig_term_c303_valid_hash"
}
]
with open(os.path.join(base, "data/samples/crdt_sync_events.json"), "w", encoding="utf-8") as f:
json.dump(crdt_json, f, ensure_ascii=False, indent=2)
print("Markdown and Sample data created.")