Phase P~S 전체 작업물: 검증 스크립트, 블록 템플릿, 설계 문서, 코드 수정

포함 내용:
- Phase P/Q/R/S 설계 문서 (IMPROVEMENT-PHASE-*.md)
- 영역별 검증 스크립트 (scripts/verify_*.py, test_*.py)
- 블록 템플릿 추가 (cards, emphasis 변형)
- 코드 수정: block_search, content_editor, design_director, slide_measurer
- catalog.yaml 블록 목록 업데이트
- CLAUDE.md, PROGRESS.md, README.md 업데이트

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-31 08:38:06 +09:00
parent 0e4b8c091c
commit 29f56187c0
44 changed files with 9431 additions and 313 deletions

View File

@@ -0,0 +1,474 @@
"""3가지 접근법 비교 — 콘텐츠 2: DX 시행 목표 및 기대 효과
이전 콘텐츠(포함 관계)와 성격이 다름:
- 목표 3가지 (안전/품질, 생산성, 소통/신뢰)
- 프로세스 변화 4가지 (생산방식, 인지검토, 협업구조, 검증대응)
- 주체별 기대효과 (DxEffect 컴포넌트 — 텍스트로 대체)
- 핵심 결론 1줄
"""
from __future__ import annotations
import asyncio, json, sys, base64
from pathlib import Path
ROOT = Path(__file__).parent.parent
sys.path.insert(0, str(ROOT))
DESIGN_TOKENS_CSS = """
:root {
--color-primary: #1e293b;
--color-accent: #2563eb;
--color-accent-light: #93c5fd;
--color-bg: #ffffff;
--color-bg-subtle: #f8fafc;
--color-bg-dark: #1e293b;
--color-bg-dark-deep: #0f172a;
--color-border: #e2e8f0;
--color-danger: #dc2626;
--color-success: #16a34a;
--color-warning: #f59e0b;
--color-text: #1e293b;
--color-text-secondary: #64748b;
--color-text-light: #94a3b8;
--color-text-on-dark: #e2e8f0;
--color-text-on-accent: #ffffff;
--font-title: 28px;
--font-section: 14px;
--font-body: 13px;
--font-small: 11px;
--font-caption: 10px;
--weight-normal: 400;
--weight-medium: 500;
--weight-bold: 700;
--weight-black: 900;
--spacing-page: 36px 40px 24px;
--spacing-section: 16px;
--spacing-block: 12px;
--spacing-inner: 10px;
--spacing-small: 6px;
--radius: 8px;
--radius-small: 6px;
--line-height: 1.6;
}
"""
SLIDE_BASE_CSS = """
@import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css');
* { margin: 0; padding: 0; box-sizing: border-box; }
.slide {
width: 1280px; height: 720px; overflow: hidden;
background: var(--color-bg);
font-family: 'Pretendard Variable', sans-serif;
color: var(--color-text);
font-size: var(--font-body);
line-height: var(--line-height);
word-break: keep-all;
display: grid;
grid-template-areas: 'header header' 'body sidebar' 'footer footer';
grid-template-columns: 65fr 35fr;
grid-template-rows: auto 1fr auto;
gap: var(--spacing-section);
padding: var(--spacing-page);
}
.header { grid-area: header; font-size: var(--font-title); font-weight: var(--weight-black); color: var(--color-primary); border-bottom: 3px solid var(--color-accent); padding-bottom: 8px; }
.body { grid-area: body; display: flex; flex-direction: column; gap: var(--spacing-block); overflow: hidden; }
.sidebar { grid-area: sidebar; display: flex; flex-direction: column; gap: var(--spacing-block); border-left: 1px solid var(--color-border); padding-left: 20px; overflow: hidden; }
.footer { grid-area: footer; background: linear-gradient(135deg, #006aff, #00aaff); border-radius: var(--radius); padding: 14px 30px; text-align: center; color: var(--color-text-on-accent); }
.footer-text { font-size: 15px; font-weight: var(--weight-bold); }
.footer-sub { font-size: var(--font-small); opacity: 0.85; margin-top: 2px; }
"""
# ═══════════════════════════════════════
# 접근 A: Few-Shot 직접 생성
# ═══════════════════════════════════════
APPROACH_A = f"""<!DOCTYPE html>
<html lang="ko"><head><meta charset="UTF-8"><title>접근 A — DX 목표</title>
<style>{DESIGN_TOKENS_CSS}{SLIDE_BASE_CSS}
.goal-cards {{ display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--spacing-inner); }}
.goal {{
border-radius: var(--radius); padding: 12px; text-align: center;
display: flex; flex-direction: column; align-items: center;
}}
.goal-1 {{ background: linear-gradient(135deg, #eff6ff, #dbeafe); border: 2px solid var(--color-accent-light); }}
.goal-2 {{ background: linear-gradient(135deg, #f0fdf4, #dcfce7); border: 2px solid #86efac; }}
.goal-3 {{ background: linear-gradient(135deg, #fefce8, #fef9c3); border: 2px solid #fde047; }}
.goal-icon {{ font-size: 24px; margin-bottom: 4px; }}
.goal-title {{ font-size: var(--font-body); font-weight: var(--weight-black); margin-bottom: 4px; }}
.goal-desc {{ font-size: var(--font-small); color: var(--color-text-secondary); line-height: 1.5; }}
.section-title {{ font-size: var(--font-section); font-weight: var(--weight-black); color: var(--color-accent); margin-bottom: 2px; }}
.process-grid {{ display: grid; grid-template-columns: 1fr 1fr; gap: 8px; flex: 1; }}
.process-item {{
background: var(--color-bg-subtle); border: 1px solid var(--color-border);
border-radius: var(--radius); padding: 10px 12px;
display: flex; gap: 10px; align-items: flex-start;
}}
.process-arrow {{
display: flex; align-items: center; justify-content: center;
font-size: 18px; color: var(--color-accent); font-weight: var(--weight-black);
width: 28px; flex-shrink: 0;
}}
.process-content {{ flex: 1; }}
.process-label {{ font-size: var(--font-small); font-weight: var(--weight-bold); color: var(--color-accent); margin-bottom: 2px; }}
.process-before {{ font-size: var(--font-caption); color: var(--color-text-light); text-decoration: line-through; }}
.process-after {{ font-size: var(--font-small); color: var(--color-text); font-weight: var(--weight-medium); margin-top: 2px; }}
.sidebar-label {{ display: flex; align-items: center; gap: 10px; font-size: var(--font-small); font-weight: var(--weight-medium); color: var(--color-text-light); }}
.sidebar-label::before, .sidebar-label::after {{ content: ''; flex: 1; height: 1px; background: var(--color-border); }}
.effect-table {{ width: 100%; border-collapse: collapse; font-size: var(--font-small); flex: 1; }}
.effect-table th {{ background: var(--color-accent); color: white; padding: 6px 8px; text-align: left; font-weight: var(--weight-bold); font-size: var(--font-small); }}
.effect-table td {{ padding: 5px 8px; border-bottom: 1px solid var(--color-border); line-height: 1.5; font-size: var(--font-caption); }}
.effect-table tr:nth-child(even) {{ background: var(--color-bg-subtle); }}
.effect-role {{ font-weight: var(--weight-bold); color: var(--color-accent); white-space: nowrap; }}
</style></head><body>
<div class="slide">
<div class="header">DX 시행 목표 및 기대 효과</div>
<div class="body">
<div class="section-title">DX를 통한 궁극적 목표</div>
<div class="goal-cards">
<div class="goal goal-1">
<div class="goal-icon">🛡️</div>
<div class="goal-title">안전과 품질</div>
<div class="goal-desc">설계-시공-운영 전 과정에서 디지털로 검증하여 안전성 확보. 하자 최소화로 고품질 성과물 제공</div>
</div>
<div class="goal goal-2">
<div class="goal-icon">⚡</div>
<div class="goal-title">생산성 향상</div>
<div class="goal-desc">Analogue → Digital 프로세스 전환. 비용 절감, 기간 단축, 인력투입 최소화로 부가가치 제고</div>
</div>
<div class="goal goal-3">
<div class="goal-icon">🤝</div>
<div class="goal-title">소통과 신뢰</div>
<div class="goal-desc">협업 강화로 의사소통 효율 증진. 3D 모델·데이터 기반 검증으로 오류 최소화 및 Claim 예방</div>
</div>
</div>
<div class="section-title">업무 수행 과정(Process)의 변화</div>
<div class="process-grid">
<div class="process-item">
<div class="process-arrow">→</div>
<div class="process-content">
<div class="process-label">생산 방식</div>
<div class="process-before">수작업 의존의 반복 업무</div>
<div class="process-after">SW를 활용한 체계화된 방식으로 전환</div>
</div>
</div>
<div class="process-item">
<div class="process-arrow">→</div>
<div class="process-content">
<div class="process-label">인지·검토</div>
<div class="process-before">2D 도면 해석 중심</div>
<div class="process-after">3D 모델 기반의 직관적 인지·검토 체계</div>
</div>
</div>
<div class="process-item">
<div class="process-arrow">→</div>
<div class="process-content">
<div class="process-label">협업 구조</div>
<div class="process-before">개별 문서 중심 협업</div>
<div class="process-after">데이터 통합 기반의 정보 공유·관리 환경</div>
</div>
</div>
<div class="process-item">
<div class="process-arrow">→</div>
<div class="process-content">
<div class="process-label">검증·대응</div>
<div class="process-before">사후 대응 중심의 문제 처리</div>
<div class="process-after">사전 검증 중심의 예방적 업무 방식</div>
</div>
</div>
</div>
</div>
<div class="sidebar">
<div class="sidebar-label">주체별 기대효과</div>
<table class="effect-table">
<tr><th>주체</th><th>기대효과</th></tr>
<tr><td class="effect-role">발주처</td><td>품질 향상, 비용·기간 절감, 투명한 관리</td></tr>
<tr><td class="effect-role">설계사</td><td>오류 감소, 설계 품질 제고, 재작업 최소화</td></tr>
<tr><td class="effect-role">시공사</td><td>공정 최적화, 안전 강화, 현장 생산성 향상</td></tr>
<tr><td class="effect-role">감리·CM</td><td>실시간 모니터링, 데이터 기반 의사결정</td></tr>
<tr><td class="effect-role">유지관리</td><td>디지털 트윈 기반 예방 정비, 자산 관리 효율화</td></tr>
</table>
</div>
<div class="footer">
<div class="footer-text">고품질의 성과품, 비용 절감, 시간 단축, 의사소통에 도움이 안 되면 DX가 아니다</div>
</div>
</div>
</body></html>"""
# ═══════════════════════════════════════
# 접근 B: 프리미티브 조합
# ═══════════════════════════════════════
APPROACH_B = f"""<!DOCTYPE html>
<html lang="ko"><head><meta charset="UTF-8"><title>접근 B — DX 목표</title>
<style>{DESIGN_TOKENS_CSS}{SLIDE_BASE_CSS}
/* 프리미티브: icon-card-row */
.p-icon-row {{ display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--spacing-inner); }}
.p-icon-card {{
background: var(--color-bg-subtle); border: 1px solid var(--color-border);
border-radius: var(--radius); padding: 10px; text-align: center;
}}
.p-icon-card .icon {{ font-size: 22px; margin-bottom: 4px; }}
.p-icon-card b {{ font-size: var(--font-body); display: block; margin-bottom: 3px; }}
.p-icon-card span {{ font-size: var(--font-small); color: var(--color-text-secondary); line-height: 1.5; }}
/* 프리미티브: section-title */
.p-sec {{ font-size: var(--font-section); font-weight: var(--weight-black); color: var(--color-accent); }}
/* 프리미티브: bullet-list */
.p-bullets {{ display: flex; flex-direction: column; gap: 4px; flex: 1; }}
.p-bullet {{
font-size: var(--font-small); line-height: 1.6; padding-left: 14px; position: relative;
}}
.p-bullet::before {{ content: ''; position: absolute; left: 0; color: var(--color-accent); font-weight: var(--weight-bold); }}
.p-bullet strong {{ color: var(--color-accent); }}
/* 프리미티브: sidebar table */
.sidebar-label {{ display: flex; align-items: center; gap: 10px; font-size: var(--font-small); font-weight: var(--weight-medium); color: var(--color-text-light); }}
.sidebar-label::before, .sidebar-label::after {{ content: ''; flex: 1; height: 1px; background: var(--color-border); }}
.p-table {{ width: 100%; border-collapse: collapse; font-size: var(--font-small); }}
.p-table th {{ background: var(--color-accent); color: white; padding: 6px 8px; text-align: left; font-size: var(--font-small); }}
.p-table td {{ padding: 5px 8px; border-bottom: 1px solid var(--color-border); font-size: var(--font-caption); line-height: 1.5; }}
.p-table tr:nth-child(even) {{ background: var(--color-bg-subtle); }}
.p-table .role {{ font-weight: var(--weight-bold); color: var(--color-accent); }}
</style></head><body>
<div class="slide">
<div class="header">DX 시행 목표 및 기대 효과</div>
<div class="body">
<div class="p-sec">DX를 통한 궁극적 목표</div>
<div class="p-icon-row">
<div class="p-icon-card">
<div class="icon">🛡️</div>
<b>안전과 품질</b>
<span>디지털 검증으로 안전성 확보, 하자 최소화로 고품질 성과물</span>
</div>
<div class="p-icon-card">
<div class="icon">⚡</div>
<b>생산성 향상</b>
<span>Digital 프로세스 전환, 비용 절감·기간 단축·부가가치 제고</span>
</div>
<div class="p-icon-card">
<div class="icon">🤝</div>
<b>소통과 신뢰</b>
<span>협업 강화, 3D·데이터 기반 검증으로 오류 최소화·Claim 예방</span>
</div>
</div>
<div class="p-sec">업무 수행 과정(Process)의 변화</div>
<div class="p-bullets">
<div class="p-bullet"><strong>생산 방식</strong>: 수작업 의존 반복 업무 → SW를 활용한 체계화된 방식으로 전환</div>
<div class="p-bullet"><strong>인지·검토</strong>: 2D 도면 해석 중심 → 3D 모델 기반의 직관적 인지·검토 체계로 전환</div>
<div class="p-bullet"><strong>협업 구조</strong>: 개별 문서 중심 → 데이터 통합 기반의 정보 공유·관리 협업 환경으로 전환</div>
<div class="p-bullet"><strong>검증·대응</strong>: 사후 대응 중심 → 사전 검증 중심의 예방적 업무 방식으로 전환</div>
</div>
</div>
<div class="sidebar">
<div class="sidebar-label">주체별 기대효과</div>
<table class="p-table">
<tr><th>주체</th><th>기대효과</th></tr>
<tr><td class="role">발주처</td><td>품질 향상, 비용·기간 절감, 투명한 관리</td></tr>
<tr><td class="role">설계사</td><td>오류 감소, 설계 품질 제고, 재작업 최소화</td></tr>
<tr><td class="role">시공사</td><td>공정 최적화, 안전 강화, 현장 생산성 향상</td></tr>
<tr><td class="role">감리·CM</td><td>실시간 모니터링, 데이터 기반 의사결정</td></tr>
<tr><td class="role">유지관리</td><td>디지털 트윈 기반 예방 정비, 자산 관리 효율화</td></tr>
</table>
</div>
<div class="footer">
<div class="footer-text">고품질의 성과품, 비용 절감, 시간 단축, 의사소통에 도움이 안 되면 DX가 아니다</div>
</div>
</div>
</body></html>"""
# ═══════════════════════════════════════
# 접근 C: 참조 기반 생성
# ideal_v2의 디자인 패턴(다크배경+포함박스+사이드바 정의) 참조하되
# 이 콘텐츠에 맞게 구조 변형
# ═══════════════════════════════════════
APPROACH_C = f"""<!DOCTYPE html>
<html lang="ko"><head><meta charset="UTF-8"><title>접근 C — DX 목표</title>
<style>{DESIGN_TOKENS_CSS}{SLIDE_BASE_CSS}
/* 참조 패턴: 상단 다크 배경 요약 */
.ref-summary {{
background: linear-gradient(135deg, var(--color-bg-dark), var(--color-bg-dark-deep));
border-radius: var(--radius); padding: 14px 20px; color: var(--color-text-on-dark);
}}
.ref-summary h3 {{ font-size: var(--font-body); font-weight: var(--weight-bold); color: var(--color-accent-light); margin-bottom: var(--spacing-small); }}
.ref-goals {{
display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--spacing-inner); margin-top: var(--spacing-inner);
}}
.ref-goal {{
background: rgba(255,255,255,0.07); border-radius: var(--radius-small);
padding: 8px 10px; text-align: center;
}}
.ref-goal-icon {{ font-size: 20px; margin-bottom: 2px; }}
.ref-goal-title {{ font-size: var(--font-small); font-weight: var(--weight-bold); color: var(--color-accent-light); }}
.ref-goal-desc {{ font-size: var(--font-caption); color: var(--color-text-light); line-height: 1.5; margin-top: 2px; }}
/* 참조 패턴: 포함 박스 (DX 프레임 안에 4가지 변화) */
.ref-section-title {{ font-size: var(--font-section); font-weight: var(--weight-black); color: var(--color-accent); text-align: center; }}
.ref-dx-frame {{
flex: 1; border: 3px solid var(--color-accent); border-radius: 14px;
padding: 16px 14px 12px; background: linear-gradient(180deg, #eff6ff, #dbeafe);
position: relative; display: flex; flex-direction: column;
}}
.ref-dx-badge {{
position: absolute; top: -11px; left: 50%; transform: translateX(-50%);
background: var(--color-accent); color: white;
font-size: var(--font-small); font-weight: var(--weight-black);
padding: 2px 16px; border-radius: var(--radius-small); white-space: nowrap;
}}
.ref-dx-sub {{ text-align: center; font-size: var(--font-small); color: #1e40af; margin-bottom: var(--spacing-inner); }}
.ref-changes {{
display: grid; grid-template-columns: 1fr 1fr; gap: 8px; flex: 1;
}}
.ref-change {{
background: white; border: 1px solid var(--color-accent-light);
border-radius: var(--radius); padding: 8px 10px;
}}
.ref-change-label {{ font-size: var(--font-small); font-weight: var(--weight-bold); color: var(--color-accent); margin-bottom: 3px; }}
.ref-change-from {{ font-size: var(--font-caption); color: var(--color-text-light); text-decoration: line-through; }}
.ref-change-to {{ font-size: var(--font-small); color: var(--color-text); font-weight: var(--weight-medium); margin-top: 2px; }}
/* 참조 패턴: 사이드바 테이블 */
.sidebar-label {{ display: flex; align-items: center; gap: 10px; font-size: var(--font-small); font-weight: var(--weight-medium); color: var(--color-text-light); }}
.sidebar-label::before, .sidebar-label::after {{ content: ''; flex: 1; height: 1px; background: var(--color-border); }}
.ref-effects {{ display: flex; flex-direction: column; gap: 6px; flex: 1; }}
.ref-effect {{
background: var(--color-bg-subtle); border: 1px solid var(--color-border);
border-radius: var(--radius); padding: 8px 10px;
display: flex; gap: 8px; align-items: flex-start;
}}
.ref-effect-role {{
background: var(--color-accent); color: white;
font-size: var(--font-caption); font-weight: var(--weight-bold);
padding: 2px 8px; border-radius: 4px; white-space: nowrap; flex-shrink: 0;
}}
.ref-effect-desc {{ font-size: var(--font-small); color: var(--color-text-secondary); line-height: 1.5; }}
</style></head><body>
<div class="slide">
<div class="header">DX 시행 목표 및 기대 효과</div>
<div class="body">
<!-- 참조 패턴 1: 다크 배경 요약 + 목표 3카드 -->
<div class="ref-summary">
<h3>DX를 통한 궁극적 목표</h3>
<div class="ref-goals">
<div class="ref-goal">
<div class="ref-goal-icon">🛡️</div>
<div class="ref-goal-title">안전과 품질</div>
<div class="ref-goal-desc">디지털 검증으로 안전성 확보<br>하자 최소화, 고품질 성과물</div>
</div>
<div class="ref-goal">
<div class="ref-goal-icon">⚡</div>
<div class="ref-goal-title">생산성 향상</div>
<div class="ref-goal-desc">Digital 프로세스 전환<br>비용 절감, 기간 단축, 부가가치 제고</div>
</div>
<div class="ref-goal">
<div class="ref-goal-icon">🤝</div>
<div class="ref-goal-title">소통과 신뢰</div>
<div class="ref-goal-desc">협업 강화, 의사소통 효율<br>데이터 검증으로 Claim 예방</div>
</div>
</div>
</div>
<!-- 참조 패턴 2: DX 프레임 안에 프로세스 변화 4가지 -->
<div class="ref-section-title">DX 기반 Process 혁신</div>
<div class="ref-dx-frame">
<div class="ref-dx-badge">업무 수행 과정의 변화</div>
<div class="ref-dx-sub">Analogue 기반 → Digital 기반 프로세스 전환</div>
<div class="ref-changes">
<div class="ref-change">
<div class="ref-change-label">생산 방식</div>
<div class="ref-change-from">수작업 의존의 반복 업무</div>
<div class="ref-change-to">SW를 활용한 체계화된 방식</div>
</div>
<div class="ref-change">
<div class="ref-change-label">인지·검토</div>
<div class="ref-change-from">2D 도면 해석 중심</div>
<div class="ref-change-to">3D 모델 기반의 직관적 인지·검토</div>
</div>
<div class="ref-change">
<div class="ref-change-label">협업 구조</div>
<div class="ref-change-from">개별 문서 중심 협업</div>
<div class="ref-change-to">데이터 통합 기반 정보 공유·관리</div>
</div>
<div class="ref-change">
<div class="ref-change-label">검증·대응</div>
<div class="ref-change-from">사후 대응 중심 문제 처리</div>
<div class="ref-change-to">사전 검증 중심 예방적 업무 방식</div>
</div>
</div>
</div>
</div>
<div class="sidebar">
<div class="sidebar-label">주체별 기대효과</div>
<div class="ref-effects">
<div class="ref-effect">
<span class="ref-effect-role">발주처</span>
<span class="ref-effect-desc">품질 향상, 비용·기간 절감, 투명한 관리</span>
</div>
<div class="ref-effect">
<span class="ref-effect-role">설계사</span>
<span class="ref-effect-desc">오류 감소, 설계 품질 제고, 재작업 최소화</span>
</div>
<div class="ref-effect">
<span class="ref-effect-role">시공사</span>
<span class="ref-effect-desc">공정 최적화, 안전 강화, 현장 생산성 향상</span>
</div>
<div class="ref-effect">
<span class="ref-effect-role">감리·CM</span>
<span class="ref-effect-desc">실시간 모니터링, 데이터 기반 의사결정</span>
</div>
<div class="ref-effect">
<span class="ref-effect-role">유지관리</span>
<span class="ref-effect-desc">디지털 트윈 기반 예방 정비, 자산 관리 효율화</span>
</div>
</div>
</div>
<div class="footer">
<div class="footer-text">고품질의 성과품, 비용 절감, 시간 단축, 의사소통에 도움이 안 되면 DX가 아니다</div>
</div>
</div>
</body></html>"""
async def main():
from src.slide_measurer import measure_rendered_heights, capture_slide_screenshot
out_dir = ROOT / "data" / "runs" / "3approaches_dx2"
out_dir.mkdir(parents=True, exist_ok=True)
for name, html in [("A_fewshot", APPROACH_A), ("B_primitives", APPROACH_B), ("C_reference", APPROACH_C)]:
print(f"\n=== 접근 {name} ===")
m = await asyncio.to_thread(measure_rendered_heights, html)
s = await asyncio.to_thread(capture_slide_screenshot, html)
(out_dir / f"{name}.html").write_text(html, encoding="utf-8")
if s:
(out_dir / f"{name}.png").write_bytes(base64.b64decode(s))
slide = m.get("slide", {})
print(f" slide: {slide.get('scrollHeight', 0)}px / 720px {'' if not slide.get('overflowed') else ''}")
print(f"\n결과물: {out_dir}")
if __name__ == "__main__":
import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s", datefmt="%H:%M:%S")
logging.getLogger("selenium").setLevel(logging.WARNING)
logging.getLogger("urllib3").setLevel(logging.WARNING)
asyncio.run(main())