untracked files on main: dceb101 feat(#63): IMP-34 R1 donor capacity measured bound (u1+u2)

This commit is contained in:
2026-05-21 22:07:41 +09:00
commit 8f085a28d3
3220 changed files with 985495 additions and 0 deletions
@@ -0,0 +1,5 @@
[2026-05-21T05:58:25.559Z] {"timestamp":1779343103551,"level":"DEBUG","args":["[Manus] Debug collector initialized (no rrweb, UI events only)"],"stack":null}
[2026-05-21T05:58:25.559Z] {"timestamp":1779343103553,"level":"DEBUG","args":["[vite] connected."],"stack":null}
[2026-05-21T05:58:25.559Z] {"timestamp":1779343103559,"level":"INFO","args":["%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools","font-weight:bold"],"stack":null}
[2026-05-21T05:58:25.616Z] {"timestamp":1779343105585,"level":"ERROR","args":["[vite]","Failed to reload /src/index.css. This could be due to syntax errors or importing non-existent modules. (see errors above)"],"stack":"Error\n at console.<computed> [as error] (http://172.16.40.143:4322/__manus__/debug-collector.js:391:37)\n at Object.error (http://172.16.40.143:4322/@vite/client:809:26)\n at HMRClient.warnFailedUpdate (http://172.16.40.143:4322/@vite/client:181:15)\n at HMRClient.fetchUpdate (http://172.16.40.143:4322/@vite/client:212:10)\n at async Promise.all (index 0)\n at async HMRClient.queueUpdate (http://172.16.40.143:4322/@vite/client:196:5)\n at async Promise.all (index 0)\n at async handleMessage (http://172.16.40.143:4322/@vite/client:838:4)"}
[2026-05-21T05:58:25.616Z] {"timestamp":1779343105591,"level":"DEBUG","args":["[vite]","hot updated: /src/index.css"],"stack":null}
@@ -0,0 +1 @@
[2026-05-21T05:58:25.559Z] {"timestamp":1779343103594,"type":"fetch","method":"GET","url":"/api/sample-mdx?mdx=03","request":{"headers":{},"body":null},"response":{"status":200,"statusText":"OK","headers":{"connection":"keep-alive","content-type":"text/markdown; charset=utf-8","date":"Thu, 21 May 2026 05:58:23 GMT","keep-alive":"timeout=5","transfer-encoding":"chunked","vary":"Origin","x-mdx-filename":"03.%20DX%20%EC%8B%9C%ED%96%89%EC%9D%84%20%EC%9C%84%ED%95%9C%20%ED%95%84%EC%88%98%20%EC%9A%94%EA%B1%B4%20%EB%B0%8F%20%ED%98%81%EC%8B%A0%20%EB%B0%A9%EC%95%88.mdx"},"body":"---\r\ntitle: DX 실행 체계 구축 방안\r\nsidebar:\r\n order: 02\r\n---\r\n\r\n## 1. DX 시행을 위한 필수 요건\r\n\r\n<br/>\r\n\r\n* **기술(디지털)**\r\n * **Digital 기술(S/W, H/W)과 업무 Process의 통합**\r\n * 기존 업무 프로세스에 다양한 디지털 기술을 접목하여 업무 수행\r\n * 프로젝트 전반에 걸친 업무 프로세스의 연결 및 조율\r\n * **분야별 전문 지식(설계, 시공, 유지관리 등) 보유**\r\n * 건설 전 단계에 대한 근본적인 이해와 지식 및 경험\r\n * 최신 토목 기술 트랜드 및 표준 기준 등에 대한 높은 지식\r\n\r\n<br/>\r\n\r\n* **사람(역량)**\r\n * **혁신적 사고방식과 창의적 문제 해결 능력**\r\n * 기존 수행 방식과 관습적 사고 등에 의한 접근 방식 탈피\r\n * 디지털 기술을 활용한 창의적, 혁신적인 솔루션 제시\r\n * **사용자 중심 사고와 DX 수행 경험**\r\n * 사용자의 요구와 기대를 충족시키는 설계 및 구현\r\n * 시행착오를 포함한 수행 경험과 사용자 경험(UX)을 반영한 해결 방안 제시\r\n\r\n<br/>\r\n\r\n* **자연(여건)**\r\n * **지속적인 투자 및 실행 의지**\r\n * 기술 도입 초기 단계에 필요한 인력·기간·비용 등의 대규모 투자\r\n * 기술 고도화를 위한 지속적인 개선 및 투자 체계 구축\r\n * 변화와 혁신을 통해 부가가치를 창출하려는 실행 의지와 추진력\r\n\r\n<br/>\r\n---\r\n\r\n## 2. Process의 혁신과 Product의 변화\r\n\r\n<br/>\r\n\r\n### 2.1 과정(Process)의 혁신\r\n\r\n* **Analogue 기반 업무의 Digital화**\r\n\r\n | As-is [Analogue] | 구분 | To-be [Digital] |\r\n | :--- | :---: | :--- |\r\n | **개념·문서·행정 절차 중심** | ➠ | **시각화된 목적물, 소통, 투...[truncated]"},"duration":4,"error":null}
@@ -0,0 +1 @@
[2026-05-21T05:58:25.559Z] {"timestamp":1779343105507,"kind":"click","url":"http://172.16.40.143:4322/","viewport":{"width":1920,"height":945},"payload":{"target":{"tag":"div","id":null,"name":null,"type":null,"role":null,"ariaLabel":null,"testId":null,"dataLoc":"client\\src\\components\\LeftMdxPanel.tsx:71","href":null,"text":"MDX SOURCE 03. DX 시행을 위한 필수 요건 필수 요건 + Process/Product 혁신 04. DX 지연 요인 DX 인식 + 정…","selectorHint":"[data-loc=\"client\\src\\components\\LeftMdxPanel.tsx:71\"]"},"x":106,"y":84}}
+33
View File
@@ -0,0 +1,33 @@
# Design Agent Frontend MVP Implementation Plan
이 문서는 프론트엔드 MVP 개발 계획 및 Phase Z 시뮬레이션 구현 로드맵입니다.
## 📅 로드맵
### Phase 1: 동적 분석 시뮬레이션 (완료)
- [x] MDX 파일 텍스트 분석 로직 구현 (`STAGE 1`)
- [x] 섹션 개수에 따른 자동 레이아웃 및 존 매핑 로직 구현 (`STAGE 2`)
- [x] 분석 결과에 따른 캔버스 동적 렌더링 연결
### Phase 2: 사용자 인터랙션 강화 (진행 중)
- [ ] 레이아웃 프리셋 변경 시 캔버스 즉시 갱신
- [ ] 프레임 선택 시 캔버스 내 카드 스타일 변경 시뮬레이션
- [ ] Zone/Region 선택 상태에 따른 시각적 피드백 정교화
### Phase 3: 콘텐츠 상세화 및 팝업 시뮬레이션
- [ ] MDX 원문 무손실 보존을 위한 팝업 UI 구현
- [ ] `display_strategy` (Preview vs Full) 시뮬레이션 로직 추가
- [ ] 최종 결과물 데이터 구조(JSON) 내보내기 기능
## 📐 핵심 설계 원칙 (Phase Z 준수)
1. **Deterministic Mapping:** 동일한 MDX 입력에 대해 항상 동일한 초기 레이아웃과 프레임이 제안되어야 함.
2. **User Override Priority:** 사용자의 수동 선택은 시스템 추천보다 우선하며, 명시적으로 `overrides` 객체에 저장됨.
3. **No-Loss Principle:** 슬라이드 캔버스 공간 부족으로 생략된 텍스트는 반드시 팝업을 통해 전체 확인이 가능해야 함.
## 🔗 STAGE별 연결 지점
- **STAGE 1 & 2:** `designAgentApi.ts``parseMdxFile`, `generateSlidePlan`
- **STAGE 3:** `FramePanel.tsx``candidates` 매핑
- **STAGE 4:** `Home.tsx``handleLayoutSelect`, `handleFrameSelect`
- **STAGE 5:** `Home.tsx``Finalize Slide` 버튼 핸들러
+54
View File
@@ -0,0 +1,54 @@
# Design Agent Frontend MVP - Phase Z Simulation
이 문서는 `design-agent` 프론트엔드 프로젝트가 백엔드 파이프라인(Phase Z)의 각 단계와 어떻게 연결되는지 설명합니다.
---
## 📋 STAGE-to-CODE 매핑 가이드
본 MVP는 백엔드 없이도 파이프라인의 흐름을 시뮬레이션할 수 있도록 설계되었습니다.
### STAGE 1: MDX 분석 (Normalization)
- **백엔드 로직:** `section_parser.py` (H2, H3 태그 및 텍스트 블록 추출)
- **프론트엔드 시뮬레이션:** `designAgentApi.ts``parseMdxFile()`
- 파일의 텍스트를 읽어 실제 `#`, `##`, `###` 패턴을 분석합니다.
- 결과를 `NormalizedContent` 객체로 변환합니다.
### STAGE 2: 레이아웃 매칭 (Zone Mapping)
- **백엔드 로직:** `layout_selector.py` (섹션 개수/성격에 따른 8개 프리셋 선택)
- **프론트엔드 시뮬레이션:** `designAgentApi.ts``generateSlidePlan()`
- 분석된 섹션 개수에 따라 `single`, `horizontal-2`, `grid-2x2` 등을 자동으로 결정합니다.
- 각 섹션을 1280x720 캔버스의 특정 `Zone`에 할당합니다.
### STAGE 3: 프레임 매칭 (V1~V4)
- **백엔드 로직:** `block_reference.py` (Figma 프레임 DB와 콘텐츠 매칭)
- **프론트엔드 시뮬레이션:** `mockDesignAgentData.ts``FramePanel.tsx`
- 각 Zone(또는 Region)에 대해 V4 매칭 점수가 높은 Top-3 프레임을 제안합니다.
### STAGE 4: 사용자 조정 (Override)
- **백엔드 로직:** `pipeline.py` (사용자 수동 선택값 반영)
- **프론트엔드 구현:** `Home.tsx``slidePlanUtils.ts`
- 사용자가 선택한 Layout이나 Frame 정보를 `UserSelection.overrides`에 저장합니다.
- `applyLayout`, `applyFrame` 함수가 이 상태 변화를 관리합니다.
### STAGE 5: 최종 조립 및 검증
- **백엔드 로직:** `block_assembler.py` (Jinja2 템플릿 조립 및 Selenium 검증)
- **프론트엔드 구현:** 하단 액션 바의 **Finalize Slide** 버튼
- 현재 구성된 플랜 데이터를 서버로 전송할 준비가 된 지점입니다.
---
## 🛠️ 핵심 파일 구조
- `client/src/services/designAgentApi.ts`: 파이프라인 단계별 로직 시뮬레이션 핵심.
- `client/src/types/designAgent.ts`: Phase Z 위계(Slide > Zone > Region > Frame) 정의.
- `client/src/components/SlideCanvas.tsx`: 16:9 비율 및 레이아웃 프리셋 시각화.
- `client/src/utils/slidePlanUtils.ts`: 사용자 선택 및 데이터 가공 유틸리티.
---
## 🚀 향후 통합 계획
1. **API 교체:** `designAgentApi.ts`의 시뮬레이션 함수들을 실제 백엔드 엔드포인트 호출로 교체합니다.
2. **실시간 프리뷰:** 백엔드에서 생성된 `final.html`을 캔버스 내 `iframe` 등으로 직접 렌더링하도록 확장합니다.
3. **팝업 연동:** `display_strategy`에 따른 상세 원문 보기 기능을 실제 MDX 원문과 연결합니다.
+44
View File
@@ -0,0 +1,44 @@
# Design Agent Frontend
React + Vite + TypeScript frontend.
## 위치
- `Front/` — 이 폴더
- 원본 작업 위치 = `D:\ad-hoc\kei\design_agent_front\design-agent\` (로컬 dev)
## 실행
```
cd Front/
pnpm install
pnpm dev
```
http://localhost:3000 에서 확인. `DESIGN_AGENT_ROOT` env 로 backend 경로 지정 가능.
## 구조
```
Front/
├── client/ React frontend (Vite root)
│ └── src/
│ ├── pages/
│ ├── components/
│ ├── services/
│ └── ...
├── server/ production express
├── vite.config.ts dev plugin + backend 연결
└── ...
```
## Backend 연결 (vite.config.ts)
Vite dev plugin 이 다음 endpoint 등록 :
| Endpoint | 동작 |
|---|---|
| `POST /api/run` | MDX + overrides → backend pipeline spawn → run_id 반환 |
| `GET /api/sample-mdx?mdx=...` | sample MDX serve |
| `GET /frame-preview/{n}` | frame thumbnail |
| `GET /data/runs/{run_id}/{path}` | pipeline 산출물 serve |
@@ -0,0 +1,569 @@
{
"v4_source": "tests\\matching\\v4_full32_result.yaml",
"v4_label_to_phase_z_status": {
"use_as_is": "matched_zone",
"light_edit": "adapt_matched_zone",
"restructure": "extract_matched_zone",
"reject": "fallback_candidate"
},
"mvp1_allowed_statuses": [
"adapt_matched_zone",
"matched_zone"
],
"mode": "composition_v0_layout_8preset",
"mode_note": "MVP-1.5b w/ composition planner v0 — sections → candidates (separate / parent_merged) → score → greedy select → 8-preset layout vocabulary (single / horizontal-2 / vertical-2 / top-1-bottom-2 / top-2-bottom-1 / left-1-right-2 / left-2-right-1 / grid-2x2). v0 layout = count-based; v1 axes (cardinality_fit / hierarchy_coherence / density_score) 추후.",
"layout_preset": "horizontal-2",
"layout_css": {
"areas": "\"top\" \"bottom\"",
"cols": "1fr",
"rows": "228px 343px",
"heights_px": [
228,
343
],
"ratios": [
0.39,
0.586
],
"computation": "min_height_first + content_weight_distribution",
"dynamic_rows": true,
"raw_zone_layout": {
"computation": "min_height_first + content_weight_distribution",
"slide_body_height": 585,
"gap": 14,
"available_after_gap": 571,
"min_heights_px": [
228,
342
],
"min_scaled": true,
"total_min_height": 570,
"remaining_after_min": 1,
"content_weights": [
{
"position": "top",
"template_id": "three_parallel_requirements",
"score": 4.425
},
{
"position": "bottom",
"template_id": "process_product_two_way",
"score": 7.305
}
],
"weight_shares": [
0.377,
0.623
],
"extras_px": [
0,
1
],
"heights_px": [
228,
343
],
"ratios": [
0.39,
0.586
]
}
},
"slide_status": {
"rendered": true,
"visual_check_passed": true,
"full_mdx_coverage": true,
"aligned_section_ids": [
"03-1",
"03-2"
],
"covered_section_ids": [
"03-1",
"03-2"
],
"filtered_section_ids": [],
"filtered_section_reasons": [],
"visual_fail_reasons": [],
"adapter_needed_count": 0,
"adapter_needed_units": [],
"content_truncated_count": 0,
"content_truncated_units": [],
"overall": "PASS",
"note": "자동 파이프라인 결과 보고. review/UI 개념 X. final.html 파일명 != PASS 의미. overall == PASS 는 visual OK + full coverage + adapter_needed=0 일 때만. adapter_needed_count > 0 = mapper 가 contract 와 안 맞아 자동 렌더 못 한 zone 존재. content_truncated_count > 0 = builder 가 truncate 한 zone 존재 (rendered 됐지만 일부 콘텐츠 손실)."
},
"fit_classification": {
"visual_check_passed": true,
"classifications": [],
"summary": "visual check passed — no overflow to classify",
"categories_seen": [],
"unclassified_signals": [],
"placement_diagnostics": [
{
"zone_position": "top",
"mapper_frame_template_id": "three_parallel_requirements",
"b4_selected_template_id": "three_parallel_requirements",
"frame_selection_matches_mapper": true,
"frame_selection_match_note": null,
"region_count": 1,
"slot_assignment_count": 1,
"rejection_count": 0
},
{
"zone_position": "bottom",
"mapper_frame_template_id": "process_product_two_way",
"b4_selected_template_id": "process_product_two_way",
"frame_selection_matches_mapper": true,
"frame_selection_match_note": null,
"region_count": 2,
"slot_assignment_count": 2,
"rejection_count": 0
}
]
},
"router_decision": {
"router_active": false,
"proposed_actions_summary": [],
"implementation_status_summary": {},
"routed_count": 0,
"routed_details": [],
"missing_actions_pending_impl": [],
"note": "visual check passed — no overflow to route"
},
"retry_trace": {
"retry_attempted": false,
"retry_action": null,
"plan": null,
"rerender_attempted": false,
"retry_passed": false,
"retry_failure_reason": null,
"retried_candidate_path": null,
"safety_margin_px": 4,
"policy": "A3 locked rules : retry budget=1, slide-base/spacing/gap fixed, donor strict (sibling/visual ok/capacity ok/slack>0/min_height 보존), (b) revert on redistribution fail or rerender visual fail.",
"retry_skipped_reason": "router_active=False (visual check passed — no overflow)",
"failure_classification": {
"failure_type": "not_attempted",
"failure_type_description": "retry was not attempted (router_active=False or zone_ratio_retry not in proposed actions). 정상 path 의 일부 — 실패 X",
"classification_rule": "retry_attempted=False — router_active=False or zone_ratio_retry not in proposed_actions"
},
"next_action_proposal": {
"next_proposed_action": "none",
"next_action_rationale": "retry 시도 자체가 없었음 (visual ok 등) — escalation 불필요",
"next_action_implementation_status": "n/a",
"mapping_source": "A4 NEXT_ACTION_BY_FAILURE (사용자 잠금 2026-04-29)"
}
},
"composition_planner_debug": {
"planner_version": "v0.2",
"selection_rule": "score desc, then source_section_ids count desc (coverage tiebreak). filter = phase_z_status ∉ allowed_statuses OR auto_selectable=False. auto_selectable=False 사유 : C1 (capacity mismatch — silent truncate / FitError 차단), W1 (rep not auto-renderable), W2 (all children reject), W3 (majority children non-auto-renderable).",
"candidates_total": 2,
"candidates_viable_auto": 2,
"candidates_summary": [
{
"source_section_ids": [
"03-1"
],
"merge_type": "single",
"template_id": "three_parallel_requirements",
"label": "use_as_is",
"phase_z_status": "matched_zone",
"score": 0.9268,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 3,
"source_shape": "top_bullets",
"capacity": {
"strict": 3,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
},
{
"source_section_ids": [
"03-2"
],
"merge_type": "single",
"template_id": "process_product_two_way",
"label": "use_as_is",
"phase_z_status": "matched_zone",
"score": 0.9198,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"merge_candidates": [],
"capacity_mismatches": [],
"selected_units_count": 2,
"layout_preset": "horizontal-2",
"layout_preset_rationale": "v0 count-based: 2 units → horizontal-2"
},
"zones": [
{
"position": "top",
"source_section_ids": [
"03-1"
],
"merge_type": "single",
"title": "1. DX 시행을 위한 필수 요건",
"v4_rank1_frame_id": "1171281190",
"v4_rank1_frame_number": 13,
"v4_template_id": "three_parallel_requirements",
"v4_label": "use_as_is",
"v4_confidence": 0.9268,
"phase_z_status": "matched_zone",
"composition_score": 0.9268,
"composition_rationale": {
"capacity_fit": {
"item_count": 3,
"source_shape": "top_bullets",
"capacity": {
"strict": 3,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.9268,
"confidence": 0.9268,
"label": "use_as_is",
"label_weight": 1.0,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"composition_notes": [],
"mapper_type": "contract",
"contract_id": "three_parallel_requirements",
"contract_frame_id": 1171281190,
"builder": "items_with_role",
"min_height_px": 230,
"slot_payload_keys": [
"pillars",
"title"
],
"content_truncated_count": null,
"assets_dir": null,
"content_weight": {
"score": 4.425,
"text_length": 660,
"top_bullets": 3,
"nested_bullets": 16,
"has_table": false,
"subsection_count": 0
},
"placement_trace": {
"section_id": "03-1",
"selected_frame_id": "1171281190",
"selected_template_id": "three_parallel_requirements",
"internal_regions": [
{
"region_id": "03-1.region-1",
"role": "primary",
"content_type": "text_block",
"ratio_estimate": 1.0,
"content_unit_ids": [
"03-1.text-1"
],
"frame_match_strategy": {
"kind": "frame_match",
"frame_id": null,
"display_strategy": "inline_full"
},
"source_shape_index": null
}
],
"slot_assignments": [
{
"region_id": "03-1.region-1",
"content_unit_id": "03-1.text-1",
"frame_slot_id": "pillar_1",
"partial_target_path": ".f13b__cols > .f13b__col:nth-child(1)",
"display_strategy": "inline_full"
}
],
"overflow_buffer": [],
"rejection": [],
"mapper_frame_template_id": "three_parallel_requirements",
"frame_selection_matches_mapper": true,
"frame_selection_match_note": null
},
"height_px": 228,
"ratio": 0.39
},
{
"position": "bottom",
"source_section_ids": [
"03-2"
],
"merge_type": "single",
"title": "2. Process의 혁신과 Product의 변화",
"v4_rank1_frame_id": "1171281210",
"v4_rank1_frame_number": 29,
"v4_template_id": "process_product_two_way",
"v4_label": "use_as_is",
"v4_confidence": 0.9198,
"phase_z_status": "matched_zone",
"composition_score": 0.9198,
"composition_rationale": {
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.9198,
"confidence": 0.9198,
"label": "use_as_is",
"label_weight": 1.0,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"composition_notes": [],
"mapper_type": "contract",
"contract_id": "process_product_two_way",
"contract_frame_id": 1171281210,
"builder": "process_product_pair",
"min_height_px": 345,
"slot_payload_keys": [
"banner_left",
"banner_right",
"process",
"product",
"title"
],
"content_truncated_count": null,
"assets_dir": "assets\\process_product_two_way",
"content_weight": {
"score": 7.305,
"text_length": 924,
"top_bullets": 6,
"nested_bullets": 7,
"has_table": true,
"subsection_count": 2
},
"placement_trace": {
"section_id": "03-2",
"selected_frame_id": "1171281210",
"selected_template_id": "process_product_two_way",
"internal_regions": [
{
"region_id": "03-2.region-1",
"role": "primary",
"content_type": "text_block",
"ratio_estimate": 0.8421,
"content_unit_ids": [
"03-2.text-1"
],
"frame_match_strategy": {
"kind": "frame_match",
"frame_id": null,
"display_strategy": "inline_full"
},
"source_shape_index": null
},
{
"region_id": "03-2.region-2",
"role": "supporting",
"content_type": "transform_table",
"ratio_estimate": 0.1579,
"content_unit_ids": [
"03-2.transform-1"
],
"frame_match_strategy": {
"kind": "frame_match",
"frame_id": null,
"display_strategy": "inline_full"
},
"source_shape_index": null
}
],
"slot_assignments": [
{
"region_id": "03-2.region-1",
"content_unit_id": "03-2.text-1",
"frame_slot_id": "product_column",
"partial_target_path": ".f29b__grid .f29b__cell--right",
"display_strategy": "inline_full"
},
{
"region_id": "03-2.region-2",
"content_unit_id": "03-2.transform-1",
"frame_slot_id": "process_column",
"partial_target_path": ".f29b__grid .f29b__cell--left",
"display_strategy": "inline_full"
}
],
"overflow_buffer": [],
"rejection": [],
"mapper_frame_template_id": "process_product_two_way",
"frame_selection_matches_mapper": true,
"frame_selection_match_note": null
},
"height_px": 343,
"ratio": 0.586
}
],
"visual_runtime_check": {
"frame_slot_metrics": [
{
"class_name": "f29b__cell f29b__cell--left",
"clientHeight": 125,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "process_column",
"overflowed": false,
"scrollHeight": 125,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
},
{
"class_name": "f29b__cell f29b__cell--right",
"clientHeight": 125,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "product_column",
"overflowed": false,
"scrollHeight": 125,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
},
{
"class_name": "f29b__cell f29b__cell--left",
"clientHeight": 43,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "process_column",
"overflowed": false,
"scrollHeight": 43,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
},
{
"class_name": "f29b__cell f29b__cell--right",
"clientHeight": 43,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "product_column",
"overflowed": false,
"scrollHeight": 43,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
},
{
"class_name": "f29b__cell f29b__cell--left",
"clientHeight": 63,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "process_column",
"overflowed": false,
"scrollHeight": 63,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
},
{
"class_name": "f29b__cell f29b__cell--right",
"clientHeight": 63,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "product_column",
"overflowed": false,
"scrollHeight": 63,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
}
],
"slide": {
"clientHeight": 720,
"clientWidth": 1280,
"excess_x": 0,
"excess_y": 0,
"overflowed": false,
"scrollHeight": 720,
"scrollWidth": 1280,
"size_correct": true
},
"slide_body": {
"clientHeight": 585,
"clientWidth": 1180,
"excess_x": 0,
"excess_y": 0,
"overflowed": false,
"scrollHeight": 585,
"scrollWidth": 1180
},
"zones": [
{
"clientHeight": 228,
"clientWidth": 1180,
"clipped_inner": [],
"excess_x": 0,
"excess_y": 0,
"overflowed": false,
"position": "top",
"scrollHeight": 228,
"scrollWidth": 1180,
"template_id": "three_parallel_requirements"
},
{
"clientHeight": 343,
"clientWidth": 1180,
"clipped_inner": [],
"excess_x": 0,
"excess_y": 0,
"overflowed": false,
"position": "bottom",
"scrollHeight": 343,
"scrollWidth": 1180,
"template_id": "process_product_two_way"
}
],
"screenshot": "data\\runs\\mdx03_f29_fix_check\\phase_z2\\preview.png",
"passed": true,
"fail_reasons": []
}
}
@@ -0,0 +1,927 @@
<!-- Phase Z-2 MVP-1.5b — single slide + Type B layout (top/bottom zones).
원래 Phase Z 설계 복귀: MDX 1 = slide 1, layout preset = zone 분할, frame-derived block ⊂ zone. -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280">
<title>DX 실행 체계 구축 방안</title>
<style>
/* ── existing tokens (inlined) ── */
/* === typography.css === */
/* ══════════════════════════════════════
Typography Tokens v1
══════════════════════════════════════
슬라이드 전체의 공통 글자 위계.
모든 블록은 이 토큰을 참조한다.
직접값(font-size: 11px) 금지 → var(--font-body) 사용.
══════════════════════════════════════ */
:root {
/* ── 1층: Global Hierarchy ── */
/* 대목차: 슬라이드 상단 제목 */
--font-slide-title: 22px;
--weight-slide-title: 700;
--lh-slide-title: 1.4;
/* 중목차: zone 제목 */
--font-zone-title: 16px;
--weight-zone-title: 700;
--lh-zone-title: 1.4;
/* 소목차: 블록 내 소제목, 카드 제목 */
--font-sub-title: 12px;
--weight-sub-title: 700;
--lh-sub-title: 1.45;
/* 본문: 블릿, 설명 텍스트 */
--font-body: 10px;
--weight-body: 500;
--lh-body: 1.55;
/* 캡션: 각주, 출처, 보조 텍스트 */
--font-caption: 10px;
--weight-caption: 400;
--lh-caption: 1.4;
/* footer: 핵심 인사이트 pill */
--font-footer: 20px;
--weight-footer: 700;
--lh-footer: 1.2;
/* ── 2층: Component Semantic Tokens ── */
/* 가까운 위계에서 기본값, 필요시 override */
/* 본문 강조 (인라인 heading) */
--font-body-strong: var(--font-body);
--weight-body-strong: 600;
/* 자세히보기 링크 */
--font-detail-link: var(--font-caption);
--weight-detail-link: 500;
/* pill/badge 라벨 */
--font-pill-label: var(--font-sub-title);
--weight-pill-label: 700;
/* 표 헤더 */
--font-table-header: var(--font-sub-title);
--weight-table-header: 700;
/* 표 셀 */
--font-table-cell: var(--font-body);
--weight-table-cell: 400;
/* 비교 뱃지 */
--font-compare-badge: var(--font-sub-title);
--weight-compare-badge: 700;
/* 강조 인용 */
--font-callout: var(--font-sub-title);
--weight-callout: 700;
/* 상단 라벨 (overline) */
--font-overline: var(--font-caption);
--weight-overline: 600;
--ls-overline: 0.05em;
}
/* === spacing.css === */
/* ══════════════════════════════════════
Spacing Tokens v1
══════════════════════════════════════
여백/간격/들여쓰기 공통 기준.
══════════════════════════════════════ */
:root {
/* ── 기본 스케일 ── */
--space-xs: 4px;
--space-sm: 8px;
--space-md: 12px;
--space-lg: 16px;
--space-xl: 24px;
/* ── slide-base 레이아웃 ── */
--slide-padding-x: 40px; /* 본문 좌우 여백 */
--slide-title-left: 52px; /* 대목차 시작 */
--slide-title-top: 22px; /* 대목차 위치 */
--slide-divider-top: 58px; /* 구분선 위치 (slide_base.html 와 일치 2026-05-07) */
--slide-body-top: 76px; /* 본문 시작 (사용자 직설: divider-body 16px) */
--slide-body-height: 585px; /* 본문 높이 (사용자 직설: body-footer 10px) */
--slide-footer-bottom: 8px; /* footer 하단 여백 (slide_base.html 와 일치) */
--slide-footer-height: 41px; /* footer 높이 */
/* ── zone ── */
--zone-gap: 8px; /* zone 간 간격 */
--zone-padding-left: 12px; /* zone 안쪽 좌측 여백 */
--zone-padding-right: 8px; /* zone 안쪽 우측 여백 */
--zone-title-mb: 8px; /* zone 제목 아래 여백 */
/* ── 블록 공통 ── */
--card-padding: 16px; /* 카드 내부 여백 */
--card-padding-sm: 8px; /* 작은 카드 내부 여백 */
--card-gap: 12px; /* 카드 간 간격 */
--card-radius: 6px; /* 카드 모서리 */
/* ── 블릿/텍스트 ── */
--bullet-indent: 14px; /* 불릿 hanging indent */
--bullet-gap: 2px; /* 불릿 항목 간 간격 */
--heading-gap: 4px; /* 소제목 아래 간격 */
--section-gap: 10px; /* 섹션 간 간격 */
/* ── flex/grid 기본 ── */
--flex-gap: 12px; /* 기본 flex gap */
--flex-gap-sm: 6px; /* 좁은 flex gap */
--grid-gap: 16px; /* 기본 grid gap */
}
/* === colors.css === */
/* ══════════════════════════════════════
Color Tokens v1
══════════════════════════════════════
2층 구조: 공통 테마색 + 블록 의미색.
══════════════════════════════════════ */
:root {
/* ══ 1층: 공통 테마색 ══ */
/* 모든 블록이 공유하는 기본 팔레트 */
/* 텍스트 */
--color-title: #1e293b; /* 제목 (진한 남색) */
--color-zone-title: #1a365d; /* zone 중목차 제목 */
--color-body: #475569; /* 본문 */
--color-body-strong: #1e293b; /* 본문 강조 */
--color-caption: #94a3b8; /* 캡션, 보조 */
--color-muted: #64748b; /* 약한 텍스트 */
/* 배경 */
--color-bg: #ffffff; /* 슬라이드 배경 */
--color-bg-subtle: #f8fafc; /* 카드/영역 배경 */
--color-bg-page: #e8ecf0; /* 페이지 배경 (슬라이드 바깥) */
/* 보더 */
--color-border: #e2e8f0; /* 기본 보더 */
--color-border-strong: #cbd5e1; /* 강한 보더 */
/* 강조 */
--color-accent: #2563eb; /* 링크, 강조 (파랑) */
--color-accent-hover: #eff6ff; /* 링크 hover 배경 */
--color-danger: #dc2626; /* 경고, 에러 */
/* slide-base 전용 */
--color-slide-title-from: #296b55; /* 대목차 gradient 시작 */
--color-slide-title-to: #123328; /* 대목차 gradient 끝 */
--color-footer-bg-from: #3b3523; /* footer gradient 시작 */
--color-footer-bg-mid: #263a2a; /* footer gradient 중간 */
--color-footer-bg-to: #113f31; /* footer gradient 끝 */
--color-footer-text: #ffffff; /* footer 텍스트 */
--color-footer-accent: #ffee33; /* footer 강조 (em) */
/* ══ 2층: 블록 의미색 ══ */
/* 특정 블록 유형에서 의미를 가지는 색 */
/* 3열 비교 (prerequisites-3col) */
--color-col-1-from: #0D78D0; /* 1열 gradient 시작 */
--color-col-1-to: #023056; /* 1열 gradient 끝 */
--color-col-2-from: #FF9A23; /* 2열 gradient 시작 */
--color-col-2-to: #CC5200; /* 2열 gradient 끝 */
--color-col-3-from: #39BE49; /* 3열 gradient 시작 */
--color-col-3-to: #23742C; /* 3열 gradient 끝 */
/* 비교 블록 (compare) */
--color-compare-left: #5c3714; /* 좌측 (AS-IS 계열) */
--color-compare-right: #285b4a; /* 우측 (TO-BE 계열) */
--color-compare-badge: #ae3607; /* VS 뱃지 */
/* 다크 카드 (direct render) */
--color-dark-card-1: #1a365d; /* 카드 1 배경 */
--color-dark-card-2: #1e3a2f; /* 카드 2 배경 */
--color-dark-card-3: #3b1f2b; /* 카드 3 배경 */
--color-dark-card-title: #fbbf24; /* 다크카드 제목 (금색) */
--color-dark-card-body: #e2e8f0; /* 다크카드 본문 */
/* 표 */
--color-table-header-bg: #64748b; /* 표 헤더 배경 */
--color-table-header-text: #ffffff; /* 표 헤더 텍스트 */
/* 블록 제목 gradient (Figma 원본) */
--color-block-title-from: #CC5200; /* 주황 gradient 시작 */
--color-block-title-to: #883700; /* 주황 gradient 끝 */
/* pill */
--color-pill-bg: #1e293b; /* pill 배경 */
--color-pill-text: #ffffff; /* pill 텍스트 */
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
background: #e8ecf0;
display: flex; justify-content: center; align-items: center;
min-height: 100vh;
word-break: keep-all;
padding: 20px 0;
}
/* ── 16:9 슬라이드 (single, 1280×720) ── */
.slide {
width: 1280px; height: 720px;
position: relative;
overflow: hidden;
background: #fff;
box-shadow: 0 4px 20px rgba(0,0,0,.15);
flex-shrink: 0;
}
.slide-bg {
position: absolute; inset: 0;
background: linear-gradient(180deg, #f0f0f0 0%, #ffffff 100%);
z-index: 0;
}
.slide-title {
position: absolute;
left: 52px; top: 22px;
width: calc(100% - 104px);
font-weight: 700;
font-size: var(--font-slide-title);
line-height: var(--lh-slide-title);
background-image: linear-gradient(180deg, #296b55 0%, #123328 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
text-shadow: 0 0 2px #322c1e;
z-index: 2;
}
.slide-divider {
position: absolute;
left: 50px; top: 58px;
width: calc(100% - 100px);
height: 2px;
background: #cbd5e1;
z-index: 2;
}
.slide-body {
position: absolute;
left: 50px; top: 76px;
width: calc(100% - 100px); /* 1180 */
height: 585px;
z-index: 1;
overflow: hidden;
}
/* ── Layout preset (composition planner v0 — 8 vocabulary) ──
단일 .layout-{preset} 클래스에 grid CSS 주입.
layout_css = pipeline build_layout_css() 결과 :
- horizontal-2 : rows = dynamic px (content_weight + frame_min_height)
- 그 외 : rows / cols = fr default (LAYOUT_PRESETS)
positions (single / top / bottom / left / right / top-left / ... / grid-2x2 9개)
은 .zone 의 inline grid-area 로 지정 — preset CSS 는 areas 만 정의. */
.layout-horizontal-2 {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 228px 343px;
grid-template-areas: "top" "bottom";
gap: 14px;
height: 100%;
}
/* ── Zone — block 가용 공간 최대화. 프레임 자체 styling 이 boundary 역할 ── */
.zone {
position: relative;
overflow: hidden;
padding: 0;
min-width: 0;
min-height: 0;
}
/* ── Frame-family text layout contract (shared, reusable) ──
feedback-1 (mvp1.5b_test7): visible improvement 강화.
Stronger hanging indent + breathing line spacing + visible hierarchy. */
.text-line {
font-size: var(--font-body); /* 11px */
font-weight: var(--weight-body);
line-height: 1.6; /* breathing room */
margin: 0;
}
.text-line + .text-line {
margin-top: 4px; /* visible gap between lines (was 2px) */
}
/* bullet line — hanging indent via padding + absolute marker (안정적) */
.text-line--bullet {
padding-left: 14px;
position: relative;
}
.text-line--bullet::before {
content: "•"; /* visible bullet 마커 */
position: absolute;
left: 2px;
top: 0;
font-weight: 700;
line-height: inherit;
color: inherit;
}
/* indent levels — visible nested hierarchy */
.text-line--indent-1 {
padding-left: 30px;
}
.text-line--indent-1::before {
content: "◦"; /* sub-bullet 다른 마커 */
left: 18px;
}
.text-line--indent-2 {
padding-left: 46px;
}
.text-line--indent-2::before {
content: "▪";
left: 34px;
}
/* body line — 마커 없음 */
.text-line--body {
padding-left: 0;
}
.text-line strong { color: #000; font-weight: 700; }
/* ── Transform-block family (frame 29 AS-IS/TO-BE dedicated comparison component) ──
feedback-3: bullet rows 가 아닌 *전용 비교 component*. Header (AS-IS / TO-BE) + paired rows.
color-coded cells, left-border accent → 단번에 *비교 구조* 인지. */
.transform-block {
margin-top: 4px;
padding: 6px 8px 6px;
background: rgba(255, 255, 255, 0.4);
border-radius: 3px;
border: 1px solid rgba(0,0,0,0.05);
}
.transform-block__header {
display: grid;
grid-template-columns: 1fr 22px 1fr;
gap: 6px;
margin-bottom: 4px;
padding-bottom: 3px;
border-bottom: 1px dashed rgba(0,0,0,0.12);
font-size: 9px;
font-weight: 900;
letter-spacing: 0.5px;
}
.transform-block__label--from { color: #6b5444; }
.transform-block__label--to { color: #2563eb; text-align: left; }
.transform-rows {
display: flex; flex-direction: column;
gap: 4px;
}
.transform-row {
display: grid;
grid-template-columns: 1fr 22px 1fr;
gap: 6px;
align-items: stretch;
font-size: var(--font-body);
line-height: 1.45;
}
.transform-row__from {
padding: 3px 8px;
background: linear-gradient(90deg, rgba(140,120,90,0.16), rgba(140,120,90,0.08));
border-left: 2px solid #b8a98a;
border-radius: 2px;
color: #4b3f30;
font-weight: 500;
}
.transform-row__arrow {
text-align: center;
color: #2563eb;
font-weight: 900;
font-size: 14px;
align-self: center;
}
.transform-row__to {
padding: 3px 8px;
background: linear-gradient(90deg, rgba(37,99,235,0.10), rgba(37,99,235,0.18));
border-left: 2px solid #2563eb;
border-radius: 2px;
color: #1e40af;
font-weight: 700;
}
/* ── Footer pill — feedback-3: body 와 weight balance, 살짝 가벼워짐 ── */
.slide-footer {
position: absolute;
left: 50px; bottom: 8px;
width: calc(100% - 100px); /* front 기준 (body 와 정렬) */
height: 41px; /* front 기준 */
border-radius: 999px;
overflow: hidden;
z-index: 2;
display: flex; align-items: center; justify-content: center;
background: linear-gradient(90deg, #3b3523 5%, #263a2a 50%, #113f31 95%);
opacity: 0.92; /* slightly lighter */
}
.slide-footer-text {
position: relative; z-index: 1;
font-size: 15px; /* was 20px (--font-footer) */
font-weight: 700;
line-height: 1.2;
color: #fff;
text-align: center;
text-shadow: 0 0 3px rgba(0,0,0,.4);
letter-spacing: -0.01em;
}
.slide-footer-text em { color: #fe3; font-style: normal; }
.phase-z2-marker {
position: absolute;
top: 4px; right: 8px;
font-size: 9px; color: #94a3b8;
font-family: monospace;
z-index: 3;
}
</style>
</head>
<body>
<div class="slide" data-page="1">
<div class="slide-bg"></div>
<div class="phase-z2-marker">phase_z2 / mvp-1.5b / horizontal-2 / single slide</div>
<div class="slide-title">DX 실행 체계 구축 방안</div>
<div class="slide-divider"></div>
<div class="slide-body">
<div class="layout-horizontal-2">
<div class="zone" data-zone-position="top" data-template-id="three_parallel_requirements" style="grid-area: top;">
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt.
Legacy templates/blocks/structures/prerequisites-3col.html 의 token-fixed font 접근 학습. -->
<style>
.f13b {
width: 100%; height: 100%;
display: flex; flex-direction: column;
gap: 4px;
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
word-break: keep-all;
}
.f13b__title {
font-size: var(--font-zone-title);
font-weight: 700;
line-height: var(--lh-zone-title);
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
flex-shrink: 0;
}
.f13b__cols {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 8px;
flex: 1;
min-height: 0;
}
.f13b__col {
display: flex;
border-top: 2px solid #000; /* PROMOTED line 57 */
border-bottom: 2px solid #000;
overflow: hidden;
min-width: 0;
background: rgba(255,255,255,0.5);
}
.f13b__bar {
flex: 0 0 50px;
display: flex; flex-direction: column;
align-items: center; justify-content: center;
color: #fff;
font-weight: 700;
text-align: center;
padding: 6px 2px;
gap: 3px;
}
.f13b__col--tech .f13b__bar { background: linear-gradient(180deg, #0D78D0 0%, #023056 100%); }
.f13b__col--people .f13b__bar { background: linear-gradient(180deg, #FF9A23 0%, #CC5200 100%); }
.f13b__col--nature .f13b__bar { background: linear-gradient(180deg, #39BE49 21%, #23742C 100%); }
/* PROMOTED Figma frame 13 line 92-93 — main + parenthetical stacked vertically */
.f13b__bar-main {
font-size: var(--font-sub-title); /* 12px — main word "기술/사람/자연" */
font-weight: 700;
line-height: 1.2;
display: block;
}
.f13b__bar-paren {
font-size: var(--font-caption); /* 10px — "(디지털/역량/여건)" */
font-weight: 500;
line-height: 1.2;
display: block;
opacity: 0.95;
}
.f13b__body {
flex: 1;
display: flex; flex-direction: column;
padding: 8px 12px; /* breathing (was 6px 10px) */
min-width: 0;
overflow: hidden;
}
.f13b__section {
flex: 1;
padding: 6px 0; /* breathing (was 4px) */
overflow: hidden;
min-height: 0;
}
.f13b__section + .f13b__section {
border-top: 2px dashed #000; /* PROMOTED line 103 */
margin-top: 6px; /* visible section gap (was 4px) */
padding-top: 8px; /* breathing (was 6px) */
}
/* heading — 부소목차 (사용자 5-layer 직설 2026-05-07): Digital 기술과... 같은 깊이 1 굵은 bullet */
.f13b__heading {
font-size: var(--font-sub-title); /* 12px — 부소목차 위계 */
font-weight: 700;
line-height: var(--lh-sub-title);
-webkit-background-clip: text; background-clip: text;
color: transparent;
margin-bottom: 6px; /* visible heading-body gap (was 4px) */
}
.f13b__col--tech .f13b__heading { background-image: linear-gradient(180deg, #0D78D0 0%, #134D7F 100%); }
.f13b__col--people .f13b__heading { background-image: linear-gradient(180deg, #FE900C 0%, #D18B37 100%); }
.f13b__col--nature .f13b__heading { background-image: linear-gradient(180deg, #3CA649 21%, #23742C 100%); }
/* desc — frame-family text layout contract (.text-line 공통 클래스 사용)
feedback (mvp1.5b_test5): browser-native ul/li 폐기. */
.f13b__desc {
color: #3E3523; /* PROMOTED line 118 */
overflow: hidden;
}
/* desc 안 .text-line 색 override */
.f13b__desc .text-line { color: #3E3523; }
</style>
<div class="f13b" data-frame-id="1171281190" data-template-id="three_parallel_requirements">
<div class="f13b__title">1. DX 시행을 위한 필수 요건</div>
<div class="f13b__cols">
<div class="f13b__col f13b__col--tech">
<div class="f13b__bar">
<span class="f13b__bar-main">기술</span>
<span class="f13b__bar-paren">(디지털)</span>
</div>
<div class="f13b__body">
<div class="f13b__section">
<div class="f13b__heading">Digital 기술(S/W, H/W)과 업무 Process의 통합</div>
<div class="f13b__desc">
<div class="text-line text-line--bullet">기존 업무 프로세스에 다양한 디지털 기술을 접목하여 업무 수행</div><div class="text-line text-line--bullet">프로젝트 전반에 걸친 업무 프로세스의 연결 및 조율</div>
</div>
</div>
<div class="f13b__section">
<div class="f13b__heading">분야별 전문 지식(설계, 시공, 유지관리 등) 보유</div>
<div class="f13b__desc">
<div class="text-line text-line--bullet">건설 전 단계에 대한 근본적인 이해와 지식 및 경험</div><div class="text-line text-line--bullet">최신 토목 기술 트랜드 및 표준 기준 등에 대한 높은 지식</div>
</div>
</div>
</div>
</div>
<div class="f13b__col f13b__col--people">
<div class="f13b__bar">
<span class="f13b__bar-main">사람</span>
<span class="f13b__bar-paren">(역량)</span>
</div>
<div class="f13b__body">
<div class="f13b__section">
<div class="f13b__heading">혁신적 사고방식과 창의적 문제 해결 능력</div>
<div class="f13b__desc">
<div class="text-line text-line--bullet">기존 수행 방식과 관습적 사고 등에 의한 접근 방식 탈피</div><div class="text-line text-line--bullet">디지털 기술을 활용한 창의적, 혁신적인 솔루션 제시</div>
</div>
</div>
<div class="f13b__section">
<div class="f13b__heading">사용자 중심 사고와 DX 수행 경험</div>
<div class="f13b__desc">
<div class="text-line text-line--bullet">사용자의 요구와 기대를 충족시키는 설계 및 구현</div><div class="text-line text-line--bullet">시행착오를 포함한 수행 경험과 사용자 경험(UX)을 반영한 해결 방안 제시</div>
</div>
</div>
</div>
</div>
<div class="f13b__col f13b__col--nature">
<div class="f13b__bar">
<span class="f13b__bar-main">자연</span>
<span class="f13b__bar-paren">(여건)</span>
</div>
<div class="f13b__body">
<div class="f13b__section">
<div class="f13b__heading">지속적인 투자 및 실행 의지</div>
<div class="f13b__desc">
<div class="text-line text-line--bullet">기술 도입 초기 단계에 필요한 인력·기간·비용 등의 대규모 투자</div><div class="text-line text-line--bullet">기술 고도화를 위한 지속적인 개선 및 투자 체계 구축</div><div class="text-line text-line--bullet">변화와 혁신을 통해 부가가치를 창출하려는 실행 의지와 추진력</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="zone" data-zone-position="bottom" data-template-id="process_product_two_way" style="grid-area: bottom;">
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
<style>
.f29b {
width: 100%; height: 100%;
display: flex; flex-direction: column;
gap: 4px;
position: relative;
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
word-break: keep-all;
overflow: hidden;
}
.f29b__title {
font-size: var(--font-zone-title); /* 13px — frame 13 의 f13b__title 과 동일 위계 */
font-weight: 700;
line-height: var(--lh-zone-title);
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
flex-shrink: 0;
padding-left: 4px;
}
/* banners — top */
.f29b__banners {
flex: 0 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4px;
position: relative;
height: 36px;
}
.f29b__banner {
position: relative;
overflow: hidden;
display: flex; align-items: center; justify-content: center;
}
/* PROMOTED background gradients — figma origin lines 84-98 (header-bg--left/right).
원본 SVG 3 개 → CSS gradient 로 재현 (R8/R9 준수). border-radius 9999px = 자동 pill. */
.f29b__banner--left {
background: linear-gradient(to right,
rgba(136, 131, 118, 0.343) 0%,
#39321E 73.1%,
#39321E 100%);
border-radius: 0 9999px 9999px 0;
}
.f29b__banner--right {
background: linear-gradient(to right,
#032118 0%,
rgba(41, 107, 85, 0.1) 100%);
border-radius: 9999px 0 0 9999px;
}
.f29b__banner-text {
position: relative;
z-index: 1;
font-size: var(--font-sub-title);
font-weight: 900;
line-height: 1;
text-shadow: 0 0 2px #322C1E;
-webkit-background-clip: text; background-clip: text;
color: transparent;
padding: 0 8px;
}
/* PROMOTED gradient — lines 101-104 / 110-113 */
.f29b__banner--left .f29b__banner-text {
background-image:
linear-gradient(90deg, rgb(62,53,35) 0%, rgb(62,53,35) 100%),
linear-gradient(180deg, rgb(41,107,85) 0%, rgb(18,51,40) 100%);
}
.f29b__banner--right .f29b__banner-text {
background-image:
linear-gradient(90deg, rgb(34,95,74) 0%, rgb(34,95,74) 100%),
linear-gradient(180deg, rgb(41,107,85) 0%, rgb(18,51,40) 100%);
}
/* body — 6 cell grid (3 rows × 2 cols) — 좌우 row divider Y 정렬 */
/* PROMOTED background — figma origin lines 53-68 (body-bg-left/right).
좌(0~50%): #39321E α0.3 (top) → white α0.3 (bottom)
우(50~100%): #296B55 α0.3 (top) → white α0.3 (bottom)
원본 SVG → CSS multi-bg 로 재현. */
.f29b__body {
flex: 1;
position: relative;
min-height: 0;
padding-top: 4px;
background:
linear-gradient(to bottom, rgba(57,50,30,0.3) 0%, rgba(255,255,255,0.3) 100%) 0% 0% / 50% 100% no-repeat,
linear-gradient(to bottom, rgba(41,107,85,0.3) 0%, rgba(255,255,255,0.3) 100%) 100% 0% / 50% 100% no-repeat;
}
/* 6 cell grid: 3 rows (section 1/2/3), 2 cols (process/product). 각 row 의 height = max(좌, 우) */
.f29b__grid {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-rows: auto;
gap: 6px 10px;
padding: 4px 8px;
height: 100%;
align-content: start;
}
.f29b__cell {
overflow: hidden;
min-width: 0;
min-height: 0;
}
/* row 2/3 (3 번째 cell 이후) 위에 dashed divider — 좌우 같은 Y */
.f29b__cell:nth-child(n+3) {
border-top: 1px dashed rgba(0,0,0,0.15);
padding-top: 6px;
margin-top: 4px;
}
/* section-title — 부소목차 (사용자 5-layer 직설 2026-05-07): Analogue 기반... 같은 깊이 0 굵은 bullet */
.f29b__section-title {
font-size: var(--font-sub-title); /* 12px — 부소목차 위계 */
font-weight: 900;
line-height: 1.3;
margin-bottom: 5px;
padding-left: 6px;
border-left: 3px solid currentColor;
}
.f29b__cell--left .f29b__section-title { color: #5C3714; } /* PROMOTED line 125 */
.f29b__cell--right .f29b__section-title { color: #084C56; } /* PROMOTED line 126 */
.f29b__section-title__sub {
font-size: var(--font-caption); /* 10px */
margin-left: 3px;
}
/* f29b 의 본문 = .text-line 공통 contract 사용. bullet color override. */
.f29b__cell .text-line--bullet { color: #000; font-weight: 700; }
/* AS-IS/TO-BE 좌우 + arrow (PROMOTED 구조) */
.f29b__transform {
display: grid;
grid-template-columns: 1fr auto 1fr;
gap: 4px;
align-items: start;
}
.f29b__transform__list {
/* .text-line 공통 contract 그대로. wrapper 만 grid 안의 cell 역할 */
}
.f29b__transform__arrow {
align-self: center;
width: 28px;
flex-shrink: 0;
}
.f29b__transform__arrow img {
width: 100%;
height: auto;
display: block;
}
.f29b__footnote {
font-size: var(--font-caption); /* 10px */
line-height: var(--lh-caption);
color: #333;
padding-left: 14px;
margin-top: 1px;
white-space: pre-wrap;
}
.f29b__aster-small { font-size: 9px; }
</style>
<div class="f29b" data-frame-id="1171281210" data-template-id="process_product_two_way">
<div class="f29b__title">2. Process의 혁신과 Product의 변화</div>
<div class="f29b__banners">
<div class="f29b__banner f29b__banner--left">
<div class="f29b__banner-text">과정(Process)의 혁신</div>
</div>
<div class="f29b__banner f29b__banner--right">
<div class="f29b__banner-text">결과(Product)의 변화</div>
</div>
</div>
<div class="f29b__body">
<div class="f29b__grid">
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">Analogue 기반 업무의 Digital화</div>
<div class="transform-block">
<div class="transform-block__header">
<span class="transform-block__label--from">AS-IS</span>
<span></span>
<span class="transform-block__label--to">TO-BE</span>
</div>
<div class="transform-rows">
<div class="transform-row">
<div class="transform-row__from">개념·문서·행정 절차 중심</div>
<div class="transform-row__arrow"></div>
<div class="transform-row__to">시각화된 목적물, 소통, 투명성 중심</div>
</div>
<div class="transform-row">
<div class="transform-row__from">2D 도면, 전문가, 규정</div>
<div class="transform-row__arrow"></div>
<div class="transform-row__to">3D 모델, 참여자, 실체</div>
</div>
<div class="transform-row">
<div class="transform-row__from">업무 구분(단절), 책임</div>
<div class="transform-row__arrow"></div>
<div class="transform-row__to">협업(융·복합), 창의성</div>
</div>
</div>
</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">Copy & Paste로 인해 하향 평준화된 기존 성과물의 품질 향상</div>
<div class="text-line text-line--bullet">과거 수작업으로 시행하면서 발생하던 오류 등의 최소화</div><div class="text-line text-line--bullet">정확한 Data에 기반한 계획으로 고품질 성과물 도출</div>
</div>
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">GIS + BIM의 연계</div>
<div class="text-line text-line--bullet">지리·지형·지반 등 위치정보(GIS)와 3D모델(형상, 속성정보) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">Analogue 기반 도서 외 Digital 기반 정보물 추가</div>
<div class="text-line text-line--bullet">기존 성과물(도면, 수량, 계산서, 시방서 등)에 3D 모델, Simulation 등의 Digital 기반 정보물 추가</div>
</div>
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">사용자 중심의 Solution 제공</div>
<div class="text-line text-line--bullet">서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계할 수 있는 설계·시공 Solution 제공</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">Solution을 활용한 업무 효율화</div>
<div class="text-line text-line--bullet">Engn. Solution을 통해 성과물에 관한 이슈를 함께 검토·논의하는 협업 환경 조성</div><div class="text-line text-line--bullet">건설 단계별 정보를 디지털 데이터로 축적하여, 건설 전 과정을 통합관리</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="slide-footer">
<div class="slide-footer-text">DX는 필요한 요건과 체계를 갖춘 후 시행해야만 그 효과를 기대할 수 있다.</div>
</div>
</div>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

@@ -0,0 +1,89 @@
---
title: DX 실행 체계 구축 방안
sidebar:
order: 02
---
## 1. DX 시행을 위한 필수 요건
<br/>
* **기술(디지털)**
* **Digital 기술(S/W, H/W)과 업무 Process의 통합**
* 기존 업무 프로세스에 다양한 디지털 기술을 접목하여 업무 수행
* 프로젝트 전반에 걸친 업무 프로세스의 연결 및 조율
* **분야별 전문 지식(설계, 시공, 유지관리 등) 보유**
* 건설 전 단계에 대한 근본적인 이해와 지식 및 경험
* 최신 토목 기술 트랜드 및 표준 기준 등에 대한 높은 지식
<br/>
* **사람(역량)**
* **혁신적 사고방식과 창의적 문제 해결 능력**
* 기존 수행 방식과 관습적 사고 등에 의한 접근 방식 탈피
* 디지털 기술을 활용한 창의적, 혁신적인 솔루션 제시
* **사용자 중심 사고와 DX 수행 경험**
* 사용자의 요구와 기대를 충족시키는 설계 및 구현
* 시행착오를 포함한 수행 경험과 사용자 경험(UX)을 반영한 해결 방안 제시
<br/>
* **자연(여건)**
* **지속적인 투자 및 실행 의지**
* 기술 도입 초기 단계에 필요한 인력·기간·비용 등의 대규모 투자
* 기술 고도화를 위한 지속적인 개선 및 투자 체계 구축
* 변화와 혁신을 통해 부가가치를 창출하려는 실행 의지와 추진력
<br/>
---
## 2. Process의 혁신과 Product의 변화
<br/>
### 2.1 과정(Process)의 혁신
* **Analogue 기반 업무의 Digital화**
| As-is [Analogue] | 구분 | To-be [Digital] |
| :--- | :---: | :--- |
| **개념·문서·행정 절차 중심** | ➠ | **시각화된 목적물, 소통, 투명성 중심** |
| **2D 도면, 전문가, 규정** | ➠ | **3D 모델, 참여자, 실체** |
| **업무 구분(단절), 책임** | ➠ | **협업(융·복합), 창의성** |
<br/>
* **GIS + BIM의 연계**
* 지리·지형·지반 등 위치정보(GIS)와 3D모델(형상, 속성정보) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신
<br/>
* **사용자 중심의 Solution 제공**
* 서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계할 수 있는 설계·시공 Solution 제공
<br/>
<br/>
### 2.2 결과(Product)의 변화
* **Copy & Paste로 인해 하향 평준화된 기존 성과물의 품질 향상**
* 과거 수작업으로 시행하면서 발생하던 오류 등의 최소화
* 정확한 Data에 기반한 계획으로 고품질 성과물 도출
<br/>
* **Analogue 기반 도서 외 Digital 기반 정보물 추가**
* 기존 성과물(도면, 수량, 계산서, 시방서 등)에 3D 모델, Simulation 등의 Digital 기반 정보물 추가
<br/>
* **Solution을 활용한 업무 효율화**
* Engn. Solution을 통해 성과물에 관한 이슈를 함께 검토·논의하는 협업 환경 조성
* 건설 단계별 정보를 디지털 데이터로 축적하여, 건설 전 과정을 통합관리
<br/>
---
:::note[핵심 요약]
* **DX는 필요한 요건과 체계를 갖춘 후 시행해야만 그 효과를 기대할 수 있다.**
:::
@@ -0,0 +1,21 @@
{
"step_num": 1,
"step_name": "mdx_upload",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"samples\\mdx_batch\\03.mdx"
],
"output": [
"step01_mdx_upload.json",
"step01_mdx_source.md"
],
"note": "MDX 원본 그대로 step01_mdx_source.md 에 복사.",
"data": {
"mdx_path": "samples\\mdx_batch\\03.mdx",
"run_id": "mdx03_f29_fix_check",
"run_dir": "d:\\ad-hoc\\kei\\design_agent\\data\\runs\\mdx03_f29_fix_check\\phase_z2",
"mdx_source_size_bytes": 3213,
"mdx_source_lines": 89
}
}
@@ -0,0 +1,36 @@
{
"step_num": 2,
"step_name": "normalized",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step01_mdx_source.md"
],
"output": [
"step02_normalized.json"
],
"note": "parse_mdx 결과: title / sections / footer 분리 + raw_content 보존. heading tree 미생성, orphan / details 감지 미완 (Step 2 ⚠ partial — 별 axis). orphans / details 필드는 schema lock — 빈 배열이라도 'detection 미수행' marker.",
"data": {
"slide_title": "DX 실행 체계 구축 방안",
"slide_footer": "DX는 필요한 요건과 체계를 갖춘 후 시행해야만 그 효과를 기대할 수 있다.",
"sections_count": 2,
"sections": [
{
"section_id": "03-1",
"section_num": 1,
"title": "1. DX 시행을 위한 필수 요건",
"raw_content_length": 660,
"raw_content": "<br/>\n\n* **기술(디지털)**\n * **Digital 기술(S/W, H/W)과 업무 Process의 통합**\n * 기존 업무 프로세스에 다양한 디지털 기술을 접목하여 업무 수행\n * 프로젝트 전반에 걸친 업무 프로세스의 연결 및 조율\n * **분야별 전문 지식(설계, 시공, 유지관리 등) 보유**\n * 건설 전 단계에 대한 근본적인 이해와 지식 및 경험\n * 최신 토목 기술 트랜드 및 표준 기준 등에 대한 높은 지식\n\n<br/>\n\n* **사람(역량)**\n * **혁신적 사고방식과 창의적 문제 해결 능력**\n * 기존 수행 방식과 관습적 사고 등에 의한 접근 방식 탈피\n * 디지털 기술을 활용한 창의적, 혁신적인 솔루션 제시\n * **사용자 중심 사고와 DX 수행 경험**\n * 사용자의 요구와 기대를 충족시키는 설계 및 구현\n * 시행착오를 포함한 수행 경험과 사용자 경험(UX)을 반영한 해결 방안 제시\n\n<br/>\n\n* **자연(여건)**\n * **지속적인 투자 및 실행 의지**\n * 기술 도입 초기 단계에 필요한 인력·기간·비용 등의 대규모 투자\n * 기술 고도화를 위한 지속적인 개선 및 투자 체계 구축\n * 변화와 혁신을 통해 부가가치를 창출하려는 실행 의지와 추진력\n\n<br/>\n---"
},
{
"section_id": "03-2",
"section_num": 2,
"title": "2. Process의 혁신과 Product의 변화",
"raw_content_length": 924,
"raw_content": "<br/>\n\n### 2.1 과정(Process)의 혁신\n\n* **Analogue 기반 업무의 Digital화**\n\n | As-is [Analogue] | 구분 | To-be [Digital] |\n | :--- | :---: | :--- |\n | **개념·문서·행정 절차 중심** | ➠ | **시각화된 목적물, 소통, 투명성 중심** |\n | **2D 도면, 전문가, 규정** | ➠ | **3D 모델, 참여자, 실체** |\n | **업무 구분(단절), 책임** | ➠ | **협업(융·복합), 창의성** |\n\n<br/>\n\n* **GIS + BIM의 연계**\n * 지리·지형·지반 등 위치정보(GIS)와 3D모델(형상, 속성정보) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신\n\n<br/>\n\n* **사용자 중심의 Solution 제공**\n * 서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계할 수 있는 설계·시공 Solution 제공\n\n<br/>\n<br/>\n\n### 2.2 결과(Product)의 변화\n\n* **Copy & Paste로 인해 하향 평준화된 기존 성과물의 품질 향상**\n * 과거 수작업으로 시행하면서 발생하던 오류 등의 최소화\n * 정확한 Data에 기반한 계획으로 고품질 성과물 도출\n\n<br/>\n\n* **Analogue 기반 도서 외 Digital 기반 정보물 추가**\n * 기존 성과물(도면, 수량, 계산서, 시방서 등)에 3D 모델, Simulation 등의 Digital 기반 정보물 추가\n\n<br/>\n\n* **Solution을 활용한 업무 효율화**\n * Engn. Solution을 통해 성과물에 관한 이슈를 함께 검토·논의하는 협업 환경 조성\n * 건설 단계별 정보를 디지털 데이터로 축적하여, 건설 전 과정을 통합관리\n\n<br/>\n---"
}
],
"orphans": [],
"details": []
}
}
@@ -0,0 +1,63 @@
{
"step_num": 5,
"step_name": "v4_evidence",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step02_normalized.json",
"tests/matching/v4_full32_result.yaml"
],
"output": [
"step05_v4_evidence.json"
],
"note": "V4 non-reject max-6 후보 list (Step 9 application_plan input). raw 32 entry 는 tests/matching/v4_full32_result.yaml 에 영속. candidate_status='ok' = 후보 1개 이상 / 'no_non_reject_v4_candidate' = 0개 (Step 9 fallback path 입력). Step 6 plan_composition() 은 lookup_v4_match() (rank-1) 그대로 사용 — backward compat (Step 6-A axis 까지).",
"data": {
"v4_source": "tests\\matching\\v4_full32_result.yaml",
"aligned_section_ids": [
"03-1",
"03-2"
],
"evidence_per_section": [
{
"section_id": "03-1",
"v4_candidates": [
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"frame_number": 13,
"confidence": 0.9268,
"label": "use_as_is"
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"frame_number": 20,
"confidence": 0.8413,
"label": "light_edit"
}
],
"candidate_status": "ok"
},
{
"section_id": "03-2",
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.9198,
"label": "use_as_is"
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"frame_number": 27,
"confidence": 0.6278,
"label": "restructure"
}
],
"candidate_status": "ok"
}
]
}
}
@@ -0,0 +1,180 @@
{
"step_num": 6,
"step_name": "composition_plan",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step02_normalized.json",
"step05_v4_evidence.json"
],
"output": [
"step06_composition_plan.json"
],
"note": "composition v0 count-based — sections → candidates → score → greedy select. Step 6-A (사용자 lock 2026-05-08): selected_units[i].v4_candidates 추가 (non-reject max-6 후보 list, candidates[0] = 단일 frame_* 와 일관). logic 무변 — runtime 결과 동일. Step 9 application_plan input.",
"data": {
"selected_units_count": 2,
"layout_preset_decided": "horizontal-2",
"candidates_summary": [
{
"source_section_ids": [
"03-1"
],
"merge_type": "single",
"template_id": "three_parallel_requirements",
"label": "use_as_is",
"phase_z_status": "matched_zone",
"score": 0.9268,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 3,
"source_shape": "top_bullets",
"capacity": {
"strict": 3,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
},
{
"source_section_ids": [
"03-2"
],
"merge_type": "single",
"template_id": "process_product_two_way",
"label": "use_as_is",
"phase_z_status": "matched_zone",
"score": 0.9198,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"candidates_total": 2,
"candidates_viable_auto": 2,
"selected_units": [
{
"source_section_ids": [
"03-1"
],
"merge_type": "single",
"frame_id": "1171281190",
"frame_number": 13,
"frame_template_id": "three_parallel_requirements",
"label": "use_as_is",
"score": 0.9268,
"phase_z_status": "matched_zone",
"rationale": {
"capacity_fit": {
"item_count": 3,
"source_shape": "top_bullets",
"capacity": {
"strict": 3,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.9268,
"confidence": 0.9268,
"label": "use_as_is",
"label_weight": 1.0,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"notes": [],
"v4_candidates": [
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"frame_number": 13,
"confidence": 0.9268,
"label": "use_as_is"
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"frame_number": 20,
"confidence": 0.8413,
"label": "light_edit"
}
]
},
{
"source_section_ids": [
"03-2"
],
"merge_type": "single",
"frame_id": "1171281210",
"frame_number": 29,
"frame_template_id": "process_product_two_way",
"label": "use_as_is",
"score": 0.9198,
"phase_z_status": "matched_zone",
"rationale": {
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.9198,
"confidence": 0.9198,
"label": "use_as_is",
"label_weight": 1.0,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"notes": [],
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.9198,
"label": "use_as_is"
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"frame_number": 27,
"confidence": 0.6278,
"label": "restructure"
}
]
}
]
}
}
@@ -0,0 +1,79 @@
{
"step_num": 7,
"step_name": "layout",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step06_composition_plan.json"
],
"output": [
"step07_layout.json",
"step07_selected_layout.html"
],
"note": "count-based v0 — 들여쓰기 / 정렬 미세 layout 미구현 (Step 7 ⚠ partial). Step 7-conn (사용자 lock 2026-05-08): unit_count → layout_candidates list (select_layout_candidates) artifact 기록. default 결정 자체는 무변 — candidates[0] 가 default (default_selection: true), 나머지는 alternative. Step 9 application_plan input.",
"data": {
"layout_preset": "horizontal-2",
"layout_css": {
"areas": "\"top\" \"bottom\"",
"cols": "1fr",
"rows": "228px 343px",
"heights_px": [
228,
343
],
"ratios": [
0.39,
0.586
],
"computation": "min_height_first + content_weight_distribution",
"dynamic_rows": true,
"raw_zone_layout": {
"computation": "min_height_first + content_weight_distribution",
"slide_body_height": 585,
"gap": 14,
"available_after_gap": 571,
"min_heights_px": [
228,
342
],
"min_scaled": true,
"total_min_height": 570,
"remaining_after_min": 1,
"content_weights": [
{
"position": "top",
"template_id": "three_parallel_requirements",
"score": 4.425
},
{
"position": "bottom",
"template_id": "process_product_two_way",
"score": 7.305
}
],
"weight_shares": [
0.377,
0.623
],
"extras_px": [
0,
1
],
"heights_px": [
228,
343
],
"ratios": [
0.39,
0.586
]
}
},
"zones_count": 2,
"unit_count": 2,
"layout_candidates": [
"horizontal-2",
"vertical-2"
]
}
}
@@ -0,0 +1,122 @@
{
"step_num": 8,
"step_name": "zone_region_ratios",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step07_layout.json",
"step10_frame_contract.json"
],
"output": [
"step08_zone_region_ratios.json",
"step08_zone_content_placement.html"
],
"note": "계획값 only. 실측값은 Step 14 (visual_check). zone-level 만 dynamic, region-level (sub_zone 안 sections) 은 균등 분배 (1/1/1). F29 처럼 비균등 콘텐츠 (transform_table + plain) 는 첫 cell 부족 가능 — Step 8 ⚠ partial. Step 8-conn (사용자 lock 2026-05-08): per_zone_plan[i] 에 region_layout_candidates + display_strategy_candidates 추가 (passive 기록). placeholder signals = text-only / region_count=1 (Step 3/4 부재 종속). 실제 content_object 신호 활성화는 별 axis. Step 9 application_plan input.",
"data": {
"zone_heights_px_planned": [
228,
343
],
"zone_ratios_planned": [
0.39,
0.586
],
"per_zone_plan": [
{
"position": "top",
"zone_height_px_planned": 228,
"zone_ratio_planned": 0.39,
"min_height_px": 230,
"frame_cardinality_strict": 3,
"sub_zones_planned": [
{
"id": "pillar_1",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": 1,
"partial_target_path": ".f13b__cols > .f13b__col:nth-child(1)"
},
{
"id": "pillar_2",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": 1,
"partial_target_path": ".f13b__cols > .f13b__col:nth-child(2)"
},
{
"id": "pillar_3",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": 1,
"partial_target_path": ".f13b__cols > .f13b__col:nth-child(3)"
}
],
"child_distribution_note": "현재 child zone (sub_zones 안 sections) 균등 분배 — Step 8 region-level ratio ⚠ partial.",
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
]
},
{
"position": "bottom",
"zone_height_px_planned": 343,
"zone_ratio_planned": 0.586,
"min_height_px": 345,
"frame_cardinality_strict": 2,
"sub_zones_planned": [
{
"id": "process_column",
"role": "main_text",
"accepts": [
"text_block",
"transform_table"
],
"cardinality_strict": 3,
"partial_target_path": ".f29b__grid .f29b__cell--left"
},
{
"id": "product_column",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": 3,
"partial_target_path": ".f29b__grid .f29b__cell--right"
}
],
"child_distribution_note": "현재 child zone (sub_zones 안 sections) 균등 분배 — Step 8 region-level ratio ⚠ partial.",
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
]
}
],
"step8_conn_placeholder_signals": {
"region_count": 1,
"content_type": "text_block",
"flow_type": null,
"role_pattern": null,
"ratio_asymmetric": false,
"has_visual_element": false,
"details_presence": false,
"large_table": false,
"long_text": false,
"fits_in_region": null,
"_note": "Step 3/4 부재 종속 placeholder — 모든 zone 을 text-only / region_count=1 로 가정. 실제 content_object 신호 활성화는 별 axis."
}
}
}
@@ -0,0 +1,135 @@
{
"step_num": 9,
"step_name": "application_plan",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step05_v4_evidence.json",
"step06_composition_plan.json",
"step07_layout.json",
"step08_zone_region_ratios.json"
],
"output": [
"step09_application_plan.json",
"step09_application_plan.html"
],
"note": "Step 9 v0 passive application_plan trace (사용자 lock 2026-05-08). V4 후보 + layout / region / display 후보 + V4 label → application_mode 변환을 side-by-side 로 기록. v0 invariant 5 가지 (status.md §4) 만족. Step 6 의 default 결정 그대로 (current_default_candidate). auto decision 은 Step 9 v1 (별 axis). region/display 후보는 Step 8-conn 의 placeholder signal 종속 (Step 3/4 부재).",
"data": {
"units": [
{
"unit_id": "03-1",
"layout_preset": "horizontal-2",
"layout_candidates": [
"horizontal-2",
"vertical-2"
],
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
],
"candidate_status": "ok",
"application_status": "ok",
"current_default_candidate": "three_parallel_requirements",
"v4_candidates": [
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"frame_number": 13,
"confidence": 0.9268,
"label": "use_as_is"
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"frame_number": 20,
"confidence": 0.8413,
"label": "light_edit"
}
],
"application_candidates": [
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"v4_label": "use_as_is",
"application_mode": "direct_insert",
"auto_applicable": true,
"required_changes": [],
"delegated_to": "step10_contract_check"
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"v4_label": "light_edit",
"application_mode": "same_frame_with_adjustment",
"auto_applicable": true,
"required_changes": [],
"delegated_to": "step10_contract_check"
}
]
},
{
"unit_id": "03-2",
"layout_preset": "horizontal-2",
"layout_candidates": [
"horizontal-2",
"vertical-2"
],
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
],
"candidate_status": "ok",
"application_status": "ok",
"current_default_candidate": "process_product_two_way",
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.9198,
"label": "use_as_is"
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"frame_number": 27,
"confidence": 0.6278,
"label": "restructure"
}
],
"application_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"v4_label": "use_as_is",
"application_mode": "direct_insert",
"auto_applicable": true,
"required_changes": [],
"delegated_to": "step10_contract_check"
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"v4_label": "restructure",
"application_mode": "layout_or_region_change",
"auto_applicable": false,
"required_changes": [],
"delegated_to": "human_review"
}
]
}
],
"candidate_status_summary": {
"units_with_no_v4_candidate": []
},
"v0_lock_note": "Step 9 v0 passive (사용자 lock 2026-05-08). Step 6 default 그대로 사용 — runtime 결과 byte-동일. auto decision / scoring 은 Step 9 v1 (별 axis)."
}
}
@@ -0,0 +1,38 @@
{
"step_num": 20,
"step_name": "slide_status",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step14_visual_check.json",
"step17_retry_trace.json",
"step19_next_action.json"
],
"output": [
"step20_slide_status.json",
"step20_final_status.html"
],
"note": "자동 파이프라인 최종 결과 보고. overall = PASS/RENDERED_WITH_VISUAL_REGRESSION/PARTIAL_COVERAGE 등.",
"data": {
"rendered": true,
"visual_check_passed": true,
"full_mdx_coverage": true,
"aligned_section_ids": [
"03-1",
"03-2"
],
"covered_section_ids": [
"03-1",
"03-2"
],
"filtered_section_ids": [],
"filtered_section_reasons": [],
"visual_fail_reasons": [],
"adapter_needed_count": 0,
"adapter_needed_units": [],
"content_truncated_count": 0,
"content_truncated_units": [],
"overall": "PASS",
"note": "자동 파이프라인 결과 보고. review/UI 개념 X. final.html 파일명 != PASS 의미. overall == PASS 는 visual OK + full coverage + adapter_needed=0 일 때만. adapter_needed_count > 0 = mapper 가 contract 와 안 맞아 자동 렌더 못 한 zone 존재. content_truncated_count > 0 = builder 가 truncate 한 zone 존재 (rendered 됐지만 일부 콘텐츠 손실)."
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,992 @@
<!-- Phase Z-2 MVP-1.5b — single slide + Type B layout (top/bottom zones).
원래 Phase Z 설계 복귀: MDX 1 = slide 1, layout preset = zone 분할, frame-derived block ⊂ zone. -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280">
<title>DX 지연 요인</title>
<style>
/* ── existing tokens (inlined) ── */
/* === typography.css === */
/* ══════════════════════════════════════
Typography Tokens v1
══════════════════════════════════════
슬라이드 전체의 공통 글자 위계.
모든 블록은 이 토큰을 참조한다.
직접값(font-size: 11px) 금지 → var(--font-body) 사용.
══════════════════════════════════════ */
:root {
/* ── 1층: Global Hierarchy ── */
/* 대목차: 슬라이드 상단 제목 */
--font-slide-title: 22px;
--weight-slide-title: 700;
--lh-slide-title: 1.4;
/* 중목차: zone 제목 */
--font-zone-title: 16px;
--weight-zone-title: 700;
--lh-zone-title: 1.4;
/* 소목차: 블록 내 소제목, 카드 제목 */
--font-sub-title: 12px;
--weight-sub-title: 700;
--lh-sub-title: 1.45;
/* 본문: 블릿, 설명 텍스트 */
--font-body: 10px;
--weight-body: 500;
--lh-body: 1.55;
/* 캡션: 각주, 출처, 보조 텍스트 */
--font-caption: 10px;
--weight-caption: 400;
--lh-caption: 1.4;
/* footer: 핵심 인사이트 pill */
--font-footer: 20px;
--weight-footer: 700;
--lh-footer: 1.2;
/* ── 2층: Component Semantic Tokens ── */
/* 가까운 위계에서 기본값, 필요시 override */
/* 본문 강조 (인라인 heading) */
--font-body-strong: var(--font-body);
--weight-body-strong: 600;
/* 자세히보기 링크 */
--font-detail-link: var(--font-caption);
--weight-detail-link: 500;
/* pill/badge 라벨 */
--font-pill-label: var(--font-sub-title);
--weight-pill-label: 700;
/* 표 헤더 */
--font-table-header: var(--font-sub-title);
--weight-table-header: 700;
/* 표 셀 */
--font-table-cell: var(--font-body);
--weight-table-cell: 400;
/* 비교 뱃지 */
--font-compare-badge: var(--font-sub-title);
--weight-compare-badge: 700;
/* 강조 인용 */
--font-callout: var(--font-sub-title);
--weight-callout: 700;
/* 상단 라벨 (overline) */
--font-overline: var(--font-caption);
--weight-overline: 600;
--ls-overline: 0.05em;
}
/* === spacing.css === */
/* ══════════════════════════════════════
Spacing Tokens v1
══════════════════════════════════════
여백/간격/들여쓰기 공통 기준.
══════════════════════════════════════ */
:root {
/* ── 기본 스케일 ── */
--space-xs: 4px;
--space-sm: 8px;
--space-md: 12px;
--space-lg: 16px;
--space-xl: 24px;
/* ── slide-base 레이아웃 ── */
--slide-padding-x: 40px; /* 본문 좌우 여백 */
--slide-title-left: 52px; /* 대목차 시작 */
--slide-title-top: 22px; /* 대목차 위치 */
--slide-divider-top: 58px; /* 구분선 위치 (slide_base.html 와 일치 2026-05-07) */
--slide-body-top: 76px; /* 본문 시작 (사용자 직설: divider-body 16px) */
--slide-body-height: 585px; /* 본문 높이 (사용자 직설: body-footer 10px) */
--slide-footer-bottom: 8px; /* footer 하단 여백 (slide_base.html 와 일치) */
--slide-footer-height: 41px; /* footer 높이 */
/* ── zone ── */
--zone-gap: 8px; /* zone 간 간격 */
--zone-padding-left: 12px; /* zone 안쪽 좌측 여백 */
--zone-padding-right: 8px; /* zone 안쪽 우측 여백 */
--zone-title-mb: 8px; /* zone 제목 아래 여백 */
/* ── 블록 공통 ── */
--card-padding: 16px; /* 카드 내부 여백 */
--card-padding-sm: 8px; /* 작은 카드 내부 여백 */
--card-gap: 12px; /* 카드 간 간격 */
--card-radius: 6px; /* 카드 모서리 */
/* ── 블릿/텍스트 ── */
--bullet-indent: 14px; /* 불릿 hanging indent */
--bullet-gap: 2px; /* 불릿 항목 간 간격 */
--heading-gap: 4px; /* 소제목 아래 간격 */
--section-gap: 10px; /* 섹션 간 간격 */
/* ── flex/grid 기본 ── */
--flex-gap: 12px; /* 기본 flex gap */
--flex-gap-sm: 6px; /* 좁은 flex gap */
--grid-gap: 16px; /* 기본 grid gap */
}
/* === colors.css === */
/* ══════════════════════════════════════
Color Tokens v1
══════════════════════════════════════
2층 구조: 공통 테마색 + 블록 의미색.
══════════════════════════════════════ */
:root {
/* ══ 1층: 공통 테마색 ══ */
/* 모든 블록이 공유하는 기본 팔레트 */
/* 텍스트 */
--color-title: #1e293b; /* 제목 (진한 남색) */
--color-zone-title: #1a365d; /* zone 중목차 제목 */
--color-body: #475569; /* 본문 */
--color-body-strong: #1e293b; /* 본문 강조 */
--color-caption: #94a3b8; /* 캡션, 보조 */
--color-muted: #64748b; /* 약한 텍스트 */
/* 배경 */
--color-bg: #ffffff; /* 슬라이드 배경 */
--color-bg-subtle: #f8fafc; /* 카드/영역 배경 */
--color-bg-page: #e8ecf0; /* 페이지 배경 (슬라이드 바깥) */
/* 보더 */
--color-border: #e2e8f0; /* 기본 보더 */
--color-border-strong: #cbd5e1; /* 강한 보더 */
/* 강조 */
--color-accent: #2563eb; /* 링크, 강조 (파랑) */
--color-accent-hover: #eff6ff; /* 링크 hover 배경 */
--color-danger: #dc2626; /* 경고, 에러 */
/* slide-base 전용 */
--color-slide-title-from: #296b55; /* 대목차 gradient 시작 */
--color-slide-title-to: #123328; /* 대목차 gradient 끝 */
--color-footer-bg-from: #3b3523; /* footer gradient 시작 */
--color-footer-bg-mid: #263a2a; /* footer gradient 중간 */
--color-footer-bg-to: #113f31; /* footer gradient 끝 */
--color-footer-text: #ffffff; /* footer 텍스트 */
--color-footer-accent: #ffee33; /* footer 강조 (em) */
/* ══ 2층: 블록 의미색 ══ */
/* 특정 블록 유형에서 의미를 가지는 색 */
/* 3열 비교 (prerequisites-3col) */
--color-col-1-from: #0D78D0; /* 1열 gradient 시작 */
--color-col-1-to: #023056; /* 1열 gradient 끝 */
--color-col-2-from: #FF9A23; /* 2열 gradient 시작 */
--color-col-2-to: #CC5200; /* 2열 gradient 끝 */
--color-col-3-from: #39BE49; /* 3열 gradient 시작 */
--color-col-3-to: #23742C; /* 3열 gradient 끝 */
/* 비교 블록 (compare) */
--color-compare-left: #5c3714; /* 좌측 (AS-IS 계열) */
--color-compare-right: #285b4a; /* 우측 (TO-BE 계열) */
--color-compare-badge: #ae3607; /* VS 뱃지 */
/* 다크 카드 (direct render) */
--color-dark-card-1: #1a365d; /* 카드 1 배경 */
--color-dark-card-2: #1e3a2f; /* 카드 2 배경 */
--color-dark-card-3: #3b1f2b; /* 카드 3 배경 */
--color-dark-card-title: #fbbf24; /* 다크카드 제목 (금색) */
--color-dark-card-body: #e2e8f0; /* 다크카드 본문 */
/* 표 */
--color-table-header-bg: #64748b; /* 표 헤더 배경 */
--color-table-header-text: #ffffff; /* 표 헤더 텍스트 */
/* 블록 제목 gradient (Figma 원본) */
--color-block-title-from: #CC5200; /* 주황 gradient 시작 */
--color-block-title-to: #883700; /* 주황 gradient 끝 */
/* pill */
--color-pill-bg: #1e293b; /* pill 배경 */
--color-pill-text: #ffffff; /* pill 텍스트 */
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
background: #e8ecf0;
display: flex; justify-content: center; align-items: center;
min-height: 100vh;
word-break: keep-all;
padding: 20px 0;
}
/* ── 16:9 슬라이드 (single, 1280×720) ── */
.slide {
width: 1280px; height: 720px;
position: relative;
overflow: hidden;
background: #fff;
box-shadow: 0 4px 20px rgba(0,0,0,.15);
flex-shrink: 0;
}
.slide-bg {
position: absolute; inset: 0;
background: linear-gradient(180deg, #f0f0f0 0%, #ffffff 100%);
z-index: 0;
}
.slide-title {
position: absolute;
left: 52px; top: 22px;
width: calc(100% - 104px);
font-weight: 700;
font-size: var(--font-slide-title);
line-height: var(--lh-slide-title);
background-image: linear-gradient(180deg, #296b55 0%, #123328 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
text-shadow: 0 0 2px #322c1e;
z-index: 2;
}
.slide-divider {
position: absolute;
left: 50px; top: 58px;
width: calc(100% - 100px);
height: 2px;
background: #cbd5e1;
z-index: 2;
}
.slide-body {
position: absolute;
left: 50px; top: 76px;
width: calc(100% - 100px); /* 1180 */
height: 585px;
z-index: 1;
overflow: hidden;
}
/* ── Layout preset (composition planner v0 — 8 vocabulary) ──
단일 .layout-{preset} 클래스에 grid CSS 주입.
layout_css = pipeline build_layout_css() 결과 :
- horizontal-2 : rows = dynamic px (content_weight + frame_min_height)
- 그 외 : rows / cols = fr default (LAYOUT_PRESETS)
positions (single / top / bottom / left / right / top-left / ... / grid-2x2 9개)
은 .zone 의 inline grid-area 로 지정 — preset CSS 는 areas 만 정의. */
.layout-horizontal-2 {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 211px 360px;
grid-template-areas: "top" "bottom";
gap: 14px;
height: 100%;
}
/* ── Zone — block 가용 공간 최대화. 프레임 자체 styling 이 boundary 역할 ── */
.zone {
position: relative;
overflow: hidden;
padding: 0;
min-width: 0;
min-height: 0;
}
/* ── Frame-family text layout contract (shared, reusable) ──
feedback-1 (mvp1.5b_test7): visible improvement 강화.
Stronger hanging indent + breathing line spacing + visible hierarchy. */
.text-line {
font-size: var(--font-body); /* 11px */
font-weight: var(--weight-body);
line-height: 1.6; /* breathing room */
margin: 0;
}
.text-line + .text-line {
margin-top: 4px; /* visible gap between lines (was 2px) */
}
/* bullet line — hanging indent via padding + absolute marker (안정적) */
.text-line--bullet {
padding-left: 14px;
position: relative;
}
.text-line--bullet::before {
content: "•"; /* visible bullet 마커 */
position: absolute;
left: 2px;
top: 0;
font-weight: 700;
line-height: inherit;
color: inherit;
}
/* indent levels — visible nested hierarchy */
.text-line--indent-1 {
padding-left: 30px;
}
.text-line--indent-1::before {
content: "◦"; /* sub-bullet 다른 마커 */
left: 18px;
}
.text-line--indent-2 {
padding-left: 46px;
}
.text-line--indent-2::before {
content: "▪";
left: 34px;
}
/* body line — 마커 없음 */
.text-line--body {
padding-left: 0;
}
.text-line strong { color: #000; font-weight: 700; }
/* ── Transform-block family (frame 29 AS-IS/TO-BE dedicated comparison component) ──
feedback-3: bullet rows 가 아닌 *전용 비교 component*. Header (AS-IS / TO-BE) + paired rows.
color-coded cells, left-border accent → 단번에 *비교 구조* 인지. */
.transform-block {
margin-top: 4px;
padding: 6px 8px 6px;
background: rgba(255, 255, 255, 0.4);
border-radius: 3px;
border: 1px solid rgba(0,0,0,0.05);
}
.transform-block__header {
display: grid;
grid-template-columns: 1fr 22px 1fr;
gap: 6px;
margin-bottom: 4px;
padding-bottom: 3px;
border-bottom: 1px dashed rgba(0,0,0,0.12);
font-size: 9px;
font-weight: 900;
letter-spacing: 0.5px;
}
.transform-block__label--from { color: #6b5444; }
.transform-block__label--to { color: #2563eb; text-align: left; }
.transform-rows {
display: flex; flex-direction: column;
gap: 4px;
}
.transform-row {
display: grid;
grid-template-columns: 1fr 22px 1fr;
gap: 6px;
align-items: stretch;
font-size: var(--font-body);
line-height: 1.45;
}
.transform-row__from {
padding: 3px 8px;
background: linear-gradient(90deg, rgba(140,120,90,0.16), rgba(140,120,90,0.08));
border-left: 2px solid #b8a98a;
border-radius: 2px;
color: #4b3f30;
font-weight: 500;
}
.transform-row__arrow {
text-align: center;
color: #2563eb;
font-weight: 900;
font-size: 14px;
align-self: center;
}
.transform-row__to {
padding: 3px 8px;
background: linear-gradient(90deg, rgba(37,99,235,0.10), rgba(37,99,235,0.18));
border-left: 2px solid #2563eb;
border-radius: 2px;
color: #1e40af;
font-weight: 700;
}
/* ── Footer pill — feedback-3: body 와 weight balance, 살짝 가벼워짐 ── */
.slide-footer {
position: absolute;
left: 50px; bottom: 8px;
width: calc(100% - 100px); /* front 기준 (body 와 정렬) */
height: 41px; /* front 기준 */
border-radius: 999px;
overflow: hidden;
z-index: 2;
display: flex; align-items: center; justify-content: center;
background: linear-gradient(90deg, #3b3523 5%, #263a2a 50%, #113f31 95%);
opacity: 0.92; /* slightly lighter */
}
.slide-footer-text {
position: relative; z-index: 1;
font-size: 15px; /* was 20px (--font-footer) */
font-weight: 700;
line-height: 1.2;
color: #fff;
text-align: center;
text-shadow: 0 0 3px rgba(0,0,0,.4);
letter-spacing: -0.01em;
}
.slide-footer-text em { color: #fe3; font-style: normal; }
.phase-z2-marker {
position: absolute;
top: 4px; right: 8px;
font-size: 9px; color: #94a3b8;
font-family: monospace;
z-index: 3;
}
</style>
</head>
<body>
<div class="slide" data-page="1">
<div class="slide-bg"></div>
<div class="phase-z2-marker">phase_z2 / mvp-1.5b / horizontal-2 / single slide</div>
<div class="slide-title">DX 지연 요인</div>
<div class="slide-divider"></div>
<div class="slide-body">
<div class="layout-horizontal-2">
<div class="zone" data-zone-position="top" data-template-id="pre_construction_model_info_stacked" style="grid-area: top;">
<!-- Phase Z-2 신규 frame partial — Frame 9 (1171281180) pre_construction_model_info_stacked.
2026-05-14 — V4 04-1 top rank-1 매칭 (의미 conf=0.722) + structure cardinality 5 일치.
사용자 룰 부합 : Figma visual (계단 pill / 5 색상 / vertical label) 유지 + 콘텐츠 cardinality
에 맞춰 보완 (pill 안 1 라인 → multi-line: pill_N_label + pill_N_body). -->
<style>
.f9b {
width: 100%; height: 100%;
display: flex; flex-direction: column;
gap: 6px;
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
word-break: keep-all;
position: relative;
}
/* 2026-05-14 — title 스타일 통일 (frame 29 process_product_two_way 와 동일 패턴) :
배경 box + box-shadow 제거, gradient 텍스트 만 유지. 사용자 룰 Q1. */
.f9b__title {
font-size: var(--font-zone-title);
font-weight: 700;
line-height: var(--lh-zone-title);
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
flex-shrink: 0;
padding-left: 4px;
}
.f9b__body {
flex: 1;
display: flex;
flex-direction: row;
gap: 8px;
min-height: 0;
}
/* 좌측 vertical label — 콘텐츠 있을 때만 표시 */
.f9b__vlabel {
flex: 0 0 auto;
width: 56px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: var(--font-sub-title);
line-height: 1.2;
color: #144838;
text-align: center;
writing-mode: vertical-rl;
text-orientation: upright;
text-shadow: 0 2px 2px rgba(0,0,0,0.15);
}
/* 2026-05-14 — pill 배치 vertical → horizontal (grid). 5 pills 를 가로로 나열 →
우측 공란 활용 + 세로 공간 절약. auto-fit + minmax 으로 N 동적 (4 / 5 / 6 모두 자동). */
.f9b__pill-rows {
flex: 1;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 6px;
min-height: 0;
}
/* 2026-05-14 — bullet 줄간격 1/3 으로 압축 + 다른 간격 (padding, label↔body) 살짝 늘림. */
.f9b__pill {
min-height: 0;
background: rgba(255,255,255,0.7);
border-radius: 10px;
border-bottom: 3px solid;
box-shadow: 1px 2px 4px rgba(0,0,0,0.15);
padding: 8px 12px;
display: flex;
flex-direction: column;
gap: 5px;
overflow: hidden;
align-self: start;
}
/* Figma frame 9 의 5 색상 — nth-child cycle. N>5 면 default border-bottom 색 (회색). */
.f9b__pill:nth-child(5n+1) { border-bottom-color: #fb5915; }
.f9b__pill:nth-child(5n+2) { border-bottom-color: #e79000; }
.f9b__pill:nth-child(5n+3) { border-bottom-color: #e9a804; }
.f9b__pill:nth-child(5n+4) { border-bottom-color: #919f00; }
.f9b__pill:nth-child(5n) { border-bottom-color: #0d6361; }
.f9b__pill-label {
font-size: var(--font-sub-title);
font-weight: 900;
line-height: 1.2;
color: #144838;
margin-bottom: 4px;
display: flex;
align-items: center;
gap: 6px;
}
/* arrow indicator — Figma frame 9 의 좌측 화살표 (▶) approximation */
.f9b__pill-label::before {
content: "▶";
flex-shrink: 0;
color: currentColor;
font-size: 0.85em;
}
/* 2026-05-14 — bullet 줄간격 1/3 으로 압축 : line-height 1.3 → 1.05 (약 1/3 감소).
bullet 간 gap 2 → 1 로 더 압축. 가독성 임계 (한 bullet 안 line wrap 시 라인 겹침 직전). */
.f9b__pill-body {
flex: 1 1 auto;
overflow: hidden;
min-height: 0;
color: #0c271e;
font-size: var(--font-body);
line-height: 1.05;
display: flex;
flex-direction: column;
gap: 1px;
}
/* 첫 line = 인용구 (italic + 무 마커) — 04-1 의 따옴표 인용구 패턴 */
.f9b__pill-body .text-line:first-child {
font-style: italic;
color: #5C3714;
padding-left: 0;
}
/* 이후 lines = 각 이슈 bullet (▪ 마커로 구분 강화) */
.f9b__pill-body .text-line:not(:first-child) {
position: relative;
padding-left: 12px;
}
.f9b__pill-body .text-line:not(:first-child)::before {
content: "▪";
position: absolute;
left: 0;
color: #919f00;
font-size: 0.9em;
}
</style>
<div class="f9b" data-frame-id="1171281180" data-template-id="pre_construction_model_info_stacked">
<div class="f9b__title">1. DX에 대한 인식</div>
<div class="f9b__body">
<div class="f9b__pill-rows">
<div class="f9b__pill" data-frame-slot-id="pill_dynamic" data-pill-n="1">
<div class="f9b__pill-label">기술 및 소프트웨어 이해도</div>
<div class="f9b__pill-body">
<div class="text-line">"무슨 말인지 잘 모르겠다, 어디까지 어떻게 해야 하는지 모르겠다"</div><div class="text-line">기본지침, 시행지침 등 새롭게 알아야 할 게 너무 많다.</div><div class="text-line">3D 모델과 별 차이점을 모르겠다. S/W마다 사용법이 다르다.</div><div class="text-line">필요한 것은 쉽고 간단한 건데, 왜 이렇게 복잡하게 만들까?</div>
</div>
</div>
<div class="f9b__pill" data-frame-slot-id="pill_dynamic" data-pill-n="2">
<div class="f9b__pill-label">효과와 효율성</div>
<div class="f9b__pill-body">
<div class="text-line">"2D 설계 후 전환설계를 수행하는데 효과는 모르겠고, 효율은 낮다"</div><div class="text-line">성과품 작성은 기존과 같게 하고, 추가 업무만 발생해 효율이 낮다.</div><div class="text-line">BIM으로 인해 가중되는 업무 대비 효과가 거의 없어 보인다.</div><div class="text-line">결과적으로 큰 차이를 못 느끼겠고, 이런 노력이 정말 가치 있는 일이야?</div>
</div>
</div>
<div class="f9b__pill" data-frame-slot-id="pill_dynamic" data-pill-n="3">
<div class="f9b__pill-label">인력 및 교육</div>
<div class="f9b__pill-body">
<div class="text-line">"수행 인력이 부족하고, 기존 직원들은 어떻게 교육해야 하나"</div><div class="text-line">교육시간 손실로 일손이 더 필요해지고, 적응하는데도 시간이 걸린다.</div><div class="text-line">신입사원은 없고 BIM 수행을 할 수 있는 기술자가 부족하다.</div><div class="text-line">여러 회사의 S/W별 사용법이 달라 새로운 S/W에 적용에 시간이 필요하다.</div>
</div>
</div>
<div class="f9b__pill" data-frame-slot-id="pill_dynamic" data-pill-n="4">
<div class="f9b__pill-label">경제적 부담</div>
<div class="f9b__pill-body">
<div class="text-line">"S/W 구독료만 크게 발생되고, 비용 보전은 안 된다"</div><div class="text-line">사용해야 할 S/W의 종류가 너무 많고 복잡한데 모두 필요한가?</div><div class="text-line">모든 Project에 적용되는 것도 아닌데, 다수의 S/W 구독료를 내야 한다.</div><div class="text-line">디지털전환 하기 위해 이 비용을 쓰는게 정말 경제적인 이득이 있는 거야?</div>
</div>
</div>
<div class="f9b__pill" data-frame-slot-id="pill_dynamic" data-pill-n="5">
<div class="f9b__pill-label">실무 및 적용성</div>
<div class="f9b__pill-body">
<div class="text-line">"실무적 사용에 의한 효율성 증진보다는 홍보, PQ용으로 사용한다"</div><div class="text-line">구체적 적용에 의한 비용, 시간, 품질 등의 효과 사례가 없다.</div><div class="text-line">지형, 선형, 도로, 교량 Model을 만드는 S/W가 모두 달라 적용이 어렵다.</div><div class="text-line">속성정보를 반영하지 않은 형상 위주의 3D 모델 제작에만 초점이 맞춰져 있다.</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="zone" data-zone-position="bottom" data-template-id="process_product_two_way" style="grid-area: bottom;">
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
<style>
.f29b {
width: 100%; height: 100%;
display: flex; flex-direction: column;
gap: 4px;
position: relative;
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
word-break: keep-all;
overflow: hidden;
}
.f29b__title {
font-size: var(--font-zone-title); /* 13px — frame 13 의 f13b__title 과 동일 위계 */
font-weight: 700;
line-height: var(--lh-zone-title);
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
flex-shrink: 0;
padding-left: 4px;
}
/* banners — top */
.f29b__banners {
flex: 0 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4px;
position: relative;
height: 36px;
}
.f29b__banner {
position: relative;
overflow: hidden;
display: flex; align-items: center; justify-content: center;
}
/* PROMOTED background gradients — figma origin lines 84-98 (header-bg--left/right).
원본 SVG 3 개 → CSS gradient 로 재현 (R8/R9 준수). border-radius 9999px = 자동 pill. */
.f29b__banner--left {
background: linear-gradient(to right,
rgba(136, 131, 118, 0.343) 0%,
#39321E 73.1%,
#39321E 100%);
border-radius: 0 9999px 9999px 0;
}
.f29b__banner--right {
background: linear-gradient(to right,
#032118 0%,
rgba(41, 107, 85, 0.1) 100%);
border-radius: 9999px 0 0 9999px;
}
.f29b__banner-text {
position: relative;
z-index: 1;
font-size: var(--font-sub-title);
font-weight: 900;
line-height: 1;
text-shadow: 0 0 2px #322C1E;
-webkit-background-clip: text; background-clip: text;
color: transparent;
padding: 0 8px;
}
/* PROMOTED gradient — lines 101-104 / 110-113 */
.f29b__banner--left .f29b__banner-text {
background-image:
linear-gradient(90deg, rgb(62,53,35) 0%, rgb(62,53,35) 100%),
linear-gradient(180deg, rgb(41,107,85) 0%, rgb(18,51,40) 100%);
}
.f29b__banner--right .f29b__banner-text {
background-image:
linear-gradient(90deg, rgb(34,95,74) 0%, rgb(34,95,74) 100%),
linear-gradient(180deg, rgb(41,107,85) 0%, rgb(18,51,40) 100%);
}
/* body — 6 cell grid (3 rows × 2 cols) — 좌우 row divider Y 정렬 */
/* PROMOTED background — figma origin lines 53-68 (body-bg-left/right).
좌(0~50%): #39321E α0.3 (top) → white α0.3 (bottom)
우(50~100%): #296B55 α0.3 (top) → white α0.3 (bottom)
원본 SVG → CSS multi-bg 로 재현. */
.f29b__body {
flex: 1;
position: relative;
min-height: 0;
padding-top: 4px;
background:
linear-gradient(to bottom, rgba(57,50,30,0.3) 0%, rgba(255,255,255,0.3) 100%) 0% 0% / 50% 100% no-repeat,
linear-gradient(to bottom, rgba(41,107,85,0.3) 0%, rgba(255,255,255,0.3) 100%) 100% 0% / 50% 100% no-repeat;
}
/* 6 cell grid: 3 rows (section 1/2/3), 2 cols (process/product). 각 row 의 height = max(좌, 우) */
.f29b__grid {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-rows: auto;
gap: 6px 10px;
padding: 4px 8px;
height: 100%;
}
.f29b__cell {
overflow: hidden;
min-width: 0;
min-height: 0;
}
/* row 2/3 (3 번째 cell 이후) 위에 dashed divider — 좌우 같은 Y */
.f29b__cell:nth-child(n+3) {
border-top: 1px dashed rgba(0,0,0,0.15);
padding-top: 6px;
margin-top: 4px;
}
/* section-title — 부소목차 (사용자 5-layer 직설 2026-05-07): Analogue 기반... 같은 깊이 0 굵은 bullet */
.f29b__section-title {
font-size: var(--font-sub-title); /* 12px — 부소목차 위계 */
font-weight: 900;
line-height: 1.3;
margin-bottom: 5px;
padding-left: 6px;
border-left: 3px solid currentColor;
}
.f29b__cell--left .f29b__section-title { color: #5C3714; } /* PROMOTED line 125 */
.f29b__cell--right .f29b__section-title { color: #084C56; } /* PROMOTED line 126 */
.f29b__section-title__sub {
font-size: var(--font-caption); /* 10px */
margin-left: 3px;
}
/* f29b 의 본문 = .text-line 공통 contract 사용. bullet color override. */
.f29b__cell .text-line--bullet { color: #000; font-weight: 700; }
/* 2026-05-14 — line-line gap 만 1/2 압축 (사용자 lock 정확 의도) :
line-height 1.6 (공통 contract) 유지. .text-line + .text-line margin 4px → 2px. */
.f29b__cell .text-line + .text-line { margin-top: 2px; }
/* popup link — 각 column 끝, 파란색 글씨 (사용자 lock 2026-05-14). */
.f29b__popup-link {
margin-top: 2px;
font-size: var(--font-caption);
font-weight: 600;
color: #1a73e8;
cursor: pointer;
text-decoration: underline;
}
.f29b__popup-link::before { content: "▶ "; font-size: 0.85em; }
/* AS-IS/TO-BE 좌우 + arrow (PROMOTED 구조) */
.f29b__transform {
display: grid;
grid-template-columns: 1fr auto 1fr;
gap: 4px;
align-items: start;
}
.f29b__transform__list {
/* .text-line 공통 contract 그대로. wrapper 만 grid 안의 cell 역할 */
}
.f29b__transform__arrow {
align-self: center;
width: 28px;
flex-shrink: 0;
}
.f29b__transform__arrow img {
width: 100%;
height: auto;
display: block;
}
.f29b__footnote {
font-size: var(--font-caption); /* 10px */
line-height: var(--lh-caption);
color: #333;
padding-left: 14px;
margin-top: 1px;
white-space: pre-wrap;
}
.f29b__aster-small { font-size: 9px; }
</style>
<div class="f29b" data-frame-id="1171281210" data-template-id="process_product_two_way">
<div class="f29b__title">2. DX 추진의 실태</div>
<div class="f29b__banners">
<div class="f29b__banner f29b__banner--left">
<div class="f29b__banner-text">정책 및 발주 체계</div>
</div>
<div class="f29b__banner f29b__banner--right">
<div class="f29b__banner-text">조직 및 수행 역량</div>
</div>
</div>
<div class="f29b__body">
<div class="f29b__grid">
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">실질적 기술 경쟁을 저해하는 정책 집행</div>
<div class="text-line text-line--bullet">모든 설계사가 수행 능력을 갖추었다는 전제하에 정책 시행</div><div class="text-line text-line--bullet">수행 능력이 없는 업체 선정 후 성과품의 수준을 낮추어 시행</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">공학적 개념 정립 부재</div>
<div class="text-line text-line--bullet">DX와 BIM의 차이점을 명확히 구분하지 못하고 접근 방식과 기술적 도구 사이의 혼란만 가중</div><div class="text-line text-line--bullet">단순히 기술적 도구의 사용에 초점을 맞추느라 3D모델 제작 S/W에 과도하게 의존</div>
</div>
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">적용 효과가 있는 사례도 없이 방침부터 도입</div>
<div class="text-line text-line--bullet">DX/BIM 적용에 따른 실무적 이득이 있다고 판단된 사례 부족</div><div class="text-line text-line--bullet">BIM 지침/방침 등을 시행 경험과 효과 검증도 없이 남발</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">‘본업 기술력 확보’ 우선의 개념 부재</div>
<div class="text-line text-line--bullet">고도의 전문지식과 현장 경험이 축적된 Manual의 중요성과 필요성에 대한 이해 부족</div><div class="text-line text-line--bullet">국가·발주처의 지침·방침에만 의존한 업체의 기술력</div>
</div>
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">엔지니어링 S/W에 대한 개념 부재</div>
<div class="text-line text-line--bullet">다양한 엔지니어링 S/W의 특성에 대한 깊은 이해 없이 범용 S/W 선택</div><div class="text-line text-line--bullet">대형 Global S/W 회사에 과도한 의존과 이에 예속되는 방침 남발로 전용 S/W 소멸</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">DX/BIM의 근본 취지와 목표의 이해 부족</div>
<div class="text-line text-line--bullet">DX에 의한 과정의 혁신과 결과물의 변화에 대한 고민 부재</div><div class="text-line text-line--bullet">기술자가 직접 3D모델을 만들고 수정하며 설계를 수행하지 않고, 별도로 외주 처리하여 본질 회피</div>
</div>
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">기술투자(R&D) 없는 성과 창출 기대</div>
<div class="text-line text-line--bullet">단순 BIM S/W만 구입하면 될 것이라는 안일한 생각</div><div class="text-line text-line--bullet">실질적 기술 개발 투자 노력 없이 남들이 하는 대로 하면 된다는 착각</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">과거의 타성에 머무르고 있는 기술자 집단</div>
<div class="text-line text-line--bullet">설계/감리/시공 임직원들의 Digital 무지와 전략적 무지</div><div class="text-line text-line--bullet">교육과 학습을 통한 인재 양성보다 당장 실무 활용이 가능한 타사 인력 빼오기에 집중</div>
</div>
</div>
<div class="f29b__popups" style="display: grid; grid-template-columns: 1fr 1fr; gap: 6px 10px; padding: 0 8px;">
<div>
<div class="f29b__popup-link">발주처 반응</div>
</div>
<div>
<div class="f29b__popup-link">설계·시공업계 반응</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="slide-footer">
<div class="slide-footer-text">검증 없는 정책의 일방적 추진과 조직의 회피, 이해 부족은 DX 지연을 반복시키고 있다.</div>
</div>
</div>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

@@ -0,0 +1,89 @@
---
title: DX 지연 요인
sidebar:
order: 03
---
## 1. DX에 대한 인식
- **기술 및 소프트웨어 이해도**
- "무슨 말인지 잘 모르겠다, 어디까지 어떻게 해야 하는지 모르겠다"
- 기본지침, 시행지침 등 새롭게 알아야 할 게 너무 많다.
- 3D 모델과 별 차이점을 모르겠다. S/W마다 사용법이 다르다.
- 필요한 것은 쉽고 간단한 건데, 왜 이렇게 복잡하게 만들까?
- **효과와 효율성**
- "2D 설계 후 전환설계를 수행하는데 효과는 모르겠고, 효율은 낮다"
- 성과품 작성은 기존과 같게 하고, 추가 업무만 발생해 효율이 낮다.
- BIM으로 인해 가중되는 업무 대비 효과가 거의 없어 보인다.
- 결과적으로 큰 차이를 못 느끼겠고, 이런 노력이 정말 가치 있는 일이야?
- **인력 및 교육**
- "수행 인력이 부족하고, 기존 직원들은 어떻게 교육해야 하나"
- 교육시간 손실로 일손이 더 필요해지고, 적응하는데도 시간이 걸린다.
- 신입사원은 없고 BIM 수행을 할 수 있는 기술자가 부족하다.
- 여러 회사의 S/W별 사용법이 달라 새로운 S/W에 적용에 시간이 필요하다.
- **경제적 부담**
- "S/W 구독료만 크게 발생되고, 비용 보전은 안 된다"
- 사용해야 할 S/W의 종류가 너무 많고 복잡한데 모두 필요한가?
- 모든 Project에 적용되는 것도 아닌데, 다수의 S/W 구독료를 내야 한다.
- 디지털전환 하기 위해 이 비용을 쓰는게 정말 경제적인 이득이 있는 거야?
- **실무 및 적용성**
- "실무적 사용에 의한 효율성 증진보다는 홍보, PQ용으로 사용한다"
- 구체적 적용에 의한 비용, 시간, 품질 등의 효과 사례가 없다.
- 지형, 선형, 도로, 교량 Model을 만드는 S/W가 모두 달라 적용이 어렵다.
- 속성정보를 반영하지 않은 형상 위주의 3D 모델 제작에만 초점이 맞춰져 있다.
<br/>
---
<br/>
## 2. DX 추진의 실태
<br/>
### 2.1 정책 및 발주 체계
- **실질적 기술 경쟁을 저해하는 정책 집행**
- 모든 설계사가 수행 능력을 갖추었다는 전제하에 정책 시행
- 수행 능력이 없는 업체 선정 후 성과품의 수준을 낮추어 시행
<br/>
- **적용 효과가 있는 사례도 없이 방침부터 도입**
- DX/BIM 적용에 따른 실무적 이득이 있다고 판단된 사례 부족
- BIM 지침/방침 등을 시행 경험과 효과 검증도 없이 남발
<br/>
- **엔지니어링 S/W에 대한 개념 부재**
- 다양한 엔지니어링 S/W의 특성에 대한 깊은 이해 없이 범용 S/W 선택
- 대형 Global S/W 회사에 과도한 의존과 이에 예속되는 방침 남발로 전용 S/W 소멸
<br/>
- **기술투자(R&D) 없는 성과 창출 기대**
- 단순 BIM S/W만 구입하면 될 것이라는 안일한 생각
- 실질적 기술 개발 투자 노력 없이 남들이 하는 대로 하면 된다는 착각
<br/>
<details>
<summary style={{cursor: 'pointer', fontWeight: 'bold', color: '#555'}}>발주처 반응</summary>
<img src="/assets/images/발주처반응.png" />
</details>
### 2.2 조직 및 수행 역량
- **공학적 개념 정립 부재**
- DX와 BIM의 차이점을 명확히 구분하지 못하고 접근 방식과 기술적 도구 사이의 혼란만 가중
- 단순히 기술적 도구의 사용에 초점을 맞추느라 3D모델 제작 S/W에 과도하게 의존
<br/>
- **‘본업 기술력 확보’ 우선의 개념 부재**
- 고도의 전문지식과 현장 경험이 축적된 Manual의 중요성과 필요성에 대한 이해 부족
- 국가·발주처의 지침·방침에만 의존한 업체의 기술력
<br/>
- **DX/BIM의 근본 취지와 목표의 이해 부족**
- DX에 의한 과정의 혁신과 결과물의 변화에 대한 고민 부재
- 기술자가 직접 3D모델을 만들고 수정하며 설계를 수행하지 않고, 별도로 외주 처리하여 본질 회피
<br/>
- **과거의 타성에 머무르고 있는 기술자 집단**
- 설계/감리/시공 임직원들의 Digital 무지와 전략적 무지
- 교육과 학습을 통한 인재 양성보다 당장 실무 활용이 가능한 타사 인력 빼오기에 집중
<br/>
<details>
<summary style={{cursor: 'pointer', fontWeight: 'bold', color: '#555'}}>설계·시공업계 반응</summary>
<img src="/assets/images/설계시공업계반응.png" />
</details>
<br/>
---
:::note[핵심 요약]
* 검증 없는 정책의 일방적 추진과 조직의 회피, 이해 부족은 DX 지연을 반복시키고 있다.
:::
@@ -0,0 +1,21 @@
{
"step_num": 1,
"step_name": "mdx_upload",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"samples\\mdx\\04. DX 지연 요인.mdx"
],
"output": [
"step01_mdx_upload.json",
"step01_mdx_source.md"
],
"note": "MDX 원본 그대로 step01_mdx_source.md 에 복사.",
"data": {
"mdx_path": "samples\\mdx\\04. DX 지연 요인.mdx",
"run_id": "mdx04_b3_v12",
"run_dir": "d:\\ad-hoc\\kei\\design_agent\\data\\runs\\mdx04_b3_v12\\phase_z2",
"mdx_source_size_bytes": 4710,
"mdx_source_lines": 89
}
}
@@ -0,0 +1,51 @@
{
"step_num": 2,
"step_name": "normalized",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step01_mdx_source.md"
],
"output": [
"step02_normalized.json"
],
"note": "parse_mdx 결과: title / sections / footer 분리 + raw_content 보존. heading tree 미생성, orphan / details 감지 미완 (Step 2 ⚠ partial — 별 axis). orphans / details 필드는 schema lock — 빈 배열이라도 'detection 미수행' marker. stage0_adapter_diagnostics = IMP-02 chained adapter trace (default OFF canary). stage0_normalized_assets = IMP-03 Step 3 slide-level handoff (popups/images/tables list).",
"data": {
"slide_title": "DX 지연 요인",
"slide_footer": "검증 없는 정책의 일방적 추진과 조직의 회피, 이해 부족은 DX 지연을 반복시키고 있다.",
"sections_count": 2,
"sections": [
{
"section_id": "04-1",
"section_num": 1,
"title": "1. DX에 대한 인식",
"raw_content_length": 934,
"raw_content": "- **기술 및 소프트웨어 이해도**\n - \"무슨 말인지 잘 모르겠다, 어디까지 어떻게 해야 하는지 모르겠다\"\n - 기본지침, 시행지침 등 새롭게 알아야 할 게 너무 많다.\n - 3D 모델과 별 차이점을 모르겠다. S/W마다 사용법이 다르다.\n - 필요한 것은 쉽고 간단한 건데, 왜 이렇게 복잡하게 만들까?\n- **효과와 효율성**\n - \"2D 설계 후 전환설계를 수행하는데 효과는 모르겠고, 효율은 낮다\"\n - 성과품 작성은 기존과 같게 하고, 추가 업무만 발생해 효율이 낮다.\n - BIM으로 인해 가중되는 업무 대비 효과가 거의 없어 보인다.\n - 결과적으로 큰 차이를 못 느끼겠고, 이런 노력이 정말 가치 있는 일이야?\n- **인력 및 교육**\n - \"수행 인력이 부족하고, 기존 직원들은 어떻게 교육해야 하나\"\n - 교육시간 손실로 일손이 더 필요해지고, 적응하는데도 시간이 걸린다.\n - 신입사원은 없고 BIM 수행을 할 수 있는 기술자가 부족하다.\n - 여러 회사의 S/W별 사용법이 달라 새로운 S/W에 적용에 시간이 필요하다.\n- **경제적 부담**\n - \"S/W 구독료만 크게 발생되고, 비용 보전은 안 된다\"\n - 사용해야 할 S/W의 종류가 너무 많고 복잡한데 모두 필요한가?\n - 모든 Project에 적용되는 것도 아닌데, 다수의 S/W 구독료를 내야 한다.\n - 디지털전환 하기 위해 이 비용을 쓰는게 정말 경제적인 이득이 있는 거야?\n- **실무 및 적용성**\n - \"실무적 사용에 의한 효율성 증진보다는 홍보, PQ용으로 사용한다\"\n - 구체적 적용에 의한 비용, 시간, 품질 등의 효과 사례가 없다.\n - 지형, 선형, 도로, 교량 Model을 만드는 S/W가 모두 달라 적용이 어렵다.\n - 속성정보를 반영하지 않은 형상 위주의 3D 모델 제작에만 초점이 맞춰져 있다.\n<br/>\n---\n<br/>"
},
{
"section_id": "04-2",
"section_num": 2,
"title": "2. DX 추진의 실태",
"raw_content_length": 1349,
"raw_content": "<br/>\n\n### 2.1 정책 및 발주 체계\n- **실질적 기술 경쟁을 저해하는 정책 집행** \n - 모든 설계사가 수행 능력을 갖추었다는 전제하에 정책 시행\n - 수행 능력이 없는 업체 선정 후 성과품의 수준을 낮추어 시행 \n<br/>\n- **적용 효과가 있는 사례도 없이 방침부터 도입** \n - DX/BIM 적용에 따른 실무적 이득이 있다고 판단된 사례 부족\n - BIM 지침/방침 등을 시행 경험과 효과 검증도 없이 남발\n<br/>\n- **엔지니어링 S/W에 대한 개념 부재** \n - 다양한 엔지니어링 S/W의 특성에 대한 깊은 이해 없이 범용 S/W 선택\n - 대형 Global S/W 회사에 과도한 의존과 이에 예속되는 방침 남발로 전용 S/W 소멸\n<br/>\n- **기술투자(R&D) 없는 성과 창출 기대** \n - 단순 BIM S/W만 구입하면 될 것이라는 안일한 생각\n - 실질적 기술 개발 투자 노력 없이 남들이 하는 대로 하면 된다는 착각\n<br/>\n<details>\n <summary style={{cursor: 'pointer', fontWeight: 'bold', color: '#555'}}>발주처 반응</summary>\n <img src=\"/assets/images/발주처반응.png\" />\n</details>\n\n### 2.2 조직 및 수행 역량\n- **공학적 개념 정립 부재** \n - DX와 BIM의 차이점을 명확히 구분하지 못하고 접근 방식과 기술적 도구 사이의 혼란만 가중\n - 단순히 기술적 도구의 사용에 초점을 맞추느라 3D모델 제작 S/W에 과도하게 의존\n<br/>\n- **‘본업 기술력 확보’ 우선의 개념 부재** \n - 고도의 전문지식과 현장 경험이 축적된 Manual의 중요성과 필요성에 대한 이해 부족\n - 국가·발주처의 지침·방침에만 의존한 업체의 기술력 \n<br/>\n- **DX/BIM의 근본 취지와 목표의 이해 부족** \n - DX에 의한 과정의 혁신과 결과물의 변화에 대한 고민 부재\n - 기술자가 직접 3D모델을 만들고 수정하며 설계를 수행하지 않고, 별도로 외주 처리하여 본질 회피\n<br/>\n- **과거의 타성에 머무르고 있는 기술자 집단** \n - 설계/감리/시공 임직원들의 Digital 무지와 전략적 무지\n - 교육과 학습을 통한 인재 양성보다 당장 실무 활용이 가능한 타사 인력 빼오기에 집중\n<br/>\n<details>\n <summary style={{cursor: 'pointer', fontWeight: 'bold', color: '#555'}}>설계·시공업계 반응</summary>\n <img src=\"/assets/images/설계시공업계반응.png\" />\n</details>\n<br/>\n---"
}
],
"orphans": [],
"details": [],
"stage0_adapter_diagnostics": {
"enabled": false,
"used": false,
"fallback_reason": null,
"id_reconstruction_log": [],
"adapter_counts": null,
"legacy_counts": {
"sections": 2
}
},
"stage0_normalized_assets": {
"popups": [],
"images": [],
"tables": []
}
}
}
@@ -0,0 +1,41 @@
{
"step_num": 5,
"step_name": "v4_evidence",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step02_normalized.json",
"tests/matching/v4_full32_result.yaml"
],
"output": [
"step05_v4_evidence.json"
],
"note": "V4 non-reject max-6 후보 list (Step 9 application_plan input). raw 32 entry 는 tests/matching/v4_full32_result.yaml 에 영속. candidate_status='ok' = 후보 1개 이상 / 'no_non_reject_v4_candidate' = 0개 (Step 9 fallback path 입력). Step 6 plan_composition() 은 lookup_v4_match() (rank-1) 그대로 사용 — backward compat (Step 6-A axis 까지).",
"data": {
"v4_source": "tests\\matching\\v4_full32_result.yaml",
"aligned_section_ids": [
"04-1",
"04-2"
],
"evidence_per_section": [
{
"section_id": "04-1",
"v4_candidates": [],
"candidate_status": "no_non_reject_v4_candidate"
},
{
"section_id": "04-2",
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.7711,
"label": "light_edit"
}
],
"candidate_status": "ok"
}
]
}
}
@@ -0,0 +1,170 @@
{
"step_num": 6,
"step_name": "composition_plan",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step02_normalized.json",
"step05_v4_evidence.json"
],
"output": [
"step06_composition_plan.json"
],
"note": "composition v0 count-based — sections → candidates → score → greedy select. Step 6-A (사용자 lock 2026-05-08): selected_units[i].v4_candidates 추가 (non-reject max-6 후보 list, candidates[0] = 단일 frame_* 와 일관). logic 무변 — runtime 결과 동일. Step 9 application_plan input.",
"data": {
"selected_units_count": 2,
"layout_preset_decided": "horizontal-2",
"candidates_summary": [
{
"source_section_ids": [
"04-1"
],
"merge_type": "single",
"template_id": "pre_construction_model_info_stacked",
"label": "reject",
"phase_z_status": "fallback_candidate",
"v4_rank": 1,
"selection_path": "rank_1",
"fallback_reason": null,
"score": 0.0,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 5,
"source_shape": "top_bullets",
"capacity": {
"strict": null,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
},
{
"source_section_ids": [
"04-2"
],
"merge_type": "single",
"template_id": "process_product_two_way",
"label": "light_edit",
"phase_z_status": "adapt_matched_zone",
"v4_rank": 2,
"selection_path": "rank_2_fallback",
"fallback_reason": "capacity_mismatch:strict_mismatch",
"score": 0.53977,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"candidates_total": 2,
"candidates_viable_auto": 2,
"selected_units": [
{
"source_section_ids": [
"04-1"
],
"merge_type": "single",
"frame_id": "1171281180",
"frame_number": 9,
"frame_template_id": "pre_construction_model_info_stacked",
"label": "reject",
"v4_rank": 1,
"selection_path": "rank_1",
"fallback_reason": null,
"score": 0.0,
"phase_z_status": "fallback_candidate",
"rationale": {
"capacity_fit": {
"item_count": 5,
"source_shape": "top_bullets",
"capacity": {
"strict": null,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.0,
"confidence": 0.7223,
"label": "reject",
"label_weight": 0.0,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"notes": [],
"v4_candidates": []
},
{
"source_section_ids": [
"04-2"
],
"merge_type": "single",
"frame_id": "1171281210",
"frame_number": 29,
"frame_template_id": "process_product_two_way",
"label": "light_edit",
"v4_rank": 2,
"selection_path": "rank_2_fallback",
"fallback_reason": "capacity_mismatch:strict_mismatch",
"score": 0.53977,
"phase_z_status": "adapt_matched_zone",
"rationale": {
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.5398,
"confidence": 0.7711,
"label": "light_edit",
"label_weight": 0.7,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"notes": [],
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.7711,
"label": "light_edit"
}
]
}
]
}
}
@@ -0,0 +1,81 @@
{
"step_num": 7,
"step_name": "layout",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step06_composition_plan.json"
],
"output": [
"step07_layout.json",
"step07_selected_layout.html"
],
"note": "count-based v0 — 들여쓰기 / 정렬 미세 layout 미구현 (Step 7 ⚠ partial). Step 7-conn (사용자 lock 2026-05-08): unit_count → layout_candidates list (select_layout_candidates) artifact 기록. default 결정 자체는 무변 — candidates[0] 가 default (default_selection: true), 나머지는 alternative. Step 9 application_plan input.",
"data": {
"layout_preset": "horizontal-2",
"layout_css": {
"areas": "\"top\" \"bottom\"",
"cols": "1fr",
"rows": "211px 360px",
"heights_px": [
211,
360
],
"ratios": [
0.361,
0.615
],
"computation": "min_height_first + content_weight_distribution",
"dynamic_rows": true,
"raw_zone_layout": {
"computation": "min_height_first + content_weight_distribution",
"slide_body_height": 585,
"gap": 14,
"available_after_gap": 571,
"min_heights_px": [
200,
345
],
"min_scaled": false,
"total_min_height": 545,
"remaining_after_min": 26,
"content_weights": [
{
"position": "top",
"template_id": "pre_construction_model_info_stacked",
"score": 6.168
},
{
"position": "bottom",
"template_id": "process_product_two_way",
"score": 8.486
}
],
"weight_shares": [
0.421,
0.579
],
"extras_px": [
11,
15
],
"heights_px": [
211,
360
],
"ratios": [
0.361,
0.615
]
}
},
"zones_count": 2,
"unit_count": 2,
"layout_candidates": [
"horizontal-2",
"vertical-2"
],
"layout_override_applied": false,
"auto_layout_preset": "horizontal-2"
}
}
@@ -0,0 +1,104 @@
{
"step_num": 8,
"step_name": "zone_region_ratios",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step07_layout.json",
"step10_frame_contract.json"
],
"output": [
"step08_zone_region_ratios.json",
"step08_zone_content_placement.html"
],
"note": "계획값 only. 실측값은 Step 14 (visual_check). zone-level 만 dynamic, region-level (sub_zone 안 sections) 은 균등 분배 (1/1/1). F29 처럼 비균등 콘텐츠 (transform_table + plain) 는 첫 cell 부족 가능 — Step 8 ⚠ partial. Step 8-conn (사용자 lock 2026-05-08): per_zone_plan[i] 에 region_layout_candidates + display_strategy_candidates 추가 (passive 기록). placeholder signals = text-only / region_count=1 (Step 3/4 부재 종속). 실제 content_object 신호 활성화는 별 axis. Step 9 application_plan input.",
"data": {
"zone_heights_px_planned": [
211,
360
],
"zone_ratios_planned": [
0.361,
0.615
],
"per_zone_plan": [
{
"position": "top",
"zone_height_px_planned": 211,
"zone_ratio_planned": 0.361,
"min_height_px": 200,
"frame_cardinality_strict": null,
"sub_zones_planned": [
{
"id": "pill_dynamic",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": null,
"partial_target_path": ".f9b__pill-rows .f9b__pill:nth-child(N)"
}
],
"child_distribution_note": "현재 child zone (sub_zones 안 sections) 균등 분배 — Step 8 region-level ratio ⚠ partial.",
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
]
},
{
"position": "bottom",
"zone_height_px_planned": 360,
"zone_ratio_planned": 0.615,
"min_height_px": 345,
"frame_cardinality_strict": 2,
"sub_zones_planned": [
{
"id": "process_column",
"role": "main_text",
"accepts": [
"text_block",
"transform_table"
],
"cardinality_strict": null,
"partial_target_path": ".f29b__grid .f29b__cell--left"
},
{
"id": "product_column",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": null,
"partial_target_path": ".f29b__grid .f29b__cell--right"
}
],
"child_distribution_note": "현재 child zone (sub_zones 안 sections) 균등 분배 — Step 8 region-level ratio ⚠ partial.",
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
]
}
],
"step8_conn_placeholder_signals": {
"region_count": 1,
"content_type": "text_block",
"flow_type": null,
"role_pattern": null,
"ratio_asymmetric": false,
"has_visual_element": false,
"details_presence": false,
"large_table": false,
"long_text": false,
"fits_in_region": null,
"_note": "Step 3/4 부재 종속 placeholder — 모든 zone 을 text-only / region_count=1 로 가정. 실제 content_object 신호 활성화는 별 axis."
}
}
}
@@ -0,0 +1,893 @@
{
"step_num": 9,
"step_name": "application_plan",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step05_v4_evidence.json",
"step06_composition_plan.json",
"step07_layout.json",
"step08_zone_region_ratios.json"
],
"output": [
"step09_application_plan.json",
"step09_application_plan.html"
],
"note": "Step 9 v0 passive application_plan trace (사용자 lock 2026-05-08). V4 후보 + layout / region / display 후보 + V4 label → application_mode 변환을 side-by-side 로 기록. v0 invariant 5 가지 (status.md §4) 만족. Step 6 의 default 결정 그대로 (current_default_candidate). auto decision 은 Step 9 v1 (별 axis). region/display 후보는 Step 8-conn 의 placeholder signal 종속 (Step 3/4 부재). Step 7-A axis (2026-05-08): frame_overrides_applied 가 사용자 LayoutPanel/FramePanel 선택값을 강제 적용한 trace.",
"data": {
"units": [
{
"unit_id": "04-1",
"layout_preset": "horizontal-2",
"layout_candidates": [
"horizontal-2",
"vertical-2"
],
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
],
"candidate_status": "no_non_reject_v4_candidate",
"application_status": "no_v4_candidate",
"current_default_candidate": null,
"selected_v4_rank": 1,
"selection_path": "rank_1",
"fallback_used": false,
"fallback_reason": null,
"candidate_evidence": [
{
"rank": 1,
"template_id": "pre_construction_model_info_stacked",
"frame_id": "1171281180",
"frame_number": 9,
"confidence": 0.7223,
"label": "reject",
"v4_label": "reject",
"phase_z_status": "fallback_candidate",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "design_reference_only",
"decision": "selected",
"reason": "primary_selected",
"capacity_fit": {
"item_count": 5,
"source_shape": "top_bullets",
"capacity": {
"strict": null,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"fallback_chain": [
{
"rank": 1,
"template_id": "pre_construction_model_info_stacked",
"frame_id": "1171281180",
"frame_number": 9,
"confidence": 0.7223,
"label": "reject",
"v4_label": "reject",
"phase_z_status": "fallback_candidate",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "design_reference_only",
"decision": "selected",
"reason": "primary_selected",
"capacity_fit": {
"item_count": 5,
"source_shape": "top_bullets",
"capacity": {
"strict": null,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"v4_candidates": [],
"v4_all_judgments": [
{
"template_id": "pre_construction_model_info_stacked",
"frame_id": "1171281180",
"frame_number": 9,
"v4_rank": 1,
"confidence": 0.7223,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "field_effectiveness_five_elements",
"frame_id": "1171281181",
"frame_number": 10,
"v4_rank": 2,
"confidence": 0.6586,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "policy_achievement_five_goals",
"frame_id": "1171281213",
"frame_number": 32,
"v4_rank": 3,
"confidence": 0.6514,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "compensation_complaint_side_card",
"frame_id": "1171281176",
"frame_number": 5,
"v4_rank": 4,
"confidence": 0.6058,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "solution_engn_split_diagram",
"frame_id": "1171281201",
"frame_number": 21,
"v4_rank": 5,
"confidence": 0.4773,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "model_specialized_engn_sw",
"frame_id": "1171281202",
"frame_number": 22,
"v4_rank": 6,
"confidence": 0.4624,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "commercial_sw_four_categories",
"frame_id": "1171281205",
"frame_number": 25,
"v4_rank": 7,
"confidence": 0.4293,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "construction_bim_three_usage",
"frame_id": "1171281182",
"frame_number": 11,
"v4_rank": 8,
"confidence": 0.4234,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "sw_dependency_four_problems",
"frame_id": "1171281206",
"frame_number": 26,
"v4_rank": 9,
"confidence": 0.3986,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "engn_sw_development_domain_knowledge",
"frame_id": "1171281173",
"frame_number": 2,
"v4_rank": 10,
"confidence": 0.3942,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "sw_development_cycle_six_nodes",
"frame_id": "1171281172",
"frame_number": 1,
"v4_rank": 11,
"confidence": 0.3899,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "policy_goals_plus_execution_requirements",
"frame_id": "1171281192",
"frame_number": 15,
"v4_rank": 12,
"confidence": 0.3833,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "bim_current_problems_paired",
"frame_id": "1171281194",
"frame_number": 17,
"v4_rank": 13,
"confidence": 0.3773,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "overseas_bim_numbered_list",
"frame_id": "1171281174",
"frame_number": 3,
"v4_rank": 14,
"confidence": 0.3748,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"frame_number": 13,
"v4_rank": 15,
"confidence": 0.3713,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "bim_issues_quadrant_four",
"frame_id": "1171281193",
"frame_number": 16,
"v4_rank": 16,
"confidence": 0.3699,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"frame_number": 20,
"v4_rank": 17,
"confidence": 0.3158,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "domestic_bim_actor_relations",
"frame_id": "1171281175",
"frame_number": 4,
"v4_rank": 18,
"confidence": 0.2897,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "bigroom_system_components",
"frame_id": "1171281178",
"frame_number": 7,
"v4_rank": 19,
"confidence": 0.2742,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "info_management_what_how_when",
"frame_id": "1171281179",
"frame_number": 8,
"v4_rank": 20,
"confidence": 0.2604,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"v4_rank": 21,
"confidence": 0.2313,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "compensation_complaint_map",
"frame_id": "1171281177",
"frame_number": 6,
"v4_rank": 22,
"confidence": 0.201,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "sw_reality_three_emphasis",
"frame_id": "1171281209",
"frame_number": 28,
"v4_rank": 23,
"confidence": 0.201,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "bim_dx_comparison_table",
"frame_id": "1171281195",
"frame_number": 18,
"v4_rank": 24,
"confidence": 0.1798,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "three_persona_benefits",
"frame_id": "1171281191",
"frame_number": 14,
"v4_rank": 25,
"confidence": 0.1787,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "construction_goals_three_circle_intersection",
"frame_id": "1171281189",
"frame_number": 12,
"v4_rank": 26,
"confidence": 0.1706,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"frame_number": 27,
"v4_rank": 27,
"confidence": 0.1399,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "engn_sw_three_types",
"frame_id": "1171281204",
"frame_number": 24,
"v4_rank": 28,
"confidence": 0.0929,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "design_method_distortion_three_col",
"frame_id": "1171281197",
"frame_number": 19,
"v4_rank": 29,
"confidence": 0.0584,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "app_sw_package_vs_solution",
"frame_id": "1171281203",
"frame_number": 23,
"v4_rank": 30,
"confidence": 0.0052,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "industry_current_status_three_col",
"frame_id": "1171281211",
"frame_number": 30,
"v4_rank": 31,
"confidence": 0.0044,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "industry_characteristics_three_col",
"frame_id": "1171281212",
"frame_number": 31,
"v4_rank": 32,
"confidence": 0.0029,
"label": "reject",
"catalog_registered": false
}
],
"application_candidates": [],
"position": null,
"assignment_source": null,
"section_assignment_override": false,
"replaced_auto_unit": null,
"skipped_collided_auto_units": [],
"skipped_reason": null
},
{
"unit_id": "04-2",
"layout_preset": "horizontal-2",
"layout_candidates": [
"horizontal-2",
"vertical-2"
],
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
],
"candidate_status": "ok",
"application_status": "ok",
"current_default_candidate": "process_product_two_way",
"selected_v4_rank": 2,
"selection_path": "rank_2_fallback",
"fallback_used": true,
"fallback_reason": "capacity_mismatch:strict_mismatch",
"candidate_evidence": [
{
"rank": 1,
"template_id": "bim_dx_comparison_table",
"frame_id": "1171281195",
"frame_number": 18,
"confidence": 0.8152,
"label": "reject",
"v4_label": "reject",
"phase_z_status": "fallback_candidate",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "design_reference_only",
"decision": "skipped",
"reason": "capacity_mismatch:strict_mismatch",
"capacity_fit": {
"item_count": 8,
"source_shape": "top_bullets",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "strict_mismatch",
"mismatch_reason": "strict cardinality 2, content has 8 items. mapper 가 FitError 를 raise 할 것."
}
},
{
"rank": 2,
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.7711,
"label": "light_edit",
"v4_label": "light_edit",
"phase_z_status": "adapt_matched_zone",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "deterministic_minor_adjustment",
"decision": "selected",
"reason": "fallback_selected",
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"fallback_chain": [
{
"rank": 1,
"template_id": "bim_dx_comparison_table",
"frame_id": "1171281195",
"frame_number": 18,
"confidence": 0.8152,
"label": "reject",
"v4_label": "reject",
"phase_z_status": "fallback_candidate",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "design_reference_only",
"decision": "skipped",
"reason": "capacity_mismatch:strict_mismatch",
"capacity_fit": {
"item_count": 8,
"source_shape": "top_bullets",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "strict_mismatch",
"mismatch_reason": "strict cardinality 2, content has 8 items. mapper 가 FitError 를 raise 할 것."
}
},
{
"rank": 2,
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.7711,
"label": "light_edit",
"v4_label": "light_edit",
"phase_z_status": "adapt_matched_zone",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "deterministic_minor_adjustment",
"decision": "selected",
"reason": "fallback_selected",
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"v4_rank": 2,
"confidence": 0.7711,
"label": "light_edit"
}
],
"v4_all_judgments": [
{
"template_id": "bim_dx_comparison_table",
"frame_id": "1171281195",
"frame_number": 18,
"v4_rank": 1,
"confidence": 0.8152,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"v4_rank": 2,
"confidence": 0.7711,
"label": "light_edit",
"catalog_registered": true
},
{
"template_id": "app_sw_package_vs_solution",
"frame_id": "1171281203",
"frame_number": 23,
"v4_rank": 3,
"confidence": 0.6389,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "engn_sw_three_types",
"frame_id": "1171281204",
"frame_number": 24,
"v4_rank": 4,
"confidence": 0.6372,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "industry_characteristics_three_col",
"frame_id": "1171281212",
"frame_number": 31,
"v4_rank": 5,
"confidence": 0.5996,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"frame_number": 27,
"v4_rank": 6,
"confidence": 0.55,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "bigroom_system_components",
"frame_id": "1171281178",
"frame_number": 7,
"v4_rank": 7,
"confidence": 0.5172,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "industry_current_status_three_col",
"frame_id": "1171281211",
"frame_number": 30,
"v4_rank": 8,
"confidence": 0.4774,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "design_method_distortion_three_col",
"frame_id": "1171281197",
"frame_number": 19,
"v4_rank": 9,
"confidence": 0.4179,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "sw_dependency_four_problems",
"frame_id": "1171281206",
"frame_number": 26,
"v4_rank": 10,
"confidence": 0.4138,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "bim_current_problems_paired",
"frame_id": "1171281194",
"frame_number": 17,
"v4_rank": 11,
"confidence": 0.3559,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "domestic_bim_actor_relations",
"frame_id": "1171281175",
"frame_number": 4,
"v4_rank": 12,
"confidence": 0.3457,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "pre_construction_model_info_stacked",
"frame_id": "1171281180",
"frame_number": 9,
"v4_rank": 13,
"confidence": 0.332,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "model_specialized_engn_sw",
"frame_id": "1171281202",
"frame_number": 22,
"v4_rank": 14,
"confidence": 0.3275,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "commercial_sw_four_categories",
"frame_id": "1171281205",
"frame_number": 25,
"v4_rank": 15,
"confidence": 0.3074,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "policy_goals_plus_execution_requirements",
"frame_id": "1171281192",
"frame_number": 15,
"v4_rank": 16,
"confidence": 0.2847,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "construction_goals_three_circle_intersection",
"frame_id": "1171281189",
"frame_number": 12,
"v4_rank": 17,
"confidence": 0.2558,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "bim_issues_quadrant_four",
"frame_id": "1171281193",
"frame_number": 16,
"v4_rank": 18,
"confidence": 0.2302,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "compensation_complaint_map",
"frame_id": "1171281177",
"frame_number": 6,
"v4_rank": 19,
"confidence": 0.2077,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"frame_number": 20,
"v4_rank": 20,
"confidence": 0.1842,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"frame_number": 13,
"v4_rank": 21,
"confidence": 0.1399,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "sw_reality_three_emphasis",
"frame_id": "1171281209",
"frame_number": 28,
"v4_rank": 22,
"confidence": 0.1271,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "solution_engn_split_diagram",
"frame_id": "1171281201",
"frame_number": 21,
"v4_rank": 23,
"confidence": 0.1171,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "overseas_bim_numbered_list",
"frame_id": "1171281174",
"frame_number": 3,
"v4_rank": 24,
"confidence": 0.1007,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "policy_achievement_five_goals",
"frame_id": "1171281213",
"frame_number": 32,
"v4_rank": 25,
"confidence": 0.0751,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "three_persona_benefits",
"frame_id": "1171281191",
"frame_number": 14,
"v4_rank": 26,
"confidence": 0.0722,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "engn_sw_development_domain_knowledge",
"frame_id": "1171281173",
"frame_number": 2,
"v4_rank": 27,
"confidence": 0.0635,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "sw_development_cycle_six_nodes",
"frame_id": "1171281172",
"frame_number": 1,
"v4_rank": 28,
"confidence": 0.0633,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "field_effectiveness_five_elements",
"frame_id": "1171281181",
"frame_number": 10,
"v4_rank": 29,
"confidence": 0.0618,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "info_management_what_how_when",
"frame_id": "1171281179",
"frame_number": 8,
"v4_rank": 30,
"confidence": 0.0487,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "compensation_complaint_side_card",
"frame_id": "1171281176",
"frame_number": 5,
"v4_rank": 31,
"confidence": 0.0457,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "construction_bim_three_usage",
"frame_id": "1171281182",
"frame_number": 11,
"v4_rank": 32,
"confidence": 0.0,
"label": "reject",
"catalog_registered": true
}
],
"application_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"v4_label": "light_edit",
"application_mode": "same_frame_with_adjustment",
"auto_applicable": true,
"required_changes": [],
"delegated_to": "step10_contract_check"
}
],
"position": null,
"assignment_source": null,
"section_assignment_override": false,
"replaced_auto_unit": null,
"skipped_collided_auto_units": [],
"skipped_reason": null
}
],
"candidate_status_summary": {
"units_with_no_v4_candidate": [
"04-1"
],
"units_with_fallback": [
"04-2"
]
},
"fallback_policy": {
"fallback_used_count": 1,
"fallback_selection_count": 1,
"chain_exhausted_count": 0,
"selection_paths": [
{
"section_id": "04-1",
"selection_path": "rank_1",
"selected_rank": 1,
"selected_template_id": "pre_construction_model_info_stacked",
"fallback_trigger": null
},
{
"section_id": "04-2",
"selection_path": "rank_2_fallback",
"selected_rank": 2,
"selected_template_id": "process_product_two_way",
"fallback_trigger": "capacity_mismatch:strict_mismatch"
}
],
"policy": "IMP-05: rank-1 is kept when usable; rank-2/3 may be promoted only when the earlier rank is not auto-renderable, has no catalog contract, or fails capacity precheck. calculate_fit is not used."
},
"frame_overrides_applied": [],
"frame_overrides_skipped": [],
"section_assignment_plan": null,
"section_assignment_summary": null,
"v0_lock_note": "Step 9 v0 passive (사용자 lock 2026-05-08). Step 6 default 그대로 사용 — runtime 결과 byte-동일. auto decision / scoring 은 Step 9 v1 (별 axis)."
}
}
@@ -0,0 +1,72 @@
{
"step_num": 20,
"step_name": "slide_status",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step14_visual_check.json",
"step17_retry_trace.json",
"step19_next_action.json"
],
"output": [
"step20_slide_status.json",
"step20_final_status.html"
],
"note": "자동 파이프라인 최종 결과 보고. overall = PASS/RENDERED_WITH_VISUAL_REGRESSION/PARTIAL_COVERAGE 등.",
"data": {
"rendered": true,
"visual_check_passed": false,
"full_mdx_coverage": true,
"aligned_section_ids": [
"04-1",
"04-2"
],
"covered_section_ids": [
"04-1",
"04-2"
],
"filtered_section_ids": [],
"filtered_section_reasons": [],
"selection_path": "fallback_used",
"fallback_used": true,
"fallback_selections": [
{
"position": "bottom",
"source_section_ids": [
"04-2"
],
"template_id": "process_product_two_way",
"selected_v4_rank": 2,
"selection_path": "rank_2_fallback",
"fallback_reason": "capacity_mismatch:strict_mismatch"
}
],
"fallback_selection_count": 1,
"selection_paths": [
{
"section_id": "04-1",
"selection_path": "rank_1",
"selected_rank": 1,
"selected_template_id": "pre_construction_model_info_stacked",
"fallback_trigger": null
},
{
"section_id": "04-2",
"selection_path": "rank_2_fallback",
"selected_rank": 2,
"selected_template_id": "process_product_two_way",
"fallback_trigger": "capacity_mismatch:strict_mismatch"
}
],
"visual_fail_reasons": [
"zone--bottom: inner clipped .f29b — excess 17px vert / 0px horiz (content 377 vs container 360)",
"zone--bottom: inner clipped .f29b__body — excess 17px vert / 0px horiz (content 311 vs container 294)"
],
"adapter_needed_count": 0,
"adapter_needed_units": [],
"content_truncated_count": 0,
"content_truncated_units": [],
"overall": "RENDERED_WITH_VISUAL_REGRESSION",
"note": "자동 파이프라인 결과 보고. review/UI 개념 X. final.html 파일명 != PASS 의미. overall == PASS 는 visual OK + full coverage + adapter_needed=0 일 때만. adapter_needed_count > 0 = mapper 가 contract 와 안 맞아 자동 렌더 못 한 zone 존재. content_truncated_count > 0 = builder 가 truncate 한 zone 존재 (rendered 됐지만 일부 콘텐츠 손실)."
}
}
@@ -0,0 +1,569 @@
{
"v4_source": "tests\\matching\\v4_full32_result.yaml",
"v4_label_to_phase_z_status": {
"use_as_is": "matched_zone",
"light_edit": "adapt_matched_zone",
"restructure": "extract_matched_zone",
"reject": "fallback_candidate"
},
"mvp1_allowed_statuses": [
"adapt_matched_zone",
"matched_zone"
],
"mode": "composition_v0_layout_8preset",
"mode_note": "MVP-1.5b w/ composition planner v0 — sections → candidates (separate / parent_merged) → score → greedy select → 8-preset layout vocabulary (single / horizontal-2 / vertical-2 / top-1-bottom-2 / top-2-bottom-1 / left-1-right-2 / left-2-right-1 / grid-2x2). v0 layout = count-based; v1 axes (cardinality_fit / hierarchy_coherence / density_score) 추후.",
"layout_preset": "horizontal-2",
"layout_css": {
"areas": "\"top\" \"bottom\"",
"cols": "1fr",
"rows": "228px 343px",
"heights_px": [
228,
343
],
"ratios": [
0.39,
0.586
],
"computation": "min_height_first + content_weight_distribution",
"dynamic_rows": true,
"raw_zone_layout": {
"computation": "min_height_first + content_weight_distribution",
"slide_body_height": 585,
"gap": 14,
"available_after_gap": 571,
"min_heights_px": [
228,
342
],
"min_scaled": true,
"total_min_height": 570,
"remaining_after_min": 1,
"content_weights": [
{
"position": "top",
"template_id": "three_parallel_requirements",
"score": 4.425
},
{
"position": "bottom",
"template_id": "process_product_two_way",
"score": 7.305
}
],
"weight_shares": [
0.377,
0.623
],
"extras_px": [
0,
1
],
"heights_px": [
228,
343
],
"ratios": [
0.39,
0.586
]
}
},
"slide_status": {
"rendered": true,
"visual_check_passed": true,
"full_mdx_coverage": true,
"aligned_section_ids": [
"03-1",
"03-2"
],
"covered_section_ids": [
"03-1",
"03-2"
],
"filtered_section_ids": [],
"filtered_section_reasons": [],
"visual_fail_reasons": [],
"adapter_needed_count": 0,
"adapter_needed_units": [],
"content_truncated_count": 0,
"content_truncated_units": [],
"overall": "PASS",
"note": "자동 파이프라인 결과 보고. review/UI 개념 X. final.html 파일명 != PASS 의미. overall == PASS 는 visual OK + full coverage + adapter_needed=0 일 때만. adapter_needed_count > 0 = mapper 가 contract 와 안 맞아 자동 렌더 못 한 zone 존재. content_truncated_count > 0 = builder 가 truncate 한 zone 존재 (rendered 됐지만 일부 콘텐츠 손실)."
},
"fit_classification": {
"visual_check_passed": true,
"classifications": [],
"summary": "visual check passed — no overflow to classify",
"categories_seen": [],
"unclassified_signals": [],
"placement_diagnostics": [
{
"zone_position": "top",
"mapper_frame_template_id": "three_parallel_requirements",
"b4_selected_template_id": "three_parallel_requirements",
"frame_selection_matches_mapper": true,
"frame_selection_match_note": null,
"region_count": 1,
"slot_assignment_count": 1,
"rejection_count": 0
},
{
"zone_position": "bottom",
"mapper_frame_template_id": "process_product_two_way",
"b4_selected_template_id": "process_product_two_way",
"frame_selection_matches_mapper": true,
"frame_selection_match_note": null,
"region_count": 2,
"slot_assignment_count": 2,
"rejection_count": 0
}
]
},
"router_decision": {
"router_active": false,
"proposed_actions_summary": [],
"implementation_status_summary": {},
"routed_count": 0,
"routed_details": [],
"missing_actions_pending_impl": [],
"note": "visual check passed — no overflow to route"
},
"retry_trace": {
"retry_attempted": false,
"retry_action": null,
"plan": null,
"rerender_attempted": false,
"retry_passed": false,
"retry_failure_reason": null,
"retried_candidate_path": null,
"safety_margin_px": 4,
"policy": "A3 locked rules : retry budget=1, slide-base/spacing/gap fixed, donor strict (sibling/visual ok/capacity ok/slack>0/min_height 보존), (b) revert on redistribution fail or rerender visual fail.",
"retry_skipped_reason": "router_active=False (visual check passed — no overflow)",
"failure_classification": {
"failure_type": "not_attempted",
"failure_type_description": "retry was not attempted (router_active=False or zone_ratio_retry not in proposed actions). 정상 path 의 일부 — 실패 X",
"classification_rule": "retry_attempted=False — router_active=False or zone_ratio_retry not in proposed_actions"
},
"next_action_proposal": {
"next_proposed_action": "none",
"next_action_rationale": "retry 시도 자체가 없었음 (visual ok 등) — escalation 불필요",
"next_action_implementation_status": "n/a",
"mapping_source": "A4 NEXT_ACTION_BY_FAILURE (사용자 잠금 2026-04-29)"
}
},
"composition_planner_debug": {
"planner_version": "v0.2",
"selection_rule": "score desc, then source_section_ids count desc (coverage tiebreak). filter = phase_z_status ∉ allowed_statuses OR auto_selectable=False. auto_selectable=False 사유 : C1 (capacity mismatch — silent truncate / FitError 차단), W1 (rep not auto-renderable), W2 (all children reject), W3 (majority children non-auto-renderable).",
"candidates_total": 2,
"candidates_viable_auto": 2,
"candidates_summary": [
{
"source_section_ids": [
"03-1"
],
"merge_type": "single",
"template_id": "three_parallel_requirements",
"label": "use_as_is",
"phase_z_status": "matched_zone",
"score": 0.9268,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 3,
"source_shape": "top_bullets",
"capacity": {
"strict": 3,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
},
{
"source_section_ids": [
"03-2"
],
"merge_type": "single",
"template_id": "process_product_two_way",
"label": "use_as_is",
"phase_z_status": "matched_zone",
"score": 0.9198,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"merge_candidates": [],
"capacity_mismatches": [],
"selected_units_count": 2,
"layout_preset": "horizontal-2",
"layout_preset_rationale": "v0 count-based: 2 units → horizontal-2"
},
"zones": [
{
"position": "top",
"source_section_ids": [
"03-1"
],
"merge_type": "single",
"title": "1. DX 시행을 위한 필수 요건",
"v4_rank1_frame_id": "1171281190",
"v4_rank1_frame_number": 13,
"v4_template_id": "three_parallel_requirements",
"v4_label": "use_as_is",
"v4_confidence": 0.9268,
"phase_z_status": "matched_zone",
"composition_score": 0.9268,
"composition_rationale": {
"capacity_fit": {
"item_count": 3,
"source_shape": "top_bullets",
"capacity": {
"strict": 3,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.9268,
"confidence": 0.9268,
"label": "use_as_is",
"label_weight": 1.0,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"composition_notes": [],
"mapper_type": "contract",
"contract_id": "three_parallel_requirements",
"contract_frame_id": 1171281190,
"builder": "items_with_role",
"min_height_px": 230,
"slot_payload_keys": [
"pillars",
"title"
],
"content_truncated_count": null,
"assets_dir": null,
"content_weight": {
"score": 4.425,
"text_length": 660,
"top_bullets": 3,
"nested_bullets": 16,
"has_table": false,
"subsection_count": 0
},
"placement_trace": {
"section_id": "03-1",
"selected_frame_id": "1171281190",
"selected_template_id": "three_parallel_requirements",
"internal_regions": [
{
"region_id": "03-1.region-1",
"role": "primary",
"content_type": "text_block",
"ratio_estimate": 1.0,
"content_unit_ids": [
"03-1.text-1"
],
"frame_match_strategy": {
"kind": "frame_match",
"frame_id": null,
"display_strategy": "inline_full"
},
"source_shape_index": null
}
],
"slot_assignments": [
{
"region_id": "03-1.region-1",
"content_unit_id": "03-1.text-1",
"frame_slot_id": "pillar_1",
"partial_target_path": ".f13b__cols > .f13b__col:nth-child(1)",
"display_strategy": "inline_full"
}
],
"overflow_buffer": [],
"rejection": [],
"mapper_frame_template_id": "three_parallel_requirements",
"frame_selection_matches_mapper": true,
"frame_selection_match_note": null
},
"height_px": 228,
"ratio": 0.39
},
{
"position": "bottom",
"source_section_ids": [
"03-2"
],
"merge_type": "single",
"title": "2. Process의 혁신과 Product의 변화",
"v4_rank1_frame_id": "1171281210",
"v4_rank1_frame_number": 29,
"v4_template_id": "process_product_two_way",
"v4_label": "use_as_is",
"v4_confidence": 0.9198,
"phase_z_status": "matched_zone",
"composition_score": 0.9198,
"composition_rationale": {
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.9198,
"confidence": 0.9198,
"label": "use_as_is",
"label_weight": 1.0,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"composition_notes": [],
"mapper_type": "contract",
"contract_id": "process_product_two_way",
"contract_frame_id": 1171281210,
"builder": "process_product_pair",
"min_height_px": 345,
"slot_payload_keys": [
"banner_left",
"banner_right",
"process",
"product",
"title"
],
"content_truncated_count": null,
"assets_dir": "assets\\process_product_two_way",
"content_weight": {
"score": 7.305,
"text_length": 924,
"top_bullets": 6,
"nested_bullets": 7,
"has_table": true,
"subsection_count": 2
},
"placement_trace": {
"section_id": "03-2",
"selected_frame_id": "1171281210",
"selected_template_id": "process_product_two_way",
"internal_regions": [
{
"region_id": "03-2.region-1",
"role": "primary",
"content_type": "text_block",
"ratio_estimate": 0.8421,
"content_unit_ids": [
"03-2.text-1"
],
"frame_match_strategy": {
"kind": "frame_match",
"frame_id": null,
"display_strategy": "inline_full"
},
"source_shape_index": null
},
{
"region_id": "03-2.region-2",
"role": "supporting",
"content_type": "transform_table",
"ratio_estimate": 0.1579,
"content_unit_ids": [
"03-2.transform-1"
],
"frame_match_strategy": {
"kind": "frame_match",
"frame_id": null,
"display_strategy": "inline_full"
},
"source_shape_index": null
}
],
"slot_assignments": [
{
"region_id": "03-2.region-1",
"content_unit_id": "03-2.text-1",
"frame_slot_id": "product_column",
"partial_target_path": ".f29b__grid .f29b__cell--right",
"display_strategy": "inline_full"
},
{
"region_id": "03-2.region-2",
"content_unit_id": "03-2.transform-1",
"frame_slot_id": "process_column",
"partial_target_path": ".f29b__grid .f29b__cell--left",
"display_strategy": "inline_full"
}
],
"overflow_buffer": [],
"rejection": [],
"mapper_frame_template_id": "process_product_two_way",
"frame_selection_matches_mapper": true,
"frame_selection_match_note": null
},
"height_px": 343,
"ratio": 0.586
}
],
"visual_runtime_check": {
"frame_slot_metrics": [
{
"class_name": "f29b__cell f29b__cell--left",
"clientHeight": 125,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "process_column",
"overflowed": false,
"scrollHeight": 125,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
},
{
"class_name": "f29b__cell f29b__cell--right",
"clientHeight": 125,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "product_column",
"overflowed": false,
"scrollHeight": 125,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
},
{
"class_name": "f29b__cell f29b__cell--left",
"clientHeight": 43,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "process_column",
"overflowed": false,
"scrollHeight": 43,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
},
{
"class_name": "f29b__cell f29b__cell--right",
"clientHeight": 43,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "product_column",
"overflowed": false,
"scrollHeight": 43,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
},
{
"class_name": "f29b__cell f29b__cell--left",
"clientHeight": 63,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "process_column",
"overflowed": false,
"scrollHeight": 63,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
},
{
"class_name": "f29b__cell f29b__cell--right",
"clientHeight": 63,
"clientWidth": 577,
"excess_x": 0,
"excess_y": 0,
"frame_slot_id": "product_column",
"overflowed": false,
"scrollHeight": 63,
"scrollWidth": 577,
"zone_position": "bottom",
"zone_template_id": "process_product_two_way"
}
],
"slide": {
"clientHeight": 720,
"clientWidth": 1280,
"excess_x": 0,
"excess_y": 0,
"overflowed": false,
"scrollHeight": 720,
"scrollWidth": 1280,
"size_correct": true
},
"slide_body": {
"clientHeight": 585,
"clientWidth": 1180,
"excess_x": 0,
"excess_y": 0,
"overflowed": false,
"scrollHeight": 585,
"scrollWidth": 1180
},
"zones": [
{
"clientHeight": 228,
"clientWidth": 1180,
"clipped_inner": [],
"excess_x": 0,
"excess_y": 0,
"overflowed": false,
"position": "top",
"scrollHeight": 228,
"scrollWidth": 1180,
"template_id": "three_parallel_requirements"
},
{
"clientHeight": 343,
"clientWidth": 1180,
"clipped_inner": [],
"excess_x": 0,
"excess_y": 0,
"overflowed": false,
"position": "bottom",
"scrollHeight": 343,
"scrollWidth": 1180,
"template_id": "process_product_two_way"
}
],
"screenshot": "data\\runs\\mdx03_f29_fix_check\\phase_z2\\preview.png",
"passed": true,
"fail_reasons": []
}
}
@@ -0,0 +1,927 @@
<!-- Phase Z-2 MVP-1.5b — single slide + Type B layout (top/bottom zones).
원래 Phase Z 설계 복귀: MDX 1 = slide 1, layout preset = zone 분할, frame-derived block ⊂ zone. -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280">
<title>DX 실행 체계 구축 방안</title>
<style>
/* ── existing tokens (inlined) ── */
/* === typography.css === */
/* ══════════════════════════════════════
Typography Tokens v1
══════════════════════════════════════
슬라이드 전체의 공통 글자 위계.
모든 블록은 이 토큰을 참조한다.
직접값(font-size: 11px) 금지 → var(--font-body) 사용.
══════════════════════════════════════ */
:root {
/* ── 1층: Global Hierarchy ── */
/* 대목차: 슬라이드 상단 제목 */
--font-slide-title: 22px;
--weight-slide-title: 700;
--lh-slide-title: 1.4;
/* 중목차: zone 제목 */
--font-zone-title: 16px;
--weight-zone-title: 700;
--lh-zone-title: 1.4;
/* 소목차: 블록 내 소제목, 카드 제목 */
--font-sub-title: 12px;
--weight-sub-title: 700;
--lh-sub-title: 1.45;
/* 본문: 블릿, 설명 텍스트 */
--font-body: 10px;
--weight-body: 500;
--lh-body: 1.55;
/* 캡션: 각주, 출처, 보조 텍스트 */
--font-caption: 10px;
--weight-caption: 400;
--lh-caption: 1.4;
/* footer: 핵심 인사이트 pill */
--font-footer: 20px;
--weight-footer: 700;
--lh-footer: 1.2;
/* ── 2층: Component Semantic Tokens ── */
/* 가까운 위계에서 기본값, 필요시 override */
/* 본문 강조 (인라인 heading) */
--font-body-strong: var(--font-body);
--weight-body-strong: 600;
/* 자세히보기 링크 */
--font-detail-link: var(--font-caption);
--weight-detail-link: 500;
/* pill/badge 라벨 */
--font-pill-label: var(--font-sub-title);
--weight-pill-label: 700;
/* 표 헤더 */
--font-table-header: var(--font-sub-title);
--weight-table-header: 700;
/* 표 셀 */
--font-table-cell: var(--font-body);
--weight-table-cell: 400;
/* 비교 뱃지 */
--font-compare-badge: var(--font-sub-title);
--weight-compare-badge: 700;
/* 강조 인용 */
--font-callout: var(--font-sub-title);
--weight-callout: 700;
/* 상단 라벨 (overline) */
--font-overline: var(--font-caption);
--weight-overline: 600;
--ls-overline: 0.05em;
}
/* === spacing.css === */
/* ══════════════════════════════════════
Spacing Tokens v1
══════════════════════════════════════
여백/간격/들여쓰기 공통 기준.
══════════════════════════════════════ */
:root {
/* ── 기본 스케일 ── */
--space-xs: 4px;
--space-sm: 8px;
--space-md: 12px;
--space-lg: 16px;
--space-xl: 24px;
/* ── slide-base 레이아웃 ── */
--slide-padding-x: 40px; /* 본문 좌우 여백 */
--slide-title-left: 52px; /* 대목차 시작 */
--slide-title-top: 22px; /* 대목차 위치 */
--slide-divider-top: 58px; /* 구분선 위치 (slide_base.html 와 일치 2026-05-07) */
--slide-body-top: 76px; /* 본문 시작 (사용자 직설: divider-body 16px) */
--slide-body-height: 585px; /* 본문 높이 (사용자 직설: body-footer 10px) */
--slide-footer-bottom: 8px; /* footer 하단 여백 (slide_base.html 와 일치) */
--slide-footer-height: 41px; /* footer 높이 */
/* ── zone ── */
--zone-gap: 8px; /* zone 간 간격 */
--zone-padding-left: 12px; /* zone 안쪽 좌측 여백 */
--zone-padding-right: 8px; /* zone 안쪽 우측 여백 */
--zone-title-mb: 8px; /* zone 제목 아래 여백 */
/* ── 블록 공통 ── */
--card-padding: 16px; /* 카드 내부 여백 */
--card-padding-sm: 8px; /* 작은 카드 내부 여백 */
--card-gap: 12px; /* 카드 간 간격 */
--card-radius: 6px; /* 카드 모서리 */
/* ── 블릿/텍스트 ── */
--bullet-indent: 14px; /* 불릿 hanging indent */
--bullet-gap: 2px; /* 불릿 항목 간 간격 */
--heading-gap: 4px; /* 소제목 아래 간격 */
--section-gap: 10px; /* 섹션 간 간격 */
/* ── flex/grid 기본 ── */
--flex-gap: 12px; /* 기본 flex gap */
--flex-gap-sm: 6px; /* 좁은 flex gap */
--grid-gap: 16px; /* 기본 grid gap */
}
/* === colors.css === */
/* ══════════════════════════════════════
Color Tokens v1
══════════════════════════════════════
2층 구조: 공통 테마색 + 블록 의미색.
══════════════════════════════════════ */
:root {
/* ══ 1층: 공통 테마색 ══ */
/* 모든 블록이 공유하는 기본 팔레트 */
/* 텍스트 */
--color-title: #1e293b; /* 제목 (진한 남색) */
--color-zone-title: #1a365d; /* zone 중목차 제목 */
--color-body: #475569; /* 본문 */
--color-body-strong: #1e293b; /* 본문 강조 */
--color-caption: #94a3b8; /* 캡션, 보조 */
--color-muted: #64748b; /* 약한 텍스트 */
/* 배경 */
--color-bg: #ffffff; /* 슬라이드 배경 */
--color-bg-subtle: #f8fafc; /* 카드/영역 배경 */
--color-bg-page: #e8ecf0; /* 페이지 배경 (슬라이드 바깥) */
/* 보더 */
--color-border: #e2e8f0; /* 기본 보더 */
--color-border-strong: #cbd5e1; /* 강한 보더 */
/* 강조 */
--color-accent: #2563eb; /* 링크, 강조 (파랑) */
--color-accent-hover: #eff6ff; /* 링크 hover 배경 */
--color-danger: #dc2626; /* 경고, 에러 */
/* slide-base 전용 */
--color-slide-title-from: #296b55; /* 대목차 gradient 시작 */
--color-slide-title-to: #123328; /* 대목차 gradient 끝 */
--color-footer-bg-from: #3b3523; /* footer gradient 시작 */
--color-footer-bg-mid: #263a2a; /* footer gradient 중간 */
--color-footer-bg-to: #113f31; /* footer gradient 끝 */
--color-footer-text: #ffffff; /* footer 텍스트 */
--color-footer-accent: #ffee33; /* footer 강조 (em) */
/* ══ 2층: 블록 의미색 ══ */
/* 특정 블록 유형에서 의미를 가지는 색 */
/* 3열 비교 (prerequisites-3col) */
--color-col-1-from: #0D78D0; /* 1열 gradient 시작 */
--color-col-1-to: #023056; /* 1열 gradient 끝 */
--color-col-2-from: #FF9A23; /* 2열 gradient 시작 */
--color-col-2-to: #CC5200; /* 2열 gradient 끝 */
--color-col-3-from: #39BE49; /* 3열 gradient 시작 */
--color-col-3-to: #23742C; /* 3열 gradient 끝 */
/* 비교 블록 (compare) */
--color-compare-left: #5c3714; /* 좌측 (AS-IS 계열) */
--color-compare-right: #285b4a; /* 우측 (TO-BE 계열) */
--color-compare-badge: #ae3607; /* VS 뱃지 */
/* 다크 카드 (direct render) */
--color-dark-card-1: #1a365d; /* 카드 1 배경 */
--color-dark-card-2: #1e3a2f; /* 카드 2 배경 */
--color-dark-card-3: #3b1f2b; /* 카드 3 배경 */
--color-dark-card-title: #fbbf24; /* 다크카드 제목 (금색) */
--color-dark-card-body: #e2e8f0; /* 다크카드 본문 */
/* 표 */
--color-table-header-bg: #64748b; /* 표 헤더 배경 */
--color-table-header-text: #ffffff; /* 표 헤더 텍스트 */
/* 블록 제목 gradient (Figma 원본) */
--color-block-title-from: #CC5200; /* 주황 gradient 시작 */
--color-block-title-to: #883700; /* 주황 gradient 끝 */
/* pill */
--color-pill-bg: #1e293b; /* pill 배경 */
--color-pill-text: #ffffff; /* pill 텍스트 */
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
background: #e8ecf0;
display: flex; justify-content: center; align-items: center;
min-height: 100vh;
word-break: keep-all;
padding: 20px 0;
}
/* ── 16:9 슬라이드 (single, 1280×720) ── */
.slide {
width: 1280px; height: 720px;
position: relative;
overflow: hidden;
background: #fff;
box-shadow: 0 4px 20px rgba(0,0,0,.15);
flex-shrink: 0;
}
.slide-bg {
position: absolute; inset: 0;
background: linear-gradient(180deg, #f0f0f0 0%, #ffffff 100%);
z-index: 0;
}
.slide-title {
position: absolute;
left: 52px; top: 22px;
width: calc(100% - 104px);
font-weight: 700;
font-size: var(--font-slide-title);
line-height: var(--lh-slide-title);
background-image: linear-gradient(180deg, #296b55 0%, #123328 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
text-shadow: 0 0 2px #322c1e;
z-index: 2;
}
.slide-divider {
position: absolute;
left: 50px; top: 58px;
width: calc(100% - 100px);
height: 2px;
background: #cbd5e1;
z-index: 2;
}
.slide-body {
position: absolute;
left: 50px; top: 76px;
width: calc(100% - 100px); /* 1180 */
height: 585px;
z-index: 1;
overflow: hidden;
}
/* ── Layout preset (composition planner v0 — 8 vocabulary) ──
단일 .layout-{preset} 클래스에 grid CSS 주입.
layout_css = pipeline build_layout_css() 결과 :
- horizontal-2 : rows = dynamic px (content_weight + frame_min_height)
- 그 외 : rows / cols = fr default (LAYOUT_PRESETS)
positions (single / top / bottom / left / right / top-left / ... / grid-2x2 9개)
은 .zone 의 inline grid-area 로 지정 — preset CSS 는 areas 만 정의. */
.layout-horizontal-2 {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 228px 343px;
grid-template-areas: "top" "bottom";
gap: 14px;
height: 100%;
}
/* ── Zone — block 가용 공간 최대화. 프레임 자체 styling 이 boundary 역할 ── */
.zone {
position: relative;
overflow: hidden;
padding: 0;
min-width: 0;
min-height: 0;
}
/* ── Frame-family text layout contract (shared, reusable) ──
feedback-1 (mvp1.5b_test7): visible improvement 강화.
Stronger hanging indent + breathing line spacing + visible hierarchy. */
.text-line {
font-size: var(--font-body); /* 11px */
font-weight: var(--weight-body);
line-height: 1.6; /* breathing room */
margin: 0;
}
.text-line + .text-line {
margin-top: 4px; /* visible gap between lines (was 2px) */
}
/* bullet line — hanging indent via padding + absolute marker (안정적) */
.text-line--bullet {
padding-left: 14px;
position: relative;
}
.text-line--bullet::before {
content: "•"; /* visible bullet 마커 */
position: absolute;
left: 2px;
top: 0;
font-weight: 700;
line-height: inherit;
color: inherit;
}
/* indent levels — visible nested hierarchy */
.text-line--indent-1 {
padding-left: 30px;
}
.text-line--indent-1::before {
content: "◦"; /* sub-bullet 다른 마커 */
left: 18px;
}
.text-line--indent-2 {
padding-left: 46px;
}
.text-line--indent-2::before {
content: "▪";
left: 34px;
}
/* body line — 마커 없음 */
.text-line--body {
padding-left: 0;
}
.text-line strong { color: #000; font-weight: 700; }
/* ── Transform-block family (frame 29 AS-IS/TO-BE dedicated comparison component) ──
feedback-3: bullet rows 가 아닌 *전용 비교 component*. Header (AS-IS / TO-BE) + paired rows.
color-coded cells, left-border accent → 단번에 *비교 구조* 인지. */
.transform-block {
margin-top: 4px;
padding: 6px 8px 6px;
background: rgba(255, 255, 255, 0.4);
border-radius: 3px;
border: 1px solid rgba(0,0,0,0.05);
}
.transform-block__header {
display: grid;
grid-template-columns: 1fr 22px 1fr;
gap: 6px;
margin-bottom: 4px;
padding-bottom: 3px;
border-bottom: 1px dashed rgba(0,0,0,0.12);
font-size: 9px;
font-weight: 900;
letter-spacing: 0.5px;
}
.transform-block__label--from { color: #6b5444; }
.transform-block__label--to { color: #2563eb; text-align: left; }
.transform-rows {
display: flex; flex-direction: column;
gap: 4px;
}
.transform-row {
display: grid;
grid-template-columns: 1fr 22px 1fr;
gap: 6px;
align-items: stretch;
font-size: var(--font-body);
line-height: 1.45;
}
.transform-row__from {
padding: 3px 8px;
background: linear-gradient(90deg, rgba(140,120,90,0.16), rgba(140,120,90,0.08));
border-left: 2px solid #b8a98a;
border-radius: 2px;
color: #4b3f30;
font-weight: 500;
}
.transform-row__arrow {
text-align: center;
color: #2563eb;
font-weight: 900;
font-size: 14px;
align-self: center;
}
.transform-row__to {
padding: 3px 8px;
background: linear-gradient(90deg, rgba(37,99,235,0.10), rgba(37,99,235,0.18));
border-left: 2px solid #2563eb;
border-radius: 2px;
color: #1e40af;
font-weight: 700;
}
/* ── Footer pill — feedback-3: body 와 weight balance, 살짝 가벼워짐 ── */
.slide-footer {
position: absolute;
left: 50px; bottom: 8px;
width: calc(100% - 100px); /* front 기준 (body 와 정렬) */
height: 41px; /* front 기준 */
border-radius: 999px;
overflow: hidden;
z-index: 2;
display: flex; align-items: center; justify-content: center;
background: linear-gradient(90deg, #3b3523 5%, #263a2a 50%, #113f31 95%);
opacity: 0.92; /* slightly lighter */
}
.slide-footer-text {
position: relative; z-index: 1;
font-size: 15px; /* was 20px (--font-footer) */
font-weight: 700;
line-height: 1.2;
color: #fff;
text-align: center;
text-shadow: 0 0 3px rgba(0,0,0,.4);
letter-spacing: -0.01em;
}
.slide-footer-text em { color: #fe3; font-style: normal; }
.phase-z2-marker {
position: absolute;
top: 4px; right: 8px;
font-size: 9px; color: #94a3b8;
font-family: monospace;
z-index: 3;
}
</style>
</head>
<body>
<div class="slide" data-page="1">
<div class="slide-bg"></div>
<div class="phase-z2-marker">phase_z2 / mvp-1.5b / horizontal-2 / single slide</div>
<div class="slide-title">DX 실행 체계 구축 방안</div>
<div class="slide-divider"></div>
<div class="slide-body">
<div class="layout-horizontal-2">
<div class="zone" data-zone-position="top" data-template-id="three_parallel_requirements" style="grid-area: top;">
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt.
Legacy templates/blocks/structures/prerequisites-3col.html 의 token-fixed font 접근 학습. -->
<style>
.f13b {
width: 100%; height: 100%;
display: flex; flex-direction: column;
gap: 4px;
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
word-break: keep-all;
}
.f13b__title {
font-size: var(--font-zone-title);
font-weight: 700;
line-height: var(--lh-zone-title);
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
flex-shrink: 0;
}
.f13b__cols {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 8px;
flex: 1;
min-height: 0;
}
.f13b__col {
display: flex;
border-top: 2px solid #000; /* PROMOTED line 57 */
border-bottom: 2px solid #000;
overflow: hidden;
min-width: 0;
background: rgba(255,255,255,0.5);
}
.f13b__bar {
flex: 0 0 50px;
display: flex; flex-direction: column;
align-items: center; justify-content: center;
color: #fff;
font-weight: 700;
text-align: center;
padding: 6px 2px;
gap: 3px;
}
.f13b__col--tech .f13b__bar { background: linear-gradient(180deg, #0D78D0 0%, #023056 100%); }
.f13b__col--people .f13b__bar { background: linear-gradient(180deg, #FF9A23 0%, #CC5200 100%); }
.f13b__col--nature .f13b__bar { background: linear-gradient(180deg, #39BE49 21%, #23742C 100%); }
/* PROMOTED Figma frame 13 line 92-93 — main + parenthetical stacked vertically */
.f13b__bar-main {
font-size: var(--font-sub-title); /* 12px — main word "기술/사람/자연" */
font-weight: 700;
line-height: 1.2;
display: block;
}
.f13b__bar-paren {
font-size: var(--font-caption); /* 10px — "(디지털/역량/여건)" */
font-weight: 500;
line-height: 1.2;
display: block;
opacity: 0.95;
}
.f13b__body {
flex: 1;
display: flex; flex-direction: column;
padding: 8px 12px; /* breathing (was 6px 10px) */
min-width: 0;
overflow: hidden;
}
.f13b__section {
flex: 1;
padding: 6px 0; /* breathing (was 4px) */
overflow: hidden;
min-height: 0;
}
.f13b__section + .f13b__section {
border-top: 2px dashed #000; /* PROMOTED line 103 */
margin-top: 6px; /* visible section gap (was 4px) */
padding-top: 8px; /* breathing (was 6px) */
}
/* heading — 부소목차 (사용자 5-layer 직설 2026-05-07): Digital 기술과... 같은 깊이 1 굵은 bullet */
.f13b__heading {
font-size: var(--font-sub-title); /* 12px — 부소목차 위계 */
font-weight: 700;
line-height: var(--lh-sub-title);
-webkit-background-clip: text; background-clip: text;
color: transparent;
margin-bottom: 6px; /* visible heading-body gap (was 4px) */
}
.f13b__col--tech .f13b__heading { background-image: linear-gradient(180deg, #0D78D0 0%, #134D7F 100%); }
.f13b__col--people .f13b__heading { background-image: linear-gradient(180deg, #FE900C 0%, #D18B37 100%); }
.f13b__col--nature .f13b__heading { background-image: linear-gradient(180deg, #3CA649 21%, #23742C 100%); }
/* desc — frame-family text layout contract (.text-line 공통 클래스 사용)
feedback (mvp1.5b_test5): browser-native ul/li 폐기. */
.f13b__desc {
color: #3E3523; /* PROMOTED line 118 */
overflow: hidden;
}
/* desc 안 .text-line 색 override */
.f13b__desc .text-line { color: #3E3523; }
</style>
<div class="f13b" data-frame-id="1171281190" data-template-id="three_parallel_requirements">
<div class="f13b__title">1. DX 시행을 위한 필수 요건</div>
<div class="f13b__cols">
<div class="f13b__col f13b__col--tech">
<div class="f13b__bar">
<span class="f13b__bar-main">기술</span>
<span class="f13b__bar-paren">(디지털)</span>
</div>
<div class="f13b__body">
<div class="f13b__section">
<div class="f13b__heading">Digital 기술(S/W, H/W)과 업무 Process의 통합</div>
<div class="f13b__desc">
<div class="text-line text-line--bullet">기존 업무 프로세스에 다양한 디지털 기술을 접목하여 업무 수행</div><div class="text-line text-line--bullet">프로젝트 전반에 걸친 업무 프로세스의 연결 및 조율</div>
</div>
</div>
<div class="f13b__section">
<div class="f13b__heading">분야별 전문 지식(설계, 시공, 유지관리 등) 보유</div>
<div class="f13b__desc">
<div class="text-line text-line--bullet">건설 전 단계에 대한 근본적인 이해와 지식 및 경험</div><div class="text-line text-line--bullet">최신 토목 기술 트랜드 및 표준 기준 등에 대한 높은 지식</div>
</div>
</div>
</div>
</div>
<div class="f13b__col f13b__col--people">
<div class="f13b__bar">
<span class="f13b__bar-main">사람</span>
<span class="f13b__bar-paren">(역량)</span>
</div>
<div class="f13b__body">
<div class="f13b__section">
<div class="f13b__heading">혁신적 사고방식과 창의적 문제 해결 능력</div>
<div class="f13b__desc">
<div class="text-line text-line--bullet">기존 수행 방식과 관습적 사고 등에 의한 접근 방식 탈피</div><div class="text-line text-line--bullet">디지털 기술을 활용한 창의적, 혁신적인 솔루션 제시</div>
</div>
</div>
<div class="f13b__section">
<div class="f13b__heading">사용자 중심 사고와 DX 수행 경험</div>
<div class="f13b__desc">
<div class="text-line text-line--bullet">사용자의 요구와 기대를 충족시키는 설계 및 구현</div><div class="text-line text-line--bullet">시행착오를 포함한 수행 경험과 사용자 경험(UX)을 반영한 해결 방안 제시</div>
</div>
</div>
</div>
</div>
<div class="f13b__col f13b__col--nature">
<div class="f13b__bar">
<span class="f13b__bar-main">자연</span>
<span class="f13b__bar-paren">(여건)</span>
</div>
<div class="f13b__body">
<div class="f13b__section">
<div class="f13b__heading">지속적인 투자 및 실행 의지</div>
<div class="f13b__desc">
<div class="text-line text-line--bullet">기술 도입 초기 단계에 필요한 인력·기간·비용 등의 대규모 투자</div><div class="text-line text-line--bullet">기술 고도화를 위한 지속적인 개선 및 투자 체계 구축</div><div class="text-line text-line--bullet">변화와 혁신을 통해 부가가치를 창출하려는 실행 의지와 추진력</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="zone" data-zone-position="bottom" data-template-id="process_product_two_way" style="grid-area: bottom;">
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
<style>
.f29b {
width: 100%; height: 100%;
display: flex; flex-direction: column;
gap: 4px;
position: relative;
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
word-break: keep-all;
overflow: hidden;
}
.f29b__title {
font-size: var(--font-zone-title); /* 13px — frame 13 의 f13b__title 과 동일 위계 */
font-weight: 700;
line-height: var(--lh-zone-title);
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
flex-shrink: 0;
padding-left: 4px;
}
/* banners — top */
.f29b__banners {
flex: 0 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4px;
position: relative;
height: 36px;
}
.f29b__banner {
position: relative;
overflow: hidden;
display: flex; align-items: center; justify-content: center;
}
/* PROMOTED background gradients — figma origin lines 84-98 (header-bg--left/right).
원본 SVG 3 개 → CSS gradient 로 재현 (R8/R9 준수). border-radius 9999px = 자동 pill. */
.f29b__banner--left {
background: linear-gradient(to right,
rgba(136, 131, 118, 0.343) 0%,
#39321E 73.1%,
#39321E 100%);
border-radius: 0 9999px 9999px 0;
}
.f29b__banner--right {
background: linear-gradient(to right,
#032118 0%,
rgba(41, 107, 85, 0.1) 100%);
border-radius: 9999px 0 0 9999px;
}
.f29b__banner-text {
position: relative;
z-index: 1;
font-size: var(--font-sub-title);
font-weight: 900;
line-height: 1;
text-shadow: 0 0 2px #322C1E;
-webkit-background-clip: text; background-clip: text;
color: transparent;
padding: 0 8px;
}
/* PROMOTED gradient — lines 101-104 / 110-113 */
.f29b__banner--left .f29b__banner-text {
background-image:
linear-gradient(90deg, rgb(62,53,35) 0%, rgb(62,53,35) 100%),
linear-gradient(180deg, rgb(41,107,85) 0%, rgb(18,51,40) 100%);
}
.f29b__banner--right .f29b__banner-text {
background-image:
linear-gradient(90deg, rgb(34,95,74) 0%, rgb(34,95,74) 100%),
linear-gradient(180deg, rgb(41,107,85) 0%, rgb(18,51,40) 100%);
}
/* body — 6 cell grid (3 rows × 2 cols) — 좌우 row divider Y 정렬 */
/* PROMOTED background — figma origin lines 53-68 (body-bg-left/right).
좌(0~50%): #39321E α0.3 (top) → white α0.3 (bottom)
우(50~100%): #296B55 α0.3 (top) → white α0.3 (bottom)
원본 SVG → CSS multi-bg 로 재현. */
.f29b__body {
flex: 1;
position: relative;
min-height: 0;
padding-top: 4px;
background:
linear-gradient(to bottom, rgba(57,50,30,0.3) 0%, rgba(255,255,255,0.3) 100%) 0% 0% / 50% 100% no-repeat,
linear-gradient(to bottom, rgba(41,107,85,0.3) 0%, rgba(255,255,255,0.3) 100%) 100% 0% / 50% 100% no-repeat;
}
/* 6 cell grid: 3 rows (section 1/2/3), 2 cols (process/product). 각 row 의 height = max(좌, 우) */
.f29b__grid {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-rows: auto;
gap: 6px 10px;
padding: 4px 8px;
height: 100%;
align-content: start;
}
.f29b__cell {
overflow: hidden;
min-width: 0;
min-height: 0;
}
/* row 2/3 (3 번째 cell 이후) 위에 dashed divider — 좌우 같은 Y */
.f29b__cell:nth-child(n+3) {
border-top: 1px dashed rgba(0,0,0,0.15);
padding-top: 6px;
margin-top: 4px;
}
/* section-title — 부소목차 (사용자 5-layer 직설 2026-05-07): Analogue 기반... 같은 깊이 0 굵은 bullet */
.f29b__section-title {
font-size: var(--font-sub-title); /* 12px — 부소목차 위계 */
font-weight: 900;
line-height: 1.3;
margin-bottom: 5px;
padding-left: 6px;
border-left: 3px solid currentColor;
}
.f29b__cell--left .f29b__section-title { color: #5C3714; } /* PROMOTED line 125 */
.f29b__cell--right .f29b__section-title { color: #084C56; } /* PROMOTED line 126 */
.f29b__section-title__sub {
font-size: var(--font-caption); /* 10px */
margin-left: 3px;
}
/* f29b 의 본문 = .text-line 공통 contract 사용. bullet color override. */
.f29b__cell .text-line--bullet { color: #000; font-weight: 700; }
/* AS-IS/TO-BE 좌우 + arrow (PROMOTED 구조) */
.f29b__transform {
display: grid;
grid-template-columns: 1fr auto 1fr;
gap: 4px;
align-items: start;
}
.f29b__transform__list {
/* .text-line 공통 contract 그대로. wrapper 만 grid 안의 cell 역할 */
}
.f29b__transform__arrow {
align-self: center;
width: 28px;
flex-shrink: 0;
}
.f29b__transform__arrow img {
width: 100%;
height: auto;
display: block;
}
.f29b__footnote {
font-size: var(--font-caption); /* 10px */
line-height: var(--lh-caption);
color: #333;
padding-left: 14px;
margin-top: 1px;
white-space: pre-wrap;
}
.f29b__aster-small { font-size: 9px; }
</style>
<div class="f29b" data-frame-id="1171281210" data-template-id="process_product_two_way">
<div class="f29b__title">2. Process의 혁신과 Product의 변화</div>
<div class="f29b__banners">
<div class="f29b__banner f29b__banner--left">
<div class="f29b__banner-text">과정(Process)의 혁신</div>
</div>
<div class="f29b__banner f29b__banner--right">
<div class="f29b__banner-text">결과(Product)의 변화</div>
</div>
</div>
<div class="f29b__body">
<div class="f29b__grid">
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">Analogue 기반 업무의 Digital화</div>
<div class="transform-block">
<div class="transform-block__header">
<span class="transform-block__label--from">AS-IS</span>
<span></span>
<span class="transform-block__label--to">TO-BE</span>
</div>
<div class="transform-rows">
<div class="transform-row">
<div class="transform-row__from">개념·문서·행정 절차 중심</div>
<div class="transform-row__arrow"></div>
<div class="transform-row__to">시각화된 목적물, 소통, 투명성 중심</div>
</div>
<div class="transform-row">
<div class="transform-row__from">2D 도면, 전문가, 규정</div>
<div class="transform-row__arrow"></div>
<div class="transform-row__to">3D 모델, 참여자, 실체</div>
</div>
<div class="transform-row">
<div class="transform-row__from">업무 구분(단절), 책임</div>
<div class="transform-row__arrow"></div>
<div class="transform-row__to">협업(융·복합), 창의성</div>
</div>
</div>
</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">Copy & Paste로 인해 하향 평준화된 기존 성과물의 품질 향상</div>
<div class="text-line text-line--bullet">과거 수작업으로 시행하면서 발생하던 오류 등의 최소화</div><div class="text-line text-line--bullet">정확한 Data에 기반한 계획으로 고품질 성과물 도출</div>
</div>
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">GIS + BIM의 연계</div>
<div class="text-line text-line--bullet">지리·지형·지반 등 위치정보(GIS)와 3D모델(형상, 속성정보) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">Analogue 기반 도서 외 Digital 기반 정보물 추가</div>
<div class="text-line text-line--bullet">기존 성과물(도면, 수량, 계산서, 시방서 등)에 3D 모델, Simulation 등의 Digital 기반 정보물 추가</div>
</div>
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">사용자 중심의 Solution 제공</div>
<div class="text-line text-line--bullet">서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계할 수 있는 설계·시공 Solution 제공</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">Solution을 활용한 업무 효율화</div>
<div class="text-line text-line--bullet">Engn. Solution을 통해 성과물에 관한 이슈를 함께 검토·논의하는 협업 환경 조성</div><div class="text-line text-line--bullet">건설 단계별 정보를 디지털 데이터로 축적하여, 건설 전 과정을 통합관리</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="slide-footer">
<div class="slide-footer-text">DX는 필요한 요건과 체계를 갖춘 후 시행해야만 그 효과를 기대할 수 있다.</div>
</div>
</div>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

@@ -0,0 +1,89 @@
---
title: DX 실행 체계 구축 방안
sidebar:
order: 02
---
## 1. DX 시행을 위한 필수 요건
<br/>
* **기술(디지털)**
* **Digital 기술(S/W, H/W)과 업무 Process의 통합**
* 기존 업무 프로세스에 다양한 디지털 기술을 접목하여 업무 수행
* 프로젝트 전반에 걸친 업무 프로세스의 연결 및 조율
* **분야별 전문 지식(설계, 시공, 유지관리 등) 보유**
* 건설 전 단계에 대한 근본적인 이해와 지식 및 경험
* 최신 토목 기술 트랜드 및 표준 기준 등에 대한 높은 지식
<br/>
* **사람(역량)**
* **혁신적 사고방식과 창의적 문제 해결 능력**
* 기존 수행 방식과 관습적 사고 등에 의한 접근 방식 탈피
* 디지털 기술을 활용한 창의적, 혁신적인 솔루션 제시
* **사용자 중심 사고와 DX 수행 경험**
* 사용자의 요구와 기대를 충족시키는 설계 및 구현
* 시행착오를 포함한 수행 경험과 사용자 경험(UX)을 반영한 해결 방안 제시
<br/>
* **자연(여건)**
* **지속적인 투자 및 실행 의지**
* 기술 도입 초기 단계에 필요한 인력·기간·비용 등의 대규모 투자
* 기술 고도화를 위한 지속적인 개선 및 투자 체계 구축
* 변화와 혁신을 통해 부가가치를 창출하려는 실행 의지와 추진력
<br/>
---
## 2. Process의 혁신과 Product의 변화
<br/>
### 2.1 과정(Process)의 혁신
* **Analogue 기반 업무의 Digital화**
| As-is [Analogue] | 구분 | To-be [Digital] |
| :--- | :---: | :--- |
| **개념·문서·행정 절차 중심** | ➠ | **시각화된 목적물, 소통, 투명성 중심** |
| **2D 도면, 전문가, 규정** | ➠ | **3D 모델, 참여자, 실체** |
| **업무 구분(단절), 책임** | ➠ | **협업(융·복합), 창의성** |
<br/>
* **GIS + BIM의 연계**
* 지리·지형·지반 등 위치정보(GIS)와 3D모델(형상, 속성정보) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신
<br/>
* **사용자 중심의 Solution 제공**
* 서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계할 수 있는 설계·시공 Solution 제공
<br/>
<br/>
### 2.2 결과(Product)의 변화
* **Copy & Paste로 인해 하향 평준화된 기존 성과물의 품질 향상**
* 과거 수작업으로 시행하면서 발생하던 오류 등의 최소화
* 정확한 Data에 기반한 계획으로 고품질 성과물 도출
<br/>
* **Analogue 기반 도서 외 Digital 기반 정보물 추가**
* 기존 성과물(도면, 수량, 계산서, 시방서 등)에 3D 모델, Simulation 등의 Digital 기반 정보물 추가
<br/>
* **Solution을 활용한 업무 효율화**
* Engn. Solution을 통해 성과물에 관한 이슈를 함께 검토·논의하는 협업 환경 조성
* 건설 단계별 정보를 디지털 데이터로 축적하여, 건설 전 과정을 통합관리
<br/>
---
:::note[핵심 요약]
* **DX는 필요한 요건과 체계를 갖춘 후 시행해야만 그 효과를 기대할 수 있다.**
:::
@@ -0,0 +1,21 @@
{
"step_num": 1,
"step_name": "mdx_upload",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"samples\\mdx_batch\\03.mdx"
],
"output": [
"step01_mdx_upload.json",
"step01_mdx_source.md"
],
"note": "MDX 원본 그대로 step01_mdx_source.md 에 복사.",
"data": {
"mdx_path": "samples\\mdx_batch\\03.mdx",
"run_id": "mdx03_f29_fix_check",
"run_dir": "d:\\ad-hoc\\kei\\design_agent\\data\\runs\\mdx03_f29_fix_check\\phase_z2",
"mdx_source_size_bytes": 3213,
"mdx_source_lines": 89
}
}
@@ -0,0 +1,36 @@
{
"step_num": 2,
"step_name": "normalized",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step01_mdx_source.md"
],
"output": [
"step02_normalized.json"
],
"note": "parse_mdx 결과: title / sections / footer 분리 + raw_content 보존. heading tree 미생성, orphan / details 감지 미완 (Step 2 ⚠ partial — 별 axis). orphans / details 필드는 schema lock — 빈 배열이라도 'detection 미수행' marker.",
"data": {
"slide_title": "DX 실행 체계 구축 방안",
"slide_footer": "DX는 필요한 요건과 체계를 갖춘 후 시행해야만 그 효과를 기대할 수 있다.",
"sections_count": 2,
"sections": [
{
"section_id": "03-1",
"section_num": 1,
"title": "1. DX 시행을 위한 필수 요건",
"raw_content_length": 660,
"raw_content": "<br/>\n\n* **기술(디지털)**\n * **Digital 기술(S/W, H/W)과 업무 Process의 통합**\n * 기존 업무 프로세스에 다양한 디지털 기술을 접목하여 업무 수행\n * 프로젝트 전반에 걸친 업무 프로세스의 연결 및 조율\n * **분야별 전문 지식(설계, 시공, 유지관리 등) 보유**\n * 건설 전 단계에 대한 근본적인 이해와 지식 및 경험\n * 최신 토목 기술 트랜드 및 표준 기준 등에 대한 높은 지식\n\n<br/>\n\n* **사람(역량)**\n * **혁신적 사고방식과 창의적 문제 해결 능력**\n * 기존 수행 방식과 관습적 사고 등에 의한 접근 방식 탈피\n * 디지털 기술을 활용한 창의적, 혁신적인 솔루션 제시\n * **사용자 중심 사고와 DX 수행 경험**\n * 사용자의 요구와 기대를 충족시키는 설계 및 구현\n * 시행착오를 포함한 수행 경험과 사용자 경험(UX)을 반영한 해결 방안 제시\n\n<br/>\n\n* **자연(여건)**\n * **지속적인 투자 및 실행 의지**\n * 기술 도입 초기 단계에 필요한 인력·기간·비용 등의 대규모 투자\n * 기술 고도화를 위한 지속적인 개선 및 투자 체계 구축\n * 변화와 혁신을 통해 부가가치를 창출하려는 실행 의지와 추진력\n\n<br/>\n---"
},
{
"section_id": "03-2",
"section_num": 2,
"title": "2. Process의 혁신과 Product의 변화",
"raw_content_length": 924,
"raw_content": "<br/>\n\n### 2.1 과정(Process)의 혁신\n\n* **Analogue 기반 업무의 Digital화**\n\n | As-is [Analogue] | 구분 | To-be [Digital] |\n | :--- | :---: | :--- |\n | **개념·문서·행정 절차 중심** | ➠ | **시각화된 목적물, 소통, 투명성 중심** |\n | **2D 도면, 전문가, 규정** | ➠ | **3D 모델, 참여자, 실체** |\n | **업무 구분(단절), 책임** | ➠ | **협업(융·복합), 창의성** |\n\n<br/>\n\n* **GIS + BIM의 연계**\n * 지리·지형·지반 등 위치정보(GIS)와 3D모델(형상, 속성정보) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신\n\n<br/>\n\n* **사용자 중심의 Solution 제공**\n * 서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계할 수 있는 설계·시공 Solution 제공\n\n<br/>\n<br/>\n\n### 2.2 결과(Product)의 변화\n\n* **Copy & Paste로 인해 하향 평준화된 기존 성과물의 품질 향상**\n * 과거 수작업으로 시행하면서 발생하던 오류 등의 최소화\n * 정확한 Data에 기반한 계획으로 고품질 성과물 도출\n\n<br/>\n\n* **Analogue 기반 도서 외 Digital 기반 정보물 추가**\n * 기존 성과물(도면, 수량, 계산서, 시방서 등)에 3D 모델, Simulation 등의 Digital 기반 정보물 추가\n\n<br/>\n\n* **Solution을 활용한 업무 효율화**\n * Engn. Solution을 통해 성과물에 관한 이슈를 함께 검토·논의하는 협업 환경 조성\n * 건설 단계별 정보를 디지털 데이터로 축적하여, 건설 전 과정을 통합관리\n\n<br/>\n---"
}
],
"orphans": [],
"details": []
}
}
@@ -0,0 +1,63 @@
{
"step_num": 5,
"step_name": "v4_evidence",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step02_normalized.json",
"tests/matching/v4_full32_result.yaml"
],
"output": [
"step05_v4_evidence.json"
],
"note": "V4 non-reject max-6 후보 list (Step 9 application_plan input). raw 32 entry 는 tests/matching/v4_full32_result.yaml 에 영속. candidate_status='ok' = 후보 1개 이상 / 'no_non_reject_v4_candidate' = 0개 (Step 9 fallback path 입력). Step 6 plan_composition() 은 lookup_v4_match() (rank-1) 그대로 사용 — backward compat (Step 6-A axis 까지).",
"data": {
"v4_source": "tests\\matching\\v4_full32_result.yaml",
"aligned_section_ids": [
"03-1",
"03-2"
],
"evidence_per_section": [
{
"section_id": "03-1",
"v4_candidates": [
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"frame_number": 13,
"confidence": 0.9268,
"label": "use_as_is"
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"frame_number": 20,
"confidence": 0.8413,
"label": "light_edit"
}
],
"candidate_status": "ok"
},
{
"section_id": "03-2",
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.9198,
"label": "use_as_is"
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"frame_number": 27,
"confidence": 0.6278,
"label": "restructure"
}
],
"candidate_status": "ok"
}
]
}
}
@@ -0,0 +1,180 @@
{
"step_num": 6,
"step_name": "composition_plan",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step02_normalized.json",
"step05_v4_evidence.json"
],
"output": [
"step06_composition_plan.json"
],
"note": "composition v0 count-based — sections → candidates → score → greedy select. Step 6-A (사용자 lock 2026-05-08): selected_units[i].v4_candidates 추가 (non-reject max-6 후보 list, candidates[0] = 단일 frame_* 와 일관). logic 무변 — runtime 결과 동일. Step 9 application_plan input.",
"data": {
"selected_units_count": 2,
"layout_preset_decided": "horizontal-2",
"candidates_summary": [
{
"source_section_ids": [
"03-1"
],
"merge_type": "single",
"template_id": "three_parallel_requirements",
"label": "use_as_is",
"phase_z_status": "matched_zone",
"score": 0.9268,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 3,
"source_shape": "top_bullets",
"capacity": {
"strict": 3,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
},
{
"source_section_ids": [
"03-2"
],
"merge_type": "single",
"template_id": "process_product_two_way",
"label": "use_as_is",
"phase_z_status": "matched_zone",
"score": 0.9198,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"candidates_total": 2,
"candidates_viable_auto": 2,
"selected_units": [
{
"source_section_ids": [
"03-1"
],
"merge_type": "single",
"frame_id": "1171281190",
"frame_number": 13,
"frame_template_id": "three_parallel_requirements",
"label": "use_as_is",
"score": 0.9268,
"phase_z_status": "matched_zone",
"rationale": {
"capacity_fit": {
"item_count": 3,
"source_shape": "top_bullets",
"capacity": {
"strict": 3,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.9268,
"confidence": 0.9268,
"label": "use_as_is",
"label_weight": 1.0,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"notes": [],
"v4_candidates": [
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"frame_number": 13,
"confidence": 0.9268,
"label": "use_as_is"
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"frame_number": 20,
"confidence": 0.8413,
"label": "light_edit"
}
]
},
{
"source_section_ids": [
"03-2"
],
"merge_type": "single",
"frame_id": "1171281210",
"frame_number": 29,
"frame_template_id": "process_product_two_way",
"label": "use_as_is",
"score": 0.9198,
"phase_z_status": "matched_zone",
"rationale": {
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.9198,
"confidence": 0.9198,
"label": "use_as_is",
"label_weight": 1.0,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"notes": [],
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.9198,
"label": "use_as_is"
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"frame_number": 27,
"confidence": 0.6278,
"label": "restructure"
}
]
}
]
}
}
@@ -0,0 +1,79 @@
{
"step_num": 7,
"step_name": "layout",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step06_composition_plan.json"
],
"output": [
"step07_layout.json",
"step07_selected_layout.html"
],
"note": "count-based v0 — 들여쓰기 / 정렬 미세 layout 미구현 (Step 7 ⚠ partial). Step 7-conn (사용자 lock 2026-05-08): unit_count → layout_candidates list (select_layout_candidates) artifact 기록. default 결정 자체는 무변 — candidates[0] 가 default (default_selection: true), 나머지는 alternative. Step 9 application_plan input.",
"data": {
"layout_preset": "horizontal-2",
"layout_css": {
"areas": "\"top\" \"bottom\"",
"cols": "1fr",
"rows": "228px 343px",
"heights_px": [
228,
343
],
"ratios": [
0.39,
0.586
],
"computation": "min_height_first + content_weight_distribution",
"dynamic_rows": true,
"raw_zone_layout": {
"computation": "min_height_first + content_weight_distribution",
"slide_body_height": 585,
"gap": 14,
"available_after_gap": 571,
"min_heights_px": [
228,
342
],
"min_scaled": true,
"total_min_height": 570,
"remaining_after_min": 1,
"content_weights": [
{
"position": "top",
"template_id": "three_parallel_requirements",
"score": 4.425
},
{
"position": "bottom",
"template_id": "process_product_two_way",
"score": 7.305
}
],
"weight_shares": [
0.377,
0.623
],
"extras_px": [
0,
1
],
"heights_px": [
228,
343
],
"ratios": [
0.39,
0.586
]
}
},
"zones_count": 2,
"unit_count": 2,
"layout_candidates": [
"horizontal-2",
"vertical-2"
]
}
}
@@ -0,0 +1,122 @@
{
"step_num": 8,
"step_name": "zone_region_ratios",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step07_layout.json",
"step10_frame_contract.json"
],
"output": [
"step08_zone_region_ratios.json",
"step08_zone_content_placement.html"
],
"note": "계획값 only. 실측값은 Step 14 (visual_check). zone-level 만 dynamic, region-level (sub_zone 안 sections) 은 균등 분배 (1/1/1). F29 처럼 비균등 콘텐츠 (transform_table + plain) 는 첫 cell 부족 가능 — Step 8 ⚠ partial. Step 8-conn (사용자 lock 2026-05-08): per_zone_plan[i] 에 region_layout_candidates + display_strategy_candidates 추가 (passive 기록). placeholder signals = text-only / region_count=1 (Step 3/4 부재 종속). 실제 content_object 신호 활성화는 별 axis. Step 9 application_plan input.",
"data": {
"zone_heights_px_planned": [
228,
343
],
"zone_ratios_planned": [
0.39,
0.586
],
"per_zone_plan": [
{
"position": "top",
"zone_height_px_planned": 228,
"zone_ratio_planned": 0.39,
"min_height_px": 230,
"frame_cardinality_strict": 3,
"sub_zones_planned": [
{
"id": "pillar_1",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": 1,
"partial_target_path": ".f13b__cols > .f13b__col:nth-child(1)"
},
{
"id": "pillar_2",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": 1,
"partial_target_path": ".f13b__cols > .f13b__col:nth-child(2)"
},
{
"id": "pillar_3",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": 1,
"partial_target_path": ".f13b__cols > .f13b__col:nth-child(3)"
}
],
"child_distribution_note": "현재 child zone (sub_zones 안 sections) 균등 분배 — Step 8 region-level ratio ⚠ partial.",
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
]
},
{
"position": "bottom",
"zone_height_px_planned": 343,
"zone_ratio_planned": 0.586,
"min_height_px": 345,
"frame_cardinality_strict": 2,
"sub_zones_planned": [
{
"id": "process_column",
"role": "main_text",
"accepts": [
"text_block",
"transform_table"
],
"cardinality_strict": 3,
"partial_target_path": ".f29b__grid .f29b__cell--left"
},
{
"id": "product_column",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": 3,
"partial_target_path": ".f29b__grid .f29b__cell--right"
}
],
"child_distribution_note": "현재 child zone (sub_zones 안 sections) 균등 분배 — Step 8 region-level ratio ⚠ partial.",
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
]
}
],
"step8_conn_placeholder_signals": {
"region_count": 1,
"content_type": "text_block",
"flow_type": null,
"role_pattern": null,
"ratio_asymmetric": false,
"has_visual_element": false,
"details_presence": false,
"large_table": false,
"long_text": false,
"fits_in_region": null,
"_note": "Step 3/4 부재 종속 placeholder — 모든 zone 을 text-only / region_count=1 로 가정. 실제 content_object 신호 활성화는 별 axis."
}
}
}
@@ -0,0 +1,135 @@
{
"step_num": 9,
"step_name": "application_plan",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step05_v4_evidence.json",
"step06_composition_plan.json",
"step07_layout.json",
"step08_zone_region_ratios.json"
],
"output": [
"step09_application_plan.json",
"step09_application_plan.html"
],
"note": "Step 9 v0 passive application_plan trace (사용자 lock 2026-05-08). V4 후보 + layout / region / display 후보 + V4 label → application_mode 변환을 side-by-side 로 기록. v0 invariant 5 가지 (status.md §4) 만족. Step 6 의 default 결정 그대로 (current_default_candidate). auto decision 은 Step 9 v1 (별 axis). region/display 후보는 Step 8-conn 의 placeholder signal 종속 (Step 3/4 부재).",
"data": {
"units": [
{
"unit_id": "03-1",
"layout_preset": "horizontal-2",
"layout_candidates": [
"horizontal-2",
"vertical-2"
],
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
],
"candidate_status": "ok",
"application_status": "ok",
"current_default_candidate": "three_parallel_requirements",
"v4_candidates": [
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"frame_number": 13,
"confidence": 0.9268,
"label": "use_as_is"
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"frame_number": 20,
"confidence": 0.8413,
"label": "light_edit"
}
],
"application_candidates": [
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"v4_label": "use_as_is",
"application_mode": "direct_insert",
"auto_applicable": true,
"required_changes": [],
"delegated_to": "step10_contract_check"
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"v4_label": "light_edit",
"application_mode": "same_frame_with_adjustment",
"auto_applicable": true,
"required_changes": [],
"delegated_to": "step10_contract_check"
}
]
},
{
"unit_id": "03-2",
"layout_preset": "horizontal-2",
"layout_candidates": [
"horizontal-2",
"vertical-2"
],
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
],
"candidate_status": "ok",
"application_status": "ok",
"current_default_candidate": "process_product_two_way",
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.9198,
"label": "use_as_is"
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"frame_number": 27,
"confidence": 0.6278,
"label": "restructure"
}
],
"application_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"v4_label": "use_as_is",
"application_mode": "direct_insert",
"auto_applicable": true,
"required_changes": [],
"delegated_to": "step10_contract_check"
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"v4_label": "restructure",
"application_mode": "layout_or_region_change",
"auto_applicable": false,
"required_changes": [],
"delegated_to": "human_review"
}
]
}
],
"candidate_status_summary": {
"units_with_no_v4_candidate": []
},
"v0_lock_note": "Step 9 v0 passive (사용자 lock 2026-05-08). Step 6 default 그대로 사용 — runtime 결과 byte-동일. auto decision / scoring 은 Step 9 v1 (별 axis)."
}
}
@@ -0,0 +1,38 @@
{
"step_num": 20,
"step_name": "slide_status",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step14_visual_check.json",
"step17_retry_trace.json",
"step19_next_action.json"
],
"output": [
"step20_slide_status.json",
"step20_final_status.html"
],
"note": "자동 파이프라인 최종 결과 보고. overall = PASS/RENDERED_WITH_VISUAL_REGRESSION/PARTIAL_COVERAGE 등.",
"data": {
"rendered": true,
"visual_check_passed": true,
"full_mdx_coverage": true,
"aligned_section_ids": [
"03-1",
"03-2"
],
"covered_section_ids": [
"03-1",
"03-2"
],
"filtered_section_ids": [],
"filtered_section_reasons": [],
"visual_fail_reasons": [],
"adapter_needed_count": 0,
"adapter_needed_units": [],
"content_truncated_count": 0,
"content_truncated_units": [],
"overall": "PASS",
"note": "자동 파이프라인 결과 보고. review/UI 개념 X. final.html 파일명 != PASS 의미. overall == PASS 는 visual OK + full coverage + adapter_needed=0 일 때만. adapter_needed_count > 0 = mapper 가 contract 와 안 맞아 자동 렌더 못 한 zone 존재. content_truncated_count > 0 = builder 가 truncate 한 zone 존재 (rendered 됐지만 일부 콘텐츠 손실)."
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,992 @@
<!-- Phase Z-2 MVP-1.5b — single slide + Type B layout (top/bottom zones).
원래 Phase Z 설계 복귀: MDX 1 = slide 1, layout preset = zone 분할, frame-derived block ⊂ zone. -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280">
<title>DX 지연 요인</title>
<style>
/* ── existing tokens (inlined) ── */
/* === typography.css === */
/* ══════════════════════════════════════
Typography Tokens v1
══════════════════════════════════════
슬라이드 전체의 공통 글자 위계.
모든 블록은 이 토큰을 참조한다.
직접값(font-size: 11px) 금지 → var(--font-body) 사용.
══════════════════════════════════════ */
:root {
/* ── 1층: Global Hierarchy ── */
/* 대목차: 슬라이드 상단 제목 */
--font-slide-title: 22px;
--weight-slide-title: 700;
--lh-slide-title: 1.4;
/* 중목차: zone 제목 */
--font-zone-title: 16px;
--weight-zone-title: 700;
--lh-zone-title: 1.4;
/* 소목차: 블록 내 소제목, 카드 제목 */
--font-sub-title: 12px;
--weight-sub-title: 700;
--lh-sub-title: 1.45;
/* 본문: 블릿, 설명 텍스트 */
--font-body: 10px;
--weight-body: 500;
--lh-body: 1.55;
/* 캡션: 각주, 출처, 보조 텍스트 */
--font-caption: 10px;
--weight-caption: 400;
--lh-caption: 1.4;
/* footer: 핵심 인사이트 pill */
--font-footer: 20px;
--weight-footer: 700;
--lh-footer: 1.2;
/* ── 2층: Component Semantic Tokens ── */
/* 가까운 위계에서 기본값, 필요시 override */
/* 본문 강조 (인라인 heading) */
--font-body-strong: var(--font-body);
--weight-body-strong: 600;
/* 자세히보기 링크 */
--font-detail-link: var(--font-caption);
--weight-detail-link: 500;
/* pill/badge 라벨 */
--font-pill-label: var(--font-sub-title);
--weight-pill-label: 700;
/* 표 헤더 */
--font-table-header: var(--font-sub-title);
--weight-table-header: 700;
/* 표 셀 */
--font-table-cell: var(--font-body);
--weight-table-cell: 400;
/* 비교 뱃지 */
--font-compare-badge: var(--font-sub-title);
--weight-compare-badge: 700;
/* 강조 인용 */
--font-callout: var(--font-sub-title);
--weight-callout: 700;
/* 상단 라벨 (overline) */
--font-overline: var(--font-caption);
--weight-overline: 600;
--ls-overline: 0.05em;
}
/* === spacing.css === */
/* ══════════════════════════════════════
Spacing Tokens v1
══════════════════════════════════════
여백/간격/들여쓰기 공통 기준.
══════════════════════════════════════ */
:root {
/* ── 기본 스케일 ── */
--space-xs: 4px;
--space-sm: 8px;
--space-md: 12px;
--space-lg: 16px;
--space-xl: 24px;
/* ── slide-base 레이아웃 ── */
--slide-padding-x: 40px; /* 본문 좌우 여백 */
--slide-title-left: 52px; /* 대목차 시작 */
--slide-title-top: 22px; /* 대목차 위치 */
--slide-divider-top: 58px; /* 구분선 위치 (slide_base.html 와 일치 2026-05-07) */
--slide-body-top: 76px; /* 본문 시작 (사용자 직설: divider-body 16px) */
--slide-body-height: 585px; /* 본문 높이 (사용자 직설: body-footer 10px) */
--slide-footer-bottom: 8px; /* footer 하단 여백 (slide_base.html 와 일치) */
--slide-footer-height: 41px; /* footer 높이 */
/* ── zone ── */
--zone-gap: 8px; /* zone 간 간격 */
--zone-padding-left: 12px; /* zone 안쪽 좌측 여백 */
--zone-padding-right: 8px; /* zone 안쪽 우측 여백 */
--zone-title-mb: 8px; /* zone 제목 아래 여백 */
/* ── 블록 공통 ── */
--card-padding: 16px; /* 카드 내부 여백 */
--card-padding-sm: 8px; /* 작은 카드 내부 여백 */
--card-gap: 12px; /* 카드 간 간격 */
--card-radius: 6px; /* 카드 모서리 */
/* ── 블릿/텍스트 ── */
--bullet-indent: 14px; /* 불릿 hanging indent */
--bullet-gap: 2px; /* 불릿 항목 간 간격 */
--heading-gap: 4px; /* 소제목 아래 간격 */
--section-gap: 10px; /* 섹션 간 간격 */
/* ── flex/grid 기본 ── */
--flex-gap: 12px; /* 기본 flex gap */
--flex-gap-sm: 6px; /* 좁은 flex gap */
--grid-gap: 16px; /* 기본 grid gap */
}
/* === colors.css === */
/* ══════════════════════════════════════
Color Tokens v1
══════════════════════════════════════
2층 구조: 공통 테마색 + 블록 의미색.
══════════════════════════════════════ */
:root {
/* ══ 1층: 공통 테마색 ══ */
/* 모든 블록이 공유하는 기본 팔레트 */
/* 텍스트 */
--color-title: #1e293b; /* 제목 (진한 남색) */
--color-zone-title: #1a365d; /* zone 중목차 제목 */
--color-body: #475569; /* 본문 */
--color-body-strong: #1e293b; /* 본문 강조 */
--color-caption: #94a3b8; /* 캡션, 보조 */
--color-muted: #64748b; /* 약한 텍스트 */
/* 배경 */
--color-bg: #ffffff; /* 슬라이드 배경 */
--color-bg-subtle: #f8fafc; /* 카드/영역 배경 */
--color-bg-page: #e8ecf0; /* 페이지 배경 (슬라이드 바깥) */
/* 보더 */
--color-border: #e2e8f0; /* 기본 보더 */
--color-border-strong: #cbd5e1; /* 강한 보더 */
/* 강조 */
--color-accent: #2563eb; /* 링크, 강조 (파랑) */
--color-accent-hover: #eff6ff; /* 링크 hover 배경 */
--color-danger: #dc2626; /* 경고, 에러 */
/* slide-base 전용 */
--color-slide-title-from: #296b55; /* 대목차 gradient 시작 */
--color-slide-title-to: #123328; /* 대목차 gradient 끝 */
--color-footer-bg-from: #3b3523; /* footer gradient 시작 */
--color-footer-bg-mid: #263a2a; /* footer gradient 중간 */
--color-footer-bg-to: #113f31; /* footer gradient 끝 */
--color-footer-text: #ffffff; /* footer 텍스트 */
--color-footer-accent: #ffee33; /* footer 강조 (em) */
/* ══ 2층: 블록 의미색 ══ */
/* 특정 블록 유형에서 의미를 가지는 색 */
/* 3열 비교 (prerequisites-3col) */
--color-col-1-from: #0D78D0; /* 1열 gradient 시작 */
--color-col-1-to: #023056; /* 1열 gradient 끝 */
--color-col-2-from: #FF9A23; /* 2열 gradient 시작 */
--color-col-2-to: #CC5200; /* 2열 gradient 끝 */
--color-col-3-from: #39BE49; /* 3열 gradient 시작 */
--color-col-3-to: #23742C; /* 3열 gradient 끝 */
/* 비교 블록 (compare) */
--color-compare-left: #5c3714; /* 좌측 (AS-IS 계열) */
--color-compare-right: #285b4a; /* 우측 (TO-BE 계열) */
--color-compare-badge: #ae3607; /* VS 뱃지 */
/* 다크 카드 (direct render) */
--color-dark-card-1: #1a365d; /* 카드 1 배경 */
--color-dark-card-2: #1e3a2f; /* 카드 2 배경 */
--color-dark-card-3: #3b1f2b; /* 카드 3 배경 */
--color-dark-card-title: #fbbf24; /* 다크카드 제목 (금색) */
--color-dark-card-body: #e2e8f0; /* 다크카드 본문 */
/* 표 */
--color-table-header-bg: #64748b; /* 표 헤더 배경 */
--color-table-header-text: #ffffff; /* 표 헤더 텍스트 */
/* 블록 제목 gradient (Figma 원본) */
--color-block-title-from: #CC5200; /* 주황 gradient 시작 */
--color-block-title-to: #883700; /* 주황 gradient 끝 */
/* pill */
--color-pill-bg: #1e293b; /* pill 배경 */
--color-pill-text: #ffffff; /* pill 텍스트 */
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
background: #e8ecf0;
display: flex; justify-content: center; align-items: center;
min-height: 100vh;
word-break: keep-all;
padding: 20px 0;
}
/* ── 16:9 슬라이드 (single, 1280×720) ── */
.slide {
width: 1280px; height: 720px;
position: relative;
overflow: hidden;
background: #fff;
box-shadow: 0 4px 20px rgba(0,0,0,.15);
flex-shrink: 0;
}
.slide-bg {
position: absolute; inset: 0;
background: linear-gradient(180deg, #f0f0f0 0%, #ffffff 100%);
z-index: 0;
}
.slide-title {
position: absolute;
left: 52px; top: 22px;
width: calc(100% - 104px);
font-weight: 700;
font-size: var(--font-slide-title);
line-height: var(--lh-slide-title);
background-image: linear-gradient(180deg, #296b55 0%, #123328 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
text-shadow: 0 0 2px #322c1e;
z-index: 2;
}
.slide-divider {
position: absolute;
left: 50px; top: 58px;
width: calc(100% - 100px);
height: 2px;
background: #cbd5e1;
z-index: 2;
}
.slide-body {
position: absolute;
left: 50px; top: 76px;
width: calc(100% - 100px); /* 1180 */
height: 585px;
z-index: 1;
overflow: hidden;
}
/* ── Layout preset (composition planner v0 — 8 vocabulary) ──
단일 .layout-{preset} 클래스에 grid CSS 주입.
layout_css = pipeline build_layout_css() 결과 :
- horizontal-2 : rows = dynamic px (content_weight + frame_min_height)
- 그 외 : rows / cols = fr default (LAYOUT_PRESETS)
positions (single / top / bottom / left / right / top-left / ... / grid-2x2 9개)
은 .zone 의 inline grid-area 로 지정 — preset CSS 는 areas 만 정의. */
.layout-horizontal-2 {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 211px 360px;
grid-template-areas: "top" "bottom";
gap: 14px;
height: 100%;
}
/* ── Zone — block 가용 공간 최대화. 프레임 자체 styling 이 boundary 역할 ── */
.zone {
position: relative;
overflow: hidden;
padding: 0;
min-width: 0;
min-height: 0;
}
/* ── Frame-family text layout contract (shared, reusable) ──
feedback-1 (mvp1.5b_test7): visible improvement 강화.
Stronger hanging indent + breathing line spacing + visible hierarchy. */
.text-line {
font-size: var(--font-body); /* 11px */
font-weight: var(--weight-body);
line-height: 1.6; /* breathing room */
margin: 0;
}
.text-line + .text-line {
margin-top: 4px; /* visible gap between lines (was 2px) */
}
/* bullet line — hanging indent via padding + absolute marker (안정적) */
.text-line--bullet {
padding-left: 14px;
position: relative;
}
.text-line--bullet::before {
content: "•"; /* visible bullet 마커 */
position: absolute;
left: 2px;
top: 0;
font-weight: 700;
line-height: inherit;
color: inherit;
}
/* indent levels — visible nested hierarchy */
.text-line--indent-1 {
padding-left: 30px;
}
.text-line--indent-1::before {
content: "◦"; /* sub-bullet 다른 마커 */
left: 18px;
}
.text-line--indent-2 {
padding-left: 46px;
}
.text-line--indent-2::before {
content: "▪";
left: 34px;
}
/* body line — 마커 없음 */
.text-line--body {
padding-left: 0;
}
.text-line strong { color: #000; font-weight: 700; }
/* ── Transform-block family (frame 29 AS-IS/TO-BE dedicated comparison component) ──
feedback-3: bullet rows 가 아닌 *전용 비교 component*. Header (AS-IS / TO-BE) + paired rows.
color-coded cells, left-border accent → 단번에 *비교 구조* 인지. */
.transform-block {
margin-top: 4px;
padding: 6px 8px 6px;
background: rgba(255, 255, 255, 0.4);
border-radius: 3px;
border: 1px solid rgba(0,0,0,0.05);
}
.transform-block__header {
display: grid;
grid-template-columns: 1fr 22px 1fr;
gap: 6px;
margin-bottom: 4px;
padding-bottom: 3px;
border-bottom: 1px dashed rgba(0,0,0,0.12);
font-size: 9px;
font-weight: 900;
letter-spacing: 0.5px;
}
.transform-block__label--from { color: #6b5444; }
.transform-block__label--to { color: #2563eb; text-align: left; }
.transform-rows {
display: flex; flex-direction: column;
gap: 4px;
}
.transform-row {
display: grid;
grid-template-columns: 1fr 22px 1fr;
gap: 6px;
align-items: stretch;
font-size: var(--font-body);
line-height: 1.45;
}
.transform-row__from {
padding: 3px 8px;
background: linear-gradient(90deg, rgba(140,120,90,0.16), rgba(140,120,90,0.08));
border-left: 2px solid #b8a98a;
border-radius: 2px;
color: #4b3f30;
font-weight: 500;
}
.transform-row__arrow {
text-align: center;
color: #2563eb;
font-weight: 900;
font-size: 14px;
align-self: center;
}
.transform-row__to {
padding: 3px 8px;
background: linear-gradient(90deg, rgba(37,99,235,0.10), rgba(37,99,235,0.18));
border-left: 2px solid #2563eb;
border-radius: 2px;
color: #1e40af;
font-weight: 700;
}
/* ── Footer pill — feedback-3: body 와 weight balance, 살짝 가벼워짐 ── */
.slide-footer {
position: absolute;
left: 50px; bottom: 8px;
width: calc(100% - 100px); /* front 기준 (body 와 정렬) */
height: 41px; /* front 기준 */
border-radius: 999px;
overflow: hidden;
z-index: 2;
display: flex; align-items: center; justify-content: center;
background: linear-gradient(90deg, #3b3523 5%, #263a2a 50%, #113f31 95%);
opacity: 0.92; /* slightly lighter */
}
.slide-footer-text {
position: relative; z-index: 1;
font-size: 15px; /* was 20px (--font-footer) */
font-weight: 700;
line-height: 1.2;
color: #fff;
text-align: center;
text-shadow: 0 0 3px rgba(0,0,0,.4);
letter-spacing: -0.01em;
}
.slide-footer-text em { color: #fe3; font-style: normal; }
.phase-z2-marker {
position: absolute;
top: 4px; right: 8px;
font-size: 9px; color: #94a3b8;
font-family: monospace;
z-index: 3;
}
</style>
</head>
<body>
<div class="slide" data-page="1">
<div class="slide-bg"></div>
<div class="phase-z2-marker">phase_z2 / mvp-1.5b / horizontal-2 / single slide</div>
<div class="slide-title">DX 지연 요인</div>
<div class="slide-divider"></div>
<div class="slide-body">
<div class="layout-horizontal-2">
<div class="zone" data-zone-position="top" data-template-id="pre_construction_model_info_stacked" style="grid-area: top;">
<!-- Phase Z-2 신규 frame partial — Frame 9 (1171281180) pre_construction_model_info_stacked.
2026-05-14 — V4 04-1 top rank-1 매칭 (의미 conf=0.722) + structure cardinality 5 일치.
사용자 룰 부합 : Figma visual (계단 pill / 5 색상 / vertical label) 유지 + 콘텐츠 cardinality
에 맞춰 보완 (pill 안 1 라인 → multi-line: pill_N_label + pill_N_body). -->
<style>
.f9b {
width: 100%; height: 100%;
display: flex; flex-direction: column;
gap: 6px;
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
word-break: keep-all;
position: relative;
}
/* 2026-05-14 — title 스타일 통일 (frame 29 process_product_two_way 와 동일 패턴) :
배경 box + box-shadow 제거, gradient 텍스트 만 유지. 사용자 룰 Q1. */
.f9b__title {
font-size: var(--font-zone-title);
font-weight: 700;
line-height: var(--lh-zone-title);
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
flex-shrink: 0;
padding-left: 4px;
}
.f9b__body {
flex: 1;
display: flex;
flex-direction: row;
gap: 8px;
min-height: 0;
}
/* 좌측 vertical label — 콘텐츠 있을 때만 표시 */
.f9b__vlabel {
flex: 0 0 auto;
width: 56px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: var(--font-sub-title);
line-height: 1.2;
color: #144838;
text-align: center;
writing-mode: vertical-rl;
text-orientation: upright;
text-shadow: 0 2px 2px rgba(0,0,0,0.15);
}
/* 2026-05-14 — pill 배치 vertical → horizontal (grid). 5 pills 를 가로로 나열 →
우측 공란 활용 + 세로 공간 절약. auto-fit + minmax 으로 N 동적 (4 / 5 / 6 모두 자동). */
.f9b__pill-rows {
flex: 1;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 6px;
min-height: 0;
}
/* 2026-05-14 — bullet 줄간격 1/3 으로 압축 + 다른 간격 (padding, label↔body) 살짝 늘림. */
.f9b__pill {
min-height: 0;
background: rgba(255,255,255,0.7);
border-radius: 10px;
border-bottom: 3px solid;
box-shadow: 1px 2px 4px rgba(0,0,0,0.15);
padding: 8px 12px;
display: flex;
flex-direction: column;
gap: 5px;
overflow: hidden;
align-self: start;
}
/* Figma frame 9 의 5 색상 — nth-child cycle. N>5 면 default border-bottom 색 (회색). */
.f9b__pill:nth-child(5n+1) { border-bottom-color: #fb5915; }
.f9b__pill:nth-child(5n+2) { border-bottom-color: #e79000; }
.f9b__pill:nth-child(5n+3) { border-bottom-color: #e9a804; }
.f9b__pill:nth-child(5n+4) { border-bottom-color: #919f00; }
.f9b__pill:nth-child(5n) { border-bottom-color: #0d6361; }
.f9b__pill-label {
font-size: var(--font-sub-title);
font-weight: 900;
line-height: 1.2;
color: #144838;
margin-bottom: 4px;
display: flex;
align-items: center;
gap: 6px;
}
/* arrow indicator — Figma frame 9 의 좌측 화살표 (▶) approximation */
.f9b__pill-label::before {
content: "▶";
flex-shrink: 0;
color: currentColor;
font-size: 0.85em;
}
/* 2026-05-14 — bullet 줄간격 1/3 으로 압축 : line-height 1.3 → 1.05 (약 1/3 감소).
bullet 간 gap 2 → 1 로 더 압축. 가독성 임계 (한 bullet 안 line wrap 시 라인 겹침 직전). */
.f9b__pill-body {
flex: 1 1 auto;
overflow: hidden;
min-height: 0;
color: #0c271e;
font-size: var(--font-body);
line-height: 1.05;
display: flex;
flex-direction: column;
gap: 1px;
}
/* 첫 line = 인용구 (italic + 무 마커) — 04-1 의 따옴표 인용구 패턴 */
.f9b__pill-body .text-line:first-child {
font-style: italic;
color: #5C3714;
padding-left: 0;
}
/* 이후 lines = 각 이슈 bullet (▪ 마커로 구분 강화) */
.f9b__pill-body .text-line:not(:first-child) {
position: relative;
padding-left: 12px;
}
.f9b__pill-body .text-line:not(:first-child)::before {
content: "▪";
position: absolute;
left: 0;
color: #919f00;
font-size: 0.9em;
}
</style>
<div class="f9b" data-frame-id="1171281180" data-template-id="pre_construction_model_info_stacked">
<div class="f9b__title">1. DX에 대한 인식</div>
<div class="f9b__body">
<div class="f9b__pill-rows">
<div class="f9b__pill" data-frame-slot-id="pill_dynamic" data-pill-n="1">
<div class="f9b__pill-label">기술 및 소프트웨어 이해도</div>
<div class="f9b__pill-body">
<div class="text-line">"무슨 말인지 잘 모르겠다, 어디까지 어떻게 해야 하는지 모르겠다"</div><div class="text-line">기본지침, 시행지침 등 새롭게 알아야 할 게 너무 많다.</div><div class="text-line">3D 모델과 별 차이점을 모르겠다. S/W마다 사용법이 다르다.</div><div class="text-line">필요한 것은 쉽고 간단한 건데, 왜 이렇게 복잡하게 만들까?</div>
</div>
</div>
<div class="f9b__pill" data-frame-slot-id="pill_dynamic" data-pill-n="2">
<div class="f9b__pill-label">효과와 효율성</div>
<div class="f9b__pill-body">
<div class="text-line">"2D 설계 후 전환설계를 수행하는데 효과는 모르겠고, 효율은 낮다"</div><div class="text-line">성과품 작성은 기존과 같게 하고, 추가 업무만 발생해 효율이 낮다.</div><div class="text-line">BIM으로 인해 가중되는 업무 대비 효과가 거의 없어 보인다.</div><div class="text-line">결과적으로 큰 차이를 못 느끼겠고, 이런 노력이 정말 가치 있는 일이야?</div>
</div>
</div>
<div class="f9b__pill" data-frame-slot-id="pill_dynamic" data-pill-n="3">
<div class="f9b__pill-label">인력 및 교육</div>
<div class="f9b__pill-body">
<div class="text-line">"수행 인력이 부족하고, 기존 직원들은 어떻게 교육해야 하나"</div><div class="text-line">교육시간 손실로 일손이 더 필요해지고, 적응하는데도 시간이 걸린다.</div><div class="text-line">신입사원은 없고 BIM 수행을 할 수 있는 기술자가 부족하다.</div><div class="text-line">여러 회사의 S/W별 사용법이 달라 새로운 S/W에 적용에 시간이 필요하다.</div>
</div>
</div>
<div class="f9b__pill" data-frame-slot-id="pill_dynamic" data-pill-n="4">
<div class="f9b__pill-label">경제적 부담</div>
<div class="f9b__pill-body">
<div class="text-line">"S/W 구독료만 크게 발생되고, 비용 보전은 안 된다"</div><div class="text-line">사용해야 할 S/W의 종류가 너무 많고 복잡한데 모두 필요한가?</div><div class="text-line">모든 Project에 적용되는 것도 아닌데, 다수의 S/W 구독료를 내야 한다.</div><div class="text-line">디지털전환 하기 위해 이 비용을 쓰는게 정말 경제적인 이득이 있는 거야?</div>
</div>
</div>
<div class="f9b__pill" data-frame-slot-id="pill_dynamic" data-pill-n="5">
<div class="f9b__pill-label">실무 및 적용성</div>
<div class="f9b__pill-body">
<div class="text-line">"실무적 사용에 의한 효율성 증진보다는 홍보, PQ용으로 사용한다"</div><div class="text-line">구체적 적용에 의한 비용, 시간, 품질 등의 효과 사례가 없다.</div><div class="text-line">지형, 선형, 도로, 교량 Model을 만드는 S/W가 모두 달라 적용이 어렵다.</div><div class="text-line">속성정보를 반영하지 않은 형상 위주의 3D 모델 제작에만 초점이 맞춰져 있다.</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="zone" data-zone-position="bottom" data-template-id="process_product_two_way" style="grid-area: bottom;">
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
<style>
.f29b {
width: 100%; height: 100%;
display: flex; flex-direction: column;
gap: 4px;
position: relative;
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
word-break: keep-all;
overflow: hidden;
}
.f29b__title {
font-size: var(--font-zone-title); /* 13px — frame 13 의 f13b__title 과 동일 위계 */
font-weight: 700;
line-height: var(--lh-zone-title);
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
flex-shrink: 0;
padding-left: 4px;
}
/* banners — top */
.f29b__banners {
flex: 0 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4px;
position: relative;
height: 36px;
}
.f29b__banner {
position: relative;
overflow: hidden;
display: flex; align-items: center; justify-content: center;
}
/* PROMOTED background gradients — figma origin lines 84-98 (header-bg--left/right).
원본 SVG 3 개 → CSS gradient 로 재현 (R8/R9 준수). border-radius 9999px = 자동 pill. */
.f29b__banner--left {
background: linear-gradient(to right,
rgba(136, 131, 118, 0.343) 0%,
#39321E 73.1%,
#39321E 100%);
border-radius: 0 9999px 9999px 0;
}
.f29b__banner--right {
background: linear-gradient(to right,
#032118 0%,
rgba(41, 107, 85, 0.1) 100%);
border-radius: 9999px 0 0 9999px;
}
.f29b__banner-text {
position: relative;
z-index: 1;
font-size: var(--font-sub-title);
font-weight: 900;
line-height: 1;
text-shadow: 0 0 2px #322C1E;
-webkit-background-clip: text; background-clip: text;
color: transparent;
padding: 0 8px;
}
/* PROMOTED gradient — lines 101-104 / 110-113 */
.f29b__banner--left .f29b__banner-text {
background-image:
linear-gradient(90deg, rgb(62,53,35) 0%, rgb(62,53,35) 100%),
linear-gradient(180deg, rgb(41,107,85) 0%, rgb(18,51,40) 100%);
}
.f29b__banner--right .f29b__banner-text {
background-image:
linear-gradient(90deg, rgb(34,95,74) 0%, rgb(34,95,74) 100%),
linear-gradient(180deg, rgb(41,107,85) 0%, rgb(18,51,40) 100%);
}
/* body — 6 cell grid (3 rows × 2 cols) — 좌우 row divider Y 정렬 */
/* PROMOTED background — figma origin lines 53-68 (body-bg-left/right).
좌(0~50%): #39321E α0.3 (top) → white α0.3 (bottom)
우(50~100%): #296B55 α0.3 (top) → white α0.3 (bottom)
원본 SVG → CSS multi-bg 로 재현. */
.f29b__body {
flex: 1;
position: relative;
min-height: 0;
padding-top: 4px;
background:
linear-gradient(to bottom, rgba(57,50,30,0.3) 0%, rgba(255,255,255,0.3) 100%) 0% 0% / 50% 100% no-repeat,
linear-gradient(to bottom, rgba(41,107,85,0.3) 0%, rgba(255,255,255,0.3) 100%) 100% 0% / 50% 100% no-repeat;
}
/* 6 cell grid: 3 rows (section 1/2/3), 2 cols (process/product). 각 row 의 height = max(좌, 우) */
.f29b__grid {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-rows: auto;
gap: 6px 10px;
padding: 4px 8px;
height: 100%;
}
.f29b__cell {
overflow: hidden;
min-width: 0;
min-height: 0;
}
/* row 2/3 (3 번째 cell 이후) 위에 dashed divider — 좌우 같은 Y */
.f29b__cell:nth-child(n+3) {
border-top: 1px dashed rgba(0,0,0,0.15);
padding-top: 6px;
margin-top: 4px;
}
/* section-title — 부소목차 (사용자 5-layer 직설 2026-05-07): Analogue 기반... 같은 깊이 0 굵은 bullet */
.f29b__section-title {
font-size: var(--font-sub-title); /* 12px — 부소목차 위계 */
font-weight: 900;
line-height: 1.3;
margin-bottom: 5px;
padding-left: 6px;
border-left: 3px solid currentColor;
}
.f29b__cell--left .f29b__section-title { color: #5C3714; } /* PROMOTED line 125 */
.f29b__cell--right .f29b__section-title { color: #084C56; } /* PROMOTED line 126 */
.f29b__section-title__sub {
font-size: var(--font-caption); /* 10px */
margin-left: 3px;
}
/* f29b 의 본문 = .text-line 공통 contract 사용. bullet color override. */
.f29b__cell .text-line--bullet { color: #000; font-weight: 700; }
/* 2026-05-14 — line-line gap 만 1/2 압축 (사용자 lock 정확 의도) :
line-height 1.6 (공통 contract) 유지. .text-line + .text-line margin 4px → 2px. */
.f29b__cell .text-line + .text-line { margin-top: 2px; }
/* popup link — 각 column 끝, 파란색 글씨 (사용자 lock 2026-05-14). */
.f29b__popup-link {
margin-top: 2px;
font-size: var(--font-caption);
font-weight: 600;
color: #1a73e8;
cursor: pointer;
text-decoration: underline;
}
.f29b__popup-link::before { content: "▶ "; font-size: 0.85em; }
/* AS-IS/TO-BE 좌우 + arrow (PROMOTED 구조) */
.f29b__transform {
display: grid;
grid-template-columns: 1fr auto 1fr;
gap: 4px;
align-items: start;
}
.f29b__transform__list {
/* .text-line 공통 contract 그대로. wrapper 만 grid 안의 cell 역할 */
}
.f29b__transform__arrow {
align-self: center;
width: 28px;
flex-shrink: 0;
}
.f29b__transform__arrow img {
width: 100%;
height: auto;
display: block;
}
.f29b__footnote {
font-size: var(--font-caption); /* 10px */
line-height: var(--lh-caption);
color: #333;
padding-left: 14px;
margin-top: 1px;
white-space: pre-wrap;
}
.f29b__aster-small { font-size: 9px; }
</style>
<div class="f29b" data-frame-id="1171281210" data-template-id="process_product_two_way">
<div class="f29b__title">2. DX 추진의 실태</div>
<div class="f29b__banners">
<div class="f29b__banner f29b__banner--left">
<div class="f29b__banner-text">정책 및 발주 체계</div>
</div>
<div class="f29b__banner f29b__banner--right">
<div class="f29b__banner-text">조직 및 수행 역량</div>
</div>
</div>
<div class="f29b__body">
<div class="f29b__grid">
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">실질적 기술 경쟁을 저해하는 정책 집행</div>
<div class="text-line text-line--bullet">모든 설계사가 수행 능력을 갖추었다는 전제하에 정책 시행</div><div class="text-line text-line--bullet">수행 능력이 없는 업체 선정 후 성과품의 수준을 낮추어 시행</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">공학적 개념 정립 부재</div>
<div class="text-line text-line--bullet">DX와 BIM의 차이점을 명확히 구분하지 못하고 접근 방식과 기술적 도구 사이의 혼란만 가중</div><div class="text-line text-line--bullet">단순히 기술적 도구의 사용에 초점을 맞추느라 3D모델 제작 S/W에 과도하게 의존</div>
</div>
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">적용 효과가 있는 사례도 없이 방침부터 도입</div>
<div class="text-line text-line--bullet">DX/BIM 적용에 따른 실무적 이득이 있다고 판단된 사례 부족</div><div class="text-line text-line--bullet">BIM 지침/방침 등을 시행 경험과 효과 검증도 없이 남발</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">‘본업 기술력 확보’ 우선의 개념 부재</div>
<div class="text-line text-line--bullet">고도의 전문지식과 현장 경험이 축적된 Manual의 중요성과 필요성에 대한 이해 부족</div><div class="text-line text-line--bullet">국가·발주처의 지침·방침에만 의존한 업체의 기술력</div>
</div>
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">엔지니어링 S/W에 대한 개념 부재</div>
<div class="text-line text-line--bullet">다양한 엔지니어링 S/W의 특성에 대한 깊은 이해 없이 범용 S/W 선택</div><div class="text-line text-line--bullet">대형 Global S/W 회사에 과도한 의존과 이에 예속되는 방침 남발로 전용 S/W 소멸</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">DX/BIM의 근본 취지와 목표의 이해 부족</div>
<div class="text-line text-line--bullet">DX에 의한 과정의 혁신과 결과물의 변화에 대한 고민 부재</div><div class="text-line text-line--bullet">기술자가 직접 3D모델을 만들고 수정하며 설계를 수행하지 않고, 별도로 외주 처리하여 본질 회피</div>
</div>
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
<div class="f29b__section-title">기술투자(R&D) 없는 성과 창출 기대</div>
<div class="text-line text-line--bullet">단순 BIM S/W만 구입하면 될 것이라는 안일한 생각</div><div class="text-line text-line--bullet">실질적 기술 개발 투자 노력 없이 남들이 하는 대로 하면 된다는 착각</div>
</div>
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
<div class="f29b__section-title">과거의 타성에 머무르고 있는 기술자 집단</div>
<div class="text-line text-line--bullet">설계/감리/시공 임직원들의 Digital 무지와 전략적 무지</div><div class="text-line text-line--bullet">교육과 학습을 통한 인재 양성보다 당장 실무 활용이 가능한 타사 인력 빼오기에 집중</div>
</div>
</div>
<div class="f29b__popups" style="display: grid; grid-template-columns: 1fr 1fr; gap: 6px 10px; padding: 0 8px;">
<div>
<div class="f29b__popup-link">발주처 반응</div>
</div>
<div>
<div class="f29b__popup-link">설계·시공업계 반응</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="slide-footer">
<div class="slide-footer-text">검증 없는 정책의 일방적 추진과 조직의 회피, 이해 부족은 DX 지연을 반복시키고 있다.</div>
</div>
</div>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

@@ -0,0 +1,89 @@
---
title: DX 지연 요인
sidebar:
order: 03
---
## 1. DX에 대한 인식
- **기술 및 소프트웨어 이해도**
- "무슨 말인지 잘 모르겠다, 어디까지 어떻게 해야 하는지 모르겠다"
- 기본지침, 시행지침 등 새롭게 알아야 할 게 너무 많다.
- 3D 모델과 별 차이점을 모르겠다. S/W마다 사용법이 다르다.
- 필요한 것은 쉽고 간단한 건데, 왜 이렇게 복잡하게 만들까?
- **효과와 효율성**
- "2D 설계 후 전환설계를 수행하는데 효과는 모르겠고, 효율은 낮다"
- 성과품 작성은 기존과 같게 하고, 추가 업무만 발생해 효율이 낮다.
- BIM으로 인해 가중되는 업무 대비 효과가 거의 없어 보인다.
- 결과적으로 큰 차이를 못 느끼겠고, 이런 노력이 정말 가치 있는 일이야?
- **인력 및 교육**
- "수행 인력이 부족하고, 기존 직원들은 어떻게 교육해야 하나"
- 교육시간 손실로 일손이 더 필요해지고, 적응하는데도 시간이 걸린다.
- 신입사원은 없고 BIM 수행을 할 수 있는 기술자가 부족하다.
- 여러 회사의 S/W별 사용법이 달라 새로운 S/W에 적용에 시간이 필요하다.
- **경제적 부담**
- "S/W 구독료만 크게 발생되고, 비용 보전은 안 된다"
- 사용해야 할 S/W의 종류가 너무 많고 복잡한데 모두 필요한가?
- 모든 Project에 적용되는 것도 아닌데, 다수의 S/W 구독료를 내야 한다.
- 디지털전환 하기 위해 이 비용을 쓰는게 정말 경제적인 이득이 있는 거야?
- **실무 및 적용성**
- "실무적 사용에 의한 효율성 증진보다는 홍보, PQ용으로 사용한다"
- 구체적 적용에 의한 비용, 시간, 품질 등의 효과 사례가 없다.
- 지형, 선형, 도로, 교량 Model을 만드는 S/W가 모두 달라 적용이 어렵다.
- 속성정보를 반영하지 않은 형상 위주의 3D 모델 제작에만 초점이 맞춰져 있다.
<br/>
---
<br/>
## 2. DX 추진의 실태
<br/>
### 2.1 정책 및 발주 체계
- **실질적 기술 경쟁을 저해하는 정책 집행**
- 모든 설계사가 수행 능력을 갖추었다는 전제하에 정책 시행
- 수행 능력이 없는 업체 선정 후 성과품의 수준을 낮추어 시행
<br/>
- **적용 효과가 있는 사례도 없이 방침부터 도입**
- DX/BIM 적용에 따른 실무적 이득이 있다고 판단된 사례 부족
- BIM 지침/방침 등을 시행 경험과 효과 검증도 없이 남발
<br/>
- **엔지니어링 S/W에 대한 개념 부재**
- 다양한 엔지니어링 S/W의 특성에 대한 깊은 이해 없이 범용 S/W 선택
- 대형 Global S/W 회사에 과도한 의존과 이에 예속되는 방침 남발로 전용 S/W 소멸
<br/>
- **기술투자(R&D) 없는 성과 창출 기대**
- 단순 BIM S/W만 구입하면 될 것이라는 안일한 생각
- 실질적 기술 개발 투자 노력 없이 남들이 하는 대로 하면 된다는 착각
<br/>
<details>
<summary style={{cursor: 'pointer', fontWeight: 'bold', color: '#555'}}>발주처 반응</summary>
<img src="/assets/images/발주처반응.png" />
</details>
### 2.2 조직 및 수행 역량
- **공학적 개념 정립 부재**
- DX와 BIM의 차이점을 명확히 구분하지 못하고 접근 방식과 기술적 도구 사이의 혼란만 가중
- 단순히 기술적 도구의 사용에 초점을 맞추느라 3D모델 제작 S/W에 과도하게 의존
<br/>
- **‘본업 기술력 확보’ 우선의 개념 부재**
- 고도의 전문지식과 현장 경험이 축적된 Manual의 중요성과 필요성에 대한 이해 부족
- 국가·발주처의 지침·방침에만 의존한 업체의 기술력
<br/>
- **DX/BIM의 근본 취지와 목표의 이해 부족**
- DX에 의한 과정의 혁신과 결과물의 변화에 대한 고민 부재
- 기술자가 직접 3D모델을 만들고 수정하며 설계를 수행하지 않고, 별도로 외주 처리하여 본질 회피
<br/>
- **과거의 타성에 머무르고 있는 기술자 집단**
- 설계/감리/시공 임직원들의 Digital 무지와 전략적 무지
- 교육과 학습을 통한 인재 양성보다 당장 실무 활용이 가능한 타사 인력 빼오기에 집중
<br/>
<details>
<summary style={{cursor: 'pointer', fontWeight: 'bold', color: '#555'}}>설계·시공업계 반응</summary>
<img src="/assets/images/설계시공업계반응.png" />
</details>
<br/>
---
:::note[핵심 요약]
* 검증 없는 정책의 일방적 추진과 조직의 회피, 이해 부족은 DX 지연을 반복시키고 있다.
:::
@@ -0,0 +1,21 @@
{
"step_num": 1,
"step_name": "mdx_upload",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"samples\\mdx\\04. DX 지연 요인.mdx"
],
"output": [
"step01_mdx_upload.json",
"step01_mdx_source.md"
],
"note": "MDX 원본 그대로 step01_mdx_source.md 에 복사.",
"data": {
"mdx_path": "samples\\mdx\\04. DX 지연 요인.mdx",
"run_id": "mdx04_b3_v12",
"run_dir": "d:\\ad-hoc\\kei\\design_agent\\data\\runs\\mdx04_b3_v12\\phase_z2",
"mdx_source_size_bytes": 4710,
"mdx_source_lines": 89
}
}
@@ -0,0 +1,51 @@
{
"step_num": 2,
"step_name": "normalized",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step01_mdx_source.md"
],
"output": [
"step02_normalized.json"
],
"note": "parse_mdx 결과: title / sections / footer 분리 + raw_content 보존. heading tree 미생성, orphan / details 감지 미완 (Step 2 ⚠ partial — 별 axis). orphans / details 필드는 schema lock — 빈 배열이라도 'detection 미수행' marker. stage0_adapter_diagnostics = IMP-02 chained adapter trace (default OFF canary). stage0_normalized_assets = IMP-03 Step 3 slide-level handoff (popups/images/tables list).",
"data": {
"slide_title": "DX 지연 요인",
"slide_footer": "검증 없는 정책의 일방적 추진과 조직의 회피, 이해 부족은 DX 지연을 반복시키고 있다.",
"sections_count": 2,
"sections": [
{
"section_id": "04-1",
"section_num": 1,
"title": "1. DX에 대한 인식",
"raw_content_length": 934,
"raw_content": "- **기술 및 소프트웨어 이해도**\n - \"무슨 말인지 잘 모르겠다, 어디까지 어떻게 해야 하는지 모르겠다\"\n - 기본지침, 시행지침 등 새롭게 알아야 할 게 너무 많다.\n - 3D 모델과 별 차이점을 모르겠다. S/W마다 사용법이 다르다.\n - 필요한 것은 쉽고 간단한 건데, 왜 이렇게 복잡하게 만들까?\n- **효과와 효율성**\n - \"2D 설계 후 전환설계를 수행하는데 효과는 모르겠고, 효율은 낮다\"\n - 성과품 작성은 기존과 같게 하고, 추가 업무만 발생해 효율이 낮다.\n - BIM으로 인해 가중되는 업무 대비 효과가 거의 없어 보인다.\n - 결과적으로 큰 차이를 못 느끼겠고, 이런 노력이 정말 가치 있는 일이야?\n- **인력 및 교육**\n - \"수행 인력이 부족하고, 기존 직원들은 어떻게 교육해야 하나\"\n - 교육시간 손실로 일손이 더 필요해지고, 적응하는데도 시간이 걸린다.\n - 신입사원은 없고 BIM 수행을 할 수 있는 기술자가 부족하다.\n - 여러 회사의 S/W별 사용법이 달라 새로운 S/W에 적용에 시간이 필요하다.\n- **경제적 부담**\n - \"S/W 구독료만 크게 발생되고, 비용 보전은 안 된다\"\n - 사용해야 할 S/W의 종류가 너무 많고 복잡한데 모두 필요한가?\n - 모든 Project에 적용되는 것도 아닌데, 다수의 S/W 구독료를 내야 한다.\n - 디지털전환 하기 위해 이 비용을 쓰는게 정말 경제적인 이득이 있는 거야?\n- **실무 및 적용성**\n - \"실무적 사용에 의한 효율성 증진보다는 홍보, PQ용으로 사용한다\"\n - 구체적 적용에 의한 비용, 시간, 품질 등의 효과 사례가 없다.\n - 지형, 선형, 도로, 교량 Model을 만드는 S/W가 모두 달라 적용이 어렵다.\n - 속성정보를 반영하지 않은 형상 위주의 3D 모델 제작에만 초점이 맞춰져 있다.\n<br/>\n---\n<br/>"
},
{
"section_id": "04-2",
"section_num": 2,
"title": "2. DX 추진의 실태",
"raw_content_length": 1349,
"raw_content": "<br/>\n\n### 2.1 정책 및 발주 체계\n- **실질적 기술 경쟁을 저해하는 정책 집행** \n - 모든 설계사가 수행 능력을 갖추었다는 전제하에 정책 시행\n - 수행 능력이 없는 업체 선정 후 성과품의 수준을 낮추어 시행 \n<br/>\n- **적용 효과가 있는 사례도 없이 방침부터 도입** \n - DX/BIM 적용에 따른 실무적 이득이 있다고 판단된 사례 부족\n - BIM 지침/방침 등을 시행 경험과 효과 검증도 없이 남발\n<br/>\n- **엔지니어링 S/W에 대한 개념 부재** \n - 다양한 엔지니어링 S/W의 특성에 대한 깊은 이해 없이 범용 S/W 선택\n - 대형 Global S/W 회사에 과도한 의존과 이에 예속되는 방침 남발로 전용 S/W 소멸\n<br/>\n- **기술투자(R&D) 없는 성과 창출 기대** \n - 단순 BIM S/W만 구입하면 될 것이라는 안일한 생각\n - 실질적 기술 개발 투자 노력 없이 남들이 하는 대로 하면 된다는 착각\n<br/>\n<details>\n <summary style={{cursor: 'pointer', fontWeight: 'bold', color: '#555'}}>발주처 반응</summary>\n <img src=\"/assets/images/발주처반응.png\" />\n</details>\n\n### 2.2 조직 및 수행 역량\n- **공학적 개념 정립 부재** \n - DX와 BIM의 차이점을 명확히 구분하지 못하고 접근 방식과 기술적 도구 사이의 혼란만 가중\n - 단순히 기술적 도구의 사용에 초점을 맞추느라 3D모델 제작 S/W에 과도하게 의존\n<br/>\n- **‘본업 기술력 확보’ 우선의 개념 부재** \n - 고도의 전문지식과 현장 경험이 축적된 Manual의 중요성과 필요성에 대한 이해 부족\n - 국가·발주처의 지침·방침에만 의존한 업체의 기술력 \n<br/>\n- **DX/BIM의 근본 취지와 목표의 이해 부족** \n - DX에 의한 과정의 혁신과 결과물의 변화에 대한 고민 부재\n - 기술자가 직접 3D모델을 만들고 수정하며 설계를 수행하지 않고, 별도로 외주 처리하여 본질 회피\n<br/>\n- **과거의 타성에 머무르고 있는 기술자 집단** \n - 설계/감리/시공 임직원들의 Digital 무지와 전략적 무지\n - 교육과 학습을 통한 인재 양성보다 당장 실무 활용이 가능한 타사 인력 빼오기에 집중\n<br/>\n<details>\n <summary style={{cursor: 'pointer', fontWeight: 'bold', color: '#555'}}>설계·시공업계 반응</summary>\n <img src=\"/assets/images/설계시공업계반응.png\" />\n</details>\n<br/>\n---"
}
],
"orphans": [],
"details": [],
"stage0_adapter_diagnostics": {
"enabled": false,
"used": false,
"fallback_reason": null,
"id_reconstruction_log": [],
"adapter_counts": null,
"legacy_counts": {
"sections": 2
}
},
"stage0_normalized_assets": {
"popups": [],
"images": [],
"tables": []
}
}
}
@@ -0,0 +1,41 @@
{
"step_num": 5,
"step_name": "v4_evidence",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step02_normalized.json",
"tests/matching/v4_full32_result.yaml"
],
"output": [
"step05_v4_evidence.json"
],
"note": "V4 non-reject max-6 후보 list (Step 9 application_plan input). raw 32 entry 는 tests/matching/v4_full32_result.yaml 에 영속. candidate_status='ok' = 후보 1개 이상 / 'no_non_reject_v4_candidate' = 0개 (Step 9 fallback path 입력). Step 6 plan_composition() 은 lookup_v4_match() (rank-1) 그대로 사용 — backward compat (Step 6-A axis 까지).",
"data": {
"v4_source": "tests\\matching\\v4_full32_result.yaml",
"aligned_section_ids": [
"04-1",
"04-2"
],
"evidence_per_section": [
{
"section_id": "04-1",
"v4_candidates": [],
"candidate_status": "no_non_reject_v4_candidate"
},
{
"section_id": "04-2",
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.7711,
"label": "light_edit"
}
],
"candidate_status": "ok"
}
]
}
}
@@ -0,0 +1,170 @@
{
"step_num": 6,
"step_name": "composition_plan",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step02_normalized.json",
"step05_v4_evidence.json"
],
"output": [
"step06_composition_plan.json"
],
"note": "composition v0 count-based — sections → candidates → score → greedy select. Step 6-A (사용자 lock 2026-05-08): selected_units[i].v4_candidates 추가 (non-reject max-6 후보 list, candidates[0] = 단일 frame_* 와 일관). logic 무변 — runtime 결과 동일. Step 9 application_plan input.",
"data": {
"selected_units_count": 2,
"layout_preset_decided": "horizontal-2",
"candidates_summary": [
{
"source_section_ids": [
"04-1"
],
"merge_type": "single",
"template_id": "pre_construction_model_info_stacked",
"label": "reject",
"phase_z_status": "fallback_candidate",
"v4_rank": 1,
"selection_path": "rank_1",
"fallback_reason": null,
"score": 0.0,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 5,
"source_shape": "top_bullets",
"capacity": {
"strict": null,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
},
{
"source_section_ids": [
"04-2"
],
"merge_type": "single",
"template_id": "process_product_two_way",
"label": "light_edit",
"phase_z_status": "adapt_matched_zone",
"v4_rank": 2,
"selection_path": "rank_2_fallback",
"fallback_reason": "capacity_mismatch:strict_mismatch",
"score": 0.53977,
"selection_state": "selected",
"auto_selectable": true,
"filter_reasons": [],
"notes": [],
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"candidates_total": 2,
"candidates_viable_auto": 2,
"selected_units": [
{
"source_section_ids": [
"04-1"
],
"merge_type": "single",
"frame_id": "1171281180",
"frame_number": 9,
"frame_template_id": "pre_construction_model_info_stacked",
"label": "reject",
"v4_rank": 1,
"selection_path": "rank_1",
"fallback_reason": null,
"score": 0.0,
"phase_z_status": "fallback_candidate",
"rationale": {
"capacity_fit": {
"item_count": 5,
"source_shape": "top_bullets",
"capacity": {
"strict": null,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.0,
"confidence": 0.7223,
"label": "reject",
"label_weight": 0.0,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"notes": [],
"v4_candidates": []
},
{
"source_section_ids": [
"04-2"
],
"merge_type": "single",
"frame_id": "1171281210",
"frame_number": 29,
"frame_template_id": "process_product_two_way",
"label": "light_edit",
"v4_rank": 2,
"selection_path": "rank_2_fallback",
"fallback_reason": "capacity_mismatch:strict_mismatch",
"score": 0.53977,
"phase_z_status": "adapt_matched_zone",
"rationale": {
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
},
"frame_compat": 0.5398,
"confidence": 0.7711,
"label": "light_edit",
"label_weight": 0.7,
"merge_type": "single",
"hierarchy_coherence": null,
"density_score": null
},
"notes": [],
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.7711,
"label": "light_edit"
}
]
}
]
}
}
@@ -0,0 +1,81 @@
{
"step_num": 7,
"step_name": "layout",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step06_composition_plan.json"
],
"output": [
"step07_layout.json",
"step07_selected_layout.html"
],
"note": "count-based v0 — 들여쓰기 / 정렬 미세 layout 미구현 (Step 7 ⚠ partial). Step 7-conn (사용자 lock 2026-05-08): unit_count → layout_candidates list (select_layout_candidates) artifact 기록. default 결정 자체는 무변 — candidates[0] 가 default (default_selection: true), 나머지는 alternative. Step 9 application_plan input.",
"data": {
"layout_preset": "horizontal-2",
"layout_css": {
"areas": "\"top\" \"bottom\"",
"cols": "1fr",
"rows": "211px 360px",
"heights_px": [
211,
360
],
"ratios": [
0.361,
0.615
],
"computation": "min_height_first + content_weight_distribution",
"dynamic_rows": true,
"raw_zone_layout": {
"computation": "min_height_first + content_weight_distribution",
"slide_body_height": 585,
"gap": 14,
"available_after_gap": 571,
"min_heights_px": [
200,
345
],
"min_scaled": false,
"total_min_height": 545,
"remaining_after_min": 26,
"content_weights": [
{
"position": "top",
"template_id": "pre_construction_model_info_stacked",
"score": 6.168
},
{
"position": "bottom",
"template_id": "process_product_two_way",
"score": 8.486
}
],
"weight_shares": [
0.421,
0.579
],
"extras_px": [
11,
15
],
"heights_px": [
211,
360
],
"ratios": [
0.361,
0.615
]
}
},
"zones_count": 2,
"unit_count": 2,
"layout_candidates": [
"horizontal-2",
"vertical-2"
],
"layout_override_applied": false,
"auto_layout_preset": "horizontal-2"
}
}
@@ -0,0 +1,104 @@
{
"step_num": 8,
"step_name": "zone_region_ratios",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step07_layout.json",
"step10_frame_contract.json"
],
"output": [
"step08_zone_region_ratios.json",
"step08_zone_content_placement.html"
],
"note": "계획값 only. 실측값은 Step 14 (visual_check). zone-level 만 dynamic, region-level (sub_zone 안 sections) 은 균등 분배 (1/1/1). F29 처럼 비균등 콘텐츠 (transform_table + plain) 는 첫 cell 부족 가능 — Step 8 ⚠ partial. Step 8-conn (사용자 lock 2026-05-08): per_zone_plan[i] 에 region_layout_candidates + display_strategy_candidates 추가 (passive 기록). placeholder signals = text-only / region_count=1 (Step 3/4 부재 종속). 실제 content_object 신호 활성화는 별 axis. Step 9 application_plan input.",
"data": {
"zone_heights_px_planned": [
211,
360
],
"zone_ratios_planned": [
0.361,
0.615
],
"per_zone_plan": [
{
"position": "top",
"zone_height_px_planned": 211,
"zone_ratio_planned": 0.361,
"min_height_px": 200,
"frame_cardinality_strict": null,
"sub_zones_planned": [
{
"id": "pill_dynamic",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": null,
"partial_target_path": ".f9b__pill-rows .f9b__pill:nth-child(N)"
}
],
"child_distribution_note": "현재 child zone (sub_zones 안 sections) 균등 분배 — Step 8 region-level ratio ⚠ partial.",
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
]
},
{
"position": "bottom",
"zone_height_px_planned": 360,
"zone_ratio_planned": 0.615,
"min_height_px": 345,
"frame_cardinality_strict": 2,
"sub_zones_planned": [
{
"id": "process_column",
"role": "main_text",
"accepts": [
"text_block",
"transform_table"
],
"cardinality_strict": null,
"partial_target_path": ".f29b__grid .f29b__cell--left"
},
{
"id": "product_column",
"role": "main_text",
"accepts": [
"text_block"
],
"cardinality_strict": null,
"partial_target_path": ".f29b__grid .f29b__cell--right"
}
],
"child_distribution_note": "현재 child zone (sub_zones 안 sections) 균등 분배 — Step 8 region-level ratio ⚠ partial.",
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
]
}
],
"step8_conn_placeholder_signals": {
"region_count": 1,
"content_type": "text_block",
"flow_type": null,
"role_pattern": null,
"ratio_asymmetric": false,
"has_visual_element": false,
"details_presence": false,
"large_table": false,
"long_text": false,
"fits_in_region": null,
"_note": "Step 3/4 부재 종속 placeholder — 모든 zone 을 text-only / region_count=1 로 가정. 실제 content_object 신호 활성화는 별 axis."
}
}
}
@@ -0,0 +1,893 @@
{
"step_num": 9,
"step_name": "application_plan",
"step_status": "partial",
"pipeline_path_connected": true,
"input": [
"step05_v4_evidence.json",
"step06_composition_plan.json",
"step07_layout.json",
"step08_zone_region_ratios.json"
],
"output": [
"step09_application_plan.json",
"step09_application_plan.html"
],
"note": "Step 9 v0 passive application_plan trace (사용자 lock 2026-05-08). V4 후보 + layout / region / display 후보 + V4 label → application_mode 변환을 side-by-side 로 기록. v0 invariant 5 가지 (status.md §4) 만족. Step 6 의 default 결정 그대로 (current_default_candidate). auto decision 은 Step 9 v1 (별 axis). region/display 후보는 Step 8-conn 의 placeholder signal 종속 (Step 3/4 부재). Step 7-A axis (2026-05-08): frame_overrides_applied 가 사용자 LayoutPanel/FramePanel 선택값을 강제 적용한 trace.",
"data": {
"units": [
{
"unit_id": "04-1",
"layout_preset": "horizontal-2",
"layout_candidates": [
"horizontal-2",
"vertical-2"
],
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
],
"candidate_status": "no_non_reject_v4_candidate",
"application_status": "no_v4_candidate",
"current_default_candidate": null,
"selected_v4_rank": 1,
"selection_path": "rank_1",
"fallback_used": false,
"fallback_reason": null,
"candidate_evidence": [
{
"rank": 1,
"template_id": "pre_construction_model_info_stacked",
"frame_id": "1171281180",
"frame_number": 9,
"confidence": 0.7223,
"label": "reject",
"v4_label": "reject",
"phase_z_status": "fallback_candidate",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "design_reference_only",
"decision": "selected",
"reason": "primary_selected",
"capacity_fit": {
"item_count": 5,
"source_shape": "top_bullets",
"capacity": {
"strict": null,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"fallback_chain": [
{
"rank": 1,
"template_id": "pre_construction_model_info_stacked",
"frame_id": "1171281180",
"frame_number": 9,
"confidence": 0.7223,
"label": "reject",
"v4_label": "reject",
"phase_z_status": "fallback_candidate",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "design_reference_only",
"decision": "selected",
"reason": "primary_selected",
"capacity_fit": {
"item_count": 5,
"source_shape": "top_bullets",
"capacity": {
"strict": null,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"v4_candidates": [],
"v4_all_judgments": [
{
"template_id": "pre_construction_model_info_stacked",
"frame_id": "1171281180",
"frame_number": 9,
"v4_rank": 1,
"confidence": 0.7223,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "field_effectiveness_five_elements",
"frame_id": "1171281181",
"frame_number": 10,
"v4_rank": 2,
"confidence": 0.6586,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "policy_achievement_five_goals",
"frame_id": "1171281213",
"frame_number": 32,
"v4_rank": 3,
"confidence": 0.6514,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "compensation_complaint_side_card",
"frame_id": "1171281176",
"frame_number": 5,
"v4_rank": 4,
"confidence": 0.6058,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "solution_engn_split_diagram",
"frame_id": "1171281201",
"frame_number": 21,
"v4_rank": 5,
"confidence": 0.4773,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "model_specialized_engn_sw",
"frame_id": "1171281202",
"frame_number": 22,
"v4_rank": 6,
"confidence": 0.4624,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "commercial_sw_four_categories",
"frame_id": "1171281205",
"frame_number": 25,
"v4_rank": 7,
"confidence": 0.4293,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "construction_bim_three_usage",
"frame_id": "1171281182",
"frame_number": 11,
"v4_rank": 8,
"confidence": 0.4234,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "sw_dependency_four_problems",
"frame_id": "1171281206",
"frame_number": 26,
"v4_rank": 9,
"confidence": 0.3986,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "engn_sw_development_domain_knowledge",
"frame_id": "1171281173",
"frame_number": 2,
"v4_rank": 10,
"confidence": 0.3942,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "sw_development_cycle_six_nodes",
"frame_id": "1171281172",
"frame_number": 1,
"v4_rank": 11,
"confidence": 0.3899,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "policy_goals_plus_execution_requirements",
"frame_id": "1171281192",
"frame_number": 15,
"v4_rank": 12,
"confidence": 0.3833,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "bim_current_problems_paired",
"frame_id": "1171281194",
"frame_number": 17,
"v4_rank": 13,
"confidence": 0.3773,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "overseas_bim_numbered_list",
"frame_id": "1171281174",
"frame_number": 3,
"v4_rank": 14,
"confidence": 0.3748,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"frame_number": 13,
"v4_rank": 15,
"confidence": 0.3713,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "bim_issues_quadrant_four",
"frame_id": "1171281193",
"frame_number": 16,
"v4_rank": 16,
"confidence": 0.3699,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"frame_number": 20,
"v4_rank": 17,
"confidence": 0.3158,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "domestic_bim_actor_relations",
"frame_id": "1171281175",
"frame_number": 4,
"v4_rank": 18,
"confidence": 0.2897,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "bigroom_system_components",
"frame_id": "1171281178",
"frame_number": 7,
"v4_rank": 19,
"confidence": 0.2742,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "info_management_what_how_when",
"frame_id": "1171281179",
"frame_number": 8,
"v4_rank": 20,
"confidence": 0.2604,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"v4_rank": 21,
"confidence": 0.2313,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "compensation_complaint_map",
"frame_id": "1171281177",
"frame_number": 6,
"v4_rank": 22,
"confidence": 0.201,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "sw_reality_three_emphasis",
"frame_id": "1171281209",
"frame_number": 28,
"v4_rank": 23,
"confidence": 0.201,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "bim_dx_comparison_table",
"frame_id": "1171281195",
"frame_number": 18,
"v4_rank": 24,
"confidence": 0.1798,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "three_persona_benefits",
"frame_id": "1171281191",
"frame_number": 14,
"v4_rank": 25,
"confidence": 0.1787,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "construction_goals_three_circle_intersection",
"frame_id": "1171281189",
"frame_number": 12,
"v4_rank": 26,
"confidence": 0.1706,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"frame_number": 27,
"v4_rank": 27,
"confidence": 0.1399,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "engn_sw_three_types",
"frame_id": "1171281204",
"frame_number": 24,
"v4_rank": 28,
"confidence": 0.0929,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "design_method_distortion_three_col",
"frame_id": "1171281197",
"frame_number": 19,
"v4_rank": 29,
"confidence": 0.0584,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "app_sw_package_vs_solution",
"frame_id": "1171281203",
"frame_number": 23,
"v4_rank": 30,
"confidence": 0.0052,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "industry_current_status_three_col",
"frame_id": "1171281211",
"frame_number": 30,
"v4_rank": 31,
"confidence": 0.0044,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "industry_characteristics_three_col",
"frame_id": "1171281212",
"frame_number": 31,
"v4_rank": 32,
"confidence": 0.0029,
"label": "reject",
"catalog_registered": false
}
],
"application_candidates": [],
"position": null,
"assignment_source": null,
"section_assignment_override": false,
"replaced_auto_unit": null,
"skipped_collided_auto_units": [],
"skipped_reason": null
},
{
"unit_id": "04-2",
"layout_preset": "horizontal-2",
"layout_candidates": [
"horizontal-2",
"vertical-2"
],
"region_layout_candidates": [
"region-single"
],
"display_strategy_candidates": [
"inline_full",
"inline_preview_with_details",
"details_only"
],
"candidate_status": "ok",
"application_status": "ok",
"current_default_candidate": "process_product_two_way",
"selected_v4_rank": 2,
"selection_path": "rank_2_fallback",
"fallback_used": true,
"fallback_reason": "capacity_mismatch:strict_mismatch",
"candidate_evidence": [
{
"rank": 1,
"template_id": "bim_dx_comparison_table",
"frame_id": "1171281195",
"frame_number": 18,
"confidence": 0.8152,
"label": "reject",
"v4_label": "reject",
"phase_z_status": "fallback_candidate",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "design_reference_only",
"decision": "skipped",
"reason": "capacity_mismatch:strict_mismatch",
"capacity_fit": {
"item_count": 8,
"source_shape": "top_bullets",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "strict_mismatch",
"mismatch_reason": "strict cardinality 2, content has 8 items. mapper 가 FitError 를 raise 할 것."
}
},
{
"rank": 2,
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.7711,
"label": "light_edit",
"v4_label": "light_edit",
"phase_z_status": "adapt_matched_zone",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "deterministic_minor_adjustment",
"decision": "selected",
"reason": "fallback_selected",
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"fallback_chain": [
{
"rank": 1,
"template_id": "bim_dx_comparison_table",
"frame_id": "1171281195",
"frame_number": 18,
"confidence": 0.8152,
"label": "reject",
"v4_label": "reject",
"phase_z_status": "fallback_candidate",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "design_reference_only",
"decision": "skipped",
"reason": "capacity_mismatch:strict_mismatch",
"capacity_fit": {
"item_count": 8,
"source_shape": "top_bullets",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "strict_mismatch",
"mismatch_reason": "strict cardinality 2, content has 8 items. mapper 가 FitError 를 raise 할 것."
}
},
{
"rank": 2,
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"confidence": 0.7711,
"label": "light_edit",
"v4_label": "light_edit",
"phase_z_status": "adapt_matched_zone",
"catalog_registered": true,
"filtered_for_direct_execution": false,
"route_hint": "deterministic_minor_adjustment",
"decision": "selected",
"reason": "fallback_selected",
"capacity_fit": {
"item_count": 2,
"source_shape": "h3_subsections",
"capacity": {
"strict": 2,
"min": null,
"max": null,
"truncate_at": null,
"pad_to": null
},
"fit_status": "ok",
"mismatch_reason": null
}
}
],
"v4_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"v4_rank": 2,
"confidence": 0.7711,
"label": "light_edit"
}
],
"v4_all_judgments": [
{
"template_id": "bim_dx_comparison_table",
"frame_id": "1171281195",
"frame_number": 18,
"v4_rank": 1,
"confidence": 0.8152,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"frame_number": 29,
"v4_rank": 2,
"confidence": 0.7711,
"label": "light_edit",
"catalog_registered": true
},
{
"template_id": "app_sw_package_vs_solution",
"frame_id": "1171281203",
"frame_number": 23,
"v4_rank": 3,
"confidence": 0.6389,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "engn_sw_three_types",
"frame_id": "1171281204",
"frame_number": 24,
"v4_rank": 4,
"confidence": 0.6372,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "industry_characteristics_three_col",
"frame_id": "1171281212",
"frame_number": 31,
"v4_rank": 5,
"confidence": 0.5996,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "bim_adoption_central_split",
"frame_id": "1171281208",
"frame_number": 27,
"v4_rank": 6,
"confidence": 0.55,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "bigroom_system_components",
"frame_id": "1171281178",
"frame_number": 7,
"v4_rank": 7,
"confidence": 0.5172,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "industry_current_status_three_col",
"frame_id": "1171281211",
"frame_number": 30,
"v4_rank": 8,
"confidence": 0.4774,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "design_method_distortion_three_col",
"frame_id": "1171281197",
"frame_number": 19,
"v4_rank": 9,
"confidence": 0.4179,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "sw_dependency_four_problems",
"frame_id": "1171281206",
"frame_number": 26,
"v4_rank": 10,
"confidence": 0.4138,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "bim_current_problems_paired",
"frame_id": "1171281194",
"frame_number": 17,
"v4_rank": 11,
"confidence": 0.3559,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "domestic_bim_actor_relations",
"frame_id": "1171281175",
"frame_number": 4,
"v4_rank": 12,
"confidence": 0.3457,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "pre_construction_model_info_stacked",
"frame_id": "1171281180",
"frame_number": 9,
"v4_rank": 13,
"confidence": 0.332,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "model_specialized_engn_sw",
"frame_id": "1171281202",
"frame_number": 22,
"v4_rank": 14,
"confidence": 0.3275,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "commercial_sw_four_categories",
"frame_id": "1171281205",
"frame_number": 25,
"v4_rank": 15,
"confidence": 0.3074,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "policy_goals_plus_execution_requirements",
"frame_id": "1171281192",
"frame_number": 15,
"v4_rank": 16,
"confidence": 0.2847,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "construction_goals_three_circle_intersection",
"frame_id": "1171281189",
"frame_number": 12,
"v4_rank": 17,
"confidence": 0.2558,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "bim_issues_quadrant_four",
"frame_id": "1171281193",
"frame_number": 16,
"v4_rank": 18,
"confidence": 0.2302,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "compensation_complaint_map",
"frame_id": "1171281177",
"frame_number": 6,
"v4_rank": 19,
"confidence": 0.2077,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "dx_sw_necessity_three_perspectives",
"frame_id": "1171281198",
"frame_number": 20,
"v4_rank": 20,
"confidence": 0.1842,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "three_parallel_requirements",
"frame_id": "1171281190",
"frame_number": 13,
"v4_rank": 21,
"confidence": 0.1399,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "sw_reality_three_emphasis",
"frame_id": "1171281209",
"frame_number": 28,
"v4_rank": 22,
"confidence": 0.1271,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "solution_engn_split_diagram",
"frame_id": "1171281201",
"frame_number": 21,
"v4_rank": 23,
"confidence": 0.1171,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "overseas_bim_numbered_list",
"frame_id": "1171281174",
"frame_number": 3,
"v4_rank": 24,
"confidence": 0.1007,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "policy_achievement_five_goals",
"frame_id": "1171281213",
"frame_number": 32,
"v4_rank": 25,
"confidence": 0.0751,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "three_persona_benefits",
"frame_id": "1171281191",
"frame_number": 14,
"v4_rank": 26,
"confidence": 0.0722,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "engn_sw_development_domain_knowledge",
"frame_id": "1171281173",
"frame_number": 2,
"v4_rank": 27,
"confidence": 0.0635,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "sw_development_cycle_six_nodes",
"frame_id": "1171281172",
"frame_number": 1,
"v4_rank": 28,
"confidence": 0.0633,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "field_effectiveness_five_elements",
"frame_id": "1171281181",
"frame_number": 10,
"v4_rank": 29,
"confidence": 0.0618,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "info_management_what_how_when",
"frame_id": "1171281179",
"frame_number": 8,
"v4_rank": 30,
"confidence": 0.0487,
"label": "reject",
"catalog_registered": true
},
{
"template_id": "compensation_complaint_side_card",
"frame_id": "1171281176",
"frame_number": 5,
"v4_rank": 31,
"confidence": 0.0457,
"label": "reject",
"catalog_registered": false
},
{
"template_id": "construction_bim_three_usage",
"frame_id": "1171281182",
"frame_number": 11,
"v4_rank": 32,
"confidence": 0.0,
"label": "reject",
"catalog_registered": true
}
],
"application_candidates": [
{
"template_id": "process_product_two_way",
"frame_id": "1171281210",
"v4_label": "light_edit",
"application_mode": "same_frame_with_adjustment",
"auto_applicable": true,
"required_changes": [],
"delegated_to": "step10_contract_check"
}
],
"position": null,
"assignment_source": null,
"section_assignment_override": false,
"replaced_auto_unit": null,
"skipped_collided_auto_units": [],
"skipped_reason": null
}
],
"candidate_status_summary": {
"units_with_no_v4_candidate": [
"04-1"
],
"units_with_fallback": [
"04-2"
]
},
"fallback_policy": {
"fallback_used_count": 1,
"fallback_selection_count": 1,
"chain_exhausted_count": 0,
"selection_paths": [
{
"section_id": "04-1",
"selection_path": "rank_1",
"selected_rank": 1,
"selected_template_id": "pre_construction_model_info_stacked",
"fallback_trigger": null
},
{
"section_id": "04-2",
"selection_path": "rank_2_fallback",
"selected_rank": 2,
"selected_template_id": "process_product_two_way",
"fallback_trigger": "capacity_mismatch:strict_mismatch"
}
],
"policy": "IMP-05: rank-1 is kept when usable; rank-2/3 may be promoted only when the earlier rank is not auto-renderable, has no catalog contract, or fails capacity precheck. calculate_fit is not used."
},
"frame_overrides_applied": [],
"frame_overrides_skipped": [],
"section_assignment_plan": null,
"section_assignment_summary": null,
"v0_lock_note": "Step 9 v0 passive (사용자 lock 2026-05-08). Step 6 default 그대로 사용 — runtime 결과 byte-동일. auto decision / scoring 은 Step 9 v1 (별 axis)."
}
}
@@ -0,0 +1,72 @@
{
"step_num": 20,
"step_name": "slide_status",
"step_status": "done",
"pipeline_path_connected": true,
"input": [
"step14_visual_check.json",
"step17_retry_trace.json",
"step19_next_action.json"
],
"output": [
"step20_slide_status.json",
"step20_final_status.html"
],
"note": "자동 파이프라인 최종 결과 보고. overall = PASS/RENDERED_WITH_VISUAL_REGRESSION/PARTIAL_COVERAGE 등.",
"data": {
"rendered": true,
"visual_check_passed": false,
"full_mdx_coverage": true,
"aligned_section_ids": [
"04-1",
"04-2"
],
"covered_section_ids": [
"04-1",
"04-2"
],
"filtered_section_ids": [],
"filtered_section_reasons": [],
"selection_path": "fallback_used",
"fallback_used": true,
"fallback_selections": [
{
"position": "bottom",
"source_section_ids": [
"04-2"
],
"template_id": "process_product_two_way",
"selected_v4_rank": 2,
"selection_path": "rank_2_fallback",
"fallback_reason": "capacity_mismatch:strict_mismatch"
}
],
"fallback_selection_count": 1,
"selection_paths": [
{
"section_id": "04-1",
"selection_path": "rank_1",
"selected_rank": 1,
"selected_template_id": "pre_construction_model_info_stacked",
"fallback_trigger": null
},
{
"section_id": "04-2",
"selection_path": "rank_2_fallback",
"selected_rank": 2,
"selected_template_id": "process_product_two_way",
"fallback_trigger": "capacity_mismatch:strict_mismatch"
}
],
"visual_fail_reasons": [
"zone--bottom: inner clipped .f29b — excess 17px vert / 0px horiz (content 377 vs container 360)",
"zone--bottom: inner clipped .f29b__body — excess 17px vert / 0px horiz (content 311 vs container 294)"
],
"adapter_needed_count": 0,
"adapter_needed_units": [],
"content_truncated_count": 0,
"content_truncated_units": [],
"overall": "RENDERED_WITH_VISUAL_REGRESSION",
"note": "자동 파이프라인 결과 보고. review/UI 개념 X. final.html 파일명 != PASS 의미. overall == PASS 는 visual OK + full coverage + adapter_needed=0 일 때만. adapter_needed_count > 0 = mapper 가 contract 와 안 맞아 자동 렌더 못 한 zone 존재. content_truncated_count > 0 = builder 가 truncate 한 zone 존재 (rendered 됐지만 일부 콘텐츠 손실)."
}
}
@@ -0,0 +1,181 @@
/**
* Design Agent - Mock Data
*
* 이 파일은 백엔드 파이프라인이 연결되기 전까지 사용하는 mock 데이터입니다.
* Phase Z 설계 규격을 따릅니다.
*/
import type {
NormalizedContent,
SlidePlan,
LayoutCandidate,
FrameCandidate,
} from "../types/designAgent";
// ─────────────────────────────────────────────────────────────────────────────
// Layout Candidates
// ─────────────────────────────────────────────────────────────────────────────
// 8 preset = backend templates/phase_z2/layouts/layouts.yaml 1:1 매칭.
// id / 순서 / 의미 모두 backend 와 동일해야 함.
export const MOCK_LAYOUT_CANDIDATES: LayoutCandidate[] = [
{ id: "single", name: "단일 본문", type: "full", description: "전체 영역 1 zone (primary)" },
{ id: "horizontal-2", name: "상/하 2단", type: "top-bottom", description: "위/아래 2 zone (top, bottom) — rows topology" },
{ id: "vertical-2", name: "좌/우 2단", type: "left-right", description: "좌/우 2 zone (left, right) — cols topology" },
{ id: "top-1-bottom-2", name: "상 1 : 하 2", type: "asymmetric", description: "위 1 zone + 아래 좌/우 2 zone — T topology" },
{ id: "top-2-bottom-1", name: "상 2 : 하 1", type: "asymmetric", description: "위 좌/우 2 zone + 아래 1 zone — inverted-T topology" },
{ id: "left-1-right-2", name: "좌 1 : 우 2", type: "asymmetric", description: "좌 1 zone + 우 상/하 2 zone — side-T-left topology" },
{ id: "left-2-right-1", name: "좌 2 : 우 1", type: "asymmetric", description: "좌 상/하 2 zone + 우 1 zone — side-T-right topology" },
{ id: "grid-2x2", name: "2x2 그리드", type: "grid", description: "4 zone 균등 배치 — 2x2 topology" },
];
// ─────────────────────────────────────────────────────────────────────────────
// Frame Candidates (샘플 이미지 포함 - 8종 세트)
// ─────────────────────────────────────────────────────────────────────────────
const SAMPLE_FRAMES: FrameCandidate[] = [
{
id: "frame-001",
name: "3-Card 프로세스",
score: 0.98,
confidence: "high",
label: "use_as_is",
thumbnailUrl: "https://images.unsplash.com/photo-1614850523296-d8c1af93d400?w=300&h=200&fit=crop",
},
{
id: "frame-002",
name: "비교 테이블 (Light)",
score: 0.85,
confidence: "medium",
label: "light_edit",
thumbnailUrl: "https://images.unsplash.com/photo-1508615039623-a25651266b91?w=300&h=200&fit=crop",
},
{
id: "frame-003",
name: "계층형 트리",
score: 0.72,
confidence: "medium",
label: "restructure",
thumbnailUrl: "https://images.unsplash.com/photo-1551288049-bbda03a24d5d?w=300&h=200&fit=crop",
},
{
id: "frame-004",
name: "4-Grid 핵심 요약",
score: 0.65,
confidence: "low",
label: "reject",
thumbnailUrl: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=300&h=200&fit=crop",
},
{
id: "frame-005",
name: "타임라인 로드맵",
score: 0.91,
confidence: "high",
label: "use_as_is",
thumbnailUrl: "https://images.unsplash.com/photo-1531403009284-440f080d1e12?w=300&h=200&fit=crop",
},
{
id: "frame-006",
name: "순환형 다이어그램",
score: 0.78,
confidence: "medium",
label: "light_edit",
thumbnailUrl: "https://images.unsplash.com/photo-1557804506-669a67965ba0?w=300&h=200&fit=crop",
},
{
id: "frame-007",
name: "수치 강조 카드",
score: 0.88,
confidence: "high",
label: "use_as_is",
thumbnailUrl: "https://images.unsplash.com/photo-1551288049-bbda03a24d5d?w=300&h=200&fit=crop",
},
{
id: "frame-008",
name: "좌우 대비 분석",
score: 0.62,
confidence: "low",
label: "restructure",
thumbnailUrl: "https://images.unsplash.com/photo-1454165833767-02a6ed8a687a?w=300&h=200&fit=crop",
},
];
export const MOCK_FRAME_CANDIDATES_SECTION1 = SAMPLE_FRAMES;
// ─────────────────────────────────────────────────────────────────────────────
// Normalized Content
// ─────────────────────────────────────────────────────────────────────────────
export const MOCK_NORMALIZED_CONTENT: NormalizedContent = {
title: "DX 실행 체계 구축 방안",
sections: [
{
id: "section-1",
index: 1,
level: 2,
title: "DX 실행 필수 요건",
content_objects: [
{ id: "co-1", type: "text_block", role: "summary", raw_payload: "조직 전반의 DX 역량 강화 필요", size_estimate: { line_count: 2 } },
{ id: "co-2", type: "text_block", role: "detail", raw_payload: "전담 조직 구성 및 KPI 설정", size_estimate: { line_count: 3 } }
]
}
]
};
// ─────────────────────────────────────────────────────────────────────────────
// Slide Plan (Phase Z 구조)
// ─────────────────────────────────────────────────────────────────────────────
export const MOCK_SLIDE_PLAN: SlidePlan = {
id: "slide-001",
title: "DX 실행 체계 구축 방안",
layout_preset: "horizontal-2",
zones: [
{
id: "zone-left",
zone_id: "left",
section_ids: ["section-1"],
position: { x: 0, y: 0, width: 0.5, height: 1 },
internal_regions: [
{
id: "region-l1",
region_id: "content-1",
role: "primary",
content_type: "mixed",
ratio_estimate: 1,
content_unit_ids: ["co-1", "co-2"],
frame_match_strategy: {
kind: "frame_match",
frame_id: "frame-001",
display_strategy: "inline_full"
},
frame_candidates: SAMPLE_FRAMES
}
]
},
{
id: "zone-right",
zone_id: "right",
section_ids: ["section-1"],
position: { x: 0.5, y: 0, width: 0.5, height: 1 },
internal_regions: [
{
id: "region-r1",
region_id: "content-2",
role: "secondary",
content_type: "text_block",
ratio_estimate: 1,
content_unit_ids: [],
frame_match_strategy: {
kind: "frame_match",
frame_id: "frame-002",
display_strategy: "inline_full"
},
frame_candidates: SAMPLE_FRAMES
}
]
}
],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
+100
View File
@@ -0,0 +1,100 @@
{
"name": "design-agent",
"version": "1.0.0",
"type": "module",
"license": "MIT",
"scripts": {
"dev": "vite --host",
"build": "vite build && esbuild server/index.ts --platform=node --packages=external --bundle --format=esm --outdir=dist",
"start": "NODE_ENV=production node dist/index.js",
"preview": "vite preview --host",
"check": "tsc --noEmit",
"format": "prettier --write ."
},
"dependencies": {
"@hookform/resolvers": "^5.2.2",
"@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-aspect-ratio": "^1.1.7",
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-context-menu": "^2.2.16",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-hover-card": "^1.1.15",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-menubar": "^1.1.16",
"@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-radio-group": "^1.3.8",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slider": "^1.3.6",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toggle": "^1.1.10",
"@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.8",
"axios": "^1.12.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"embla-carousel-react": "^8.6.0",
"express": "^4.21.2",
"framer-motion": "^12.23.22",
"input-otp": "^1.4.2",
"lucide-react": "^0.453.0",
"nanoid": "^5.1.5",
"next-themes": "^0.4.6",
"react": "^19.2.1",
"react-day-picker": "^9.11.1",
"react-dom": "^19.2.1",
"react-hook-form": "^7.64.0",
"react-resizable-panels": "^3.0.6",
"recharts": "^2.15.2",
"sonner": "^2.0.7",
"streamdown": "^1.4.0",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"vaul": "^1.1.2",
"wouter": "^3.3.5",
"zod": "^4.1.12"
},
"devDependencies": {
"@builder.io/vite-plugin-jsx-loc": "^0.1.1",
"@tailwindcss/typography": "^0.5.15",
"@tailwindcss/vite": "^4.1.3",
"@types/express": "4.17.21",
"@types/google.maps": "^3.58.1",
"@types/node": "^24.7.0",
"@types/react": "^19.2.1",
"@types/react-dom": "^19.2.1",
"@vitejs/plugin-react": "^5.0.4",
"add": "^2.0.6",
"autoprefixer": "^10.4.20",
"esbuild": "^0.25.0",
"pnpm": "^10.15.1",
"postcss": "^8.4.47",
"prettier": "^3.6.2",
"tailwindcss": "^4.1.14",
"tsx": "^4.19.1",
"tw-animate-css": "^1.4.0",
"typescript": "5.6.3",
"vite": "^7.1.7",
"vite-plugin-manus-runtime": "^0.0.57",
"vitest": "^2.1.4"
},
"packageManager": "pnpm@10.4.1+sha512.c753b6c3ad7afa13af388fa6d808035a008e30ea9993f58c6663e2bc5ff21679aa834db094987129aa4d488b86df57f7b634981b2f827cdcacc698cc0cfb88af",
"pnpm": {
"patchedDependencies": {
"wouter@3.7.1": "patches/wouter@3.7.1.patch"
},
"overrides": {
"tailwindcss>nanoid": "3.3.7"
}
}
}
@@ -0,0 +1,28 @@
diff --git a/esm/index.js b/esm/index.js
index c83bc63a2c10431fb62e25b7d490656a3796f301..bcae513cc20a4be6c38dc116e0b8d9bacda62b5b 100644
--- a/esm/index.js
+++ b/esm/index.js
@@ -338,6 +338,23 @@ const Switch = ({ children, location }) => {
const router = useRouter();
const [originalLocation] = useLocationFromRouter(router);
+ // Collect all route paths to window object
+ if (typeof window !== 'undefined') {
+ if (!window.__WOUTER_ROUTES__) {
+ window.__WOUTER_ROUTES__ = [];
+ }
+
+ const allChildren = flattenChildren(children);
+ allChildren.forEach((element) => {
+ if (isValidElement(element) && element.props.path) {
+ const path = element.props.path;
+ if (!window.__WOUTER_ROUTES__.includes(path)) {
+ window.__WOUTER_ROUTES__.push(path);
+ }
+ }
+ });
+ }
+
for (const element of flattenChildren(children)) {
let match = 0;
+7192
View File
File diff suppressed because it is too large Load Diff
+169
View File
@@ -0,0 +1,169 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Slide Layout Preview (Step 22)</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;900&display=swap');
body { font-family: 'Inter', sans-serif; background-color: #f8fafc; padding: 40px; }
.slide-container {
width: 1280px;
height: 720px;
background: white;
box-shadow: 0 40px 100px -20px rgba(0,0,0,0.2);
border-radius: 16px;
overflow: hidden;
margin-bottom: 60px;
position: relative;
display: flex;
flex-direction: column;
}
.label {
position: absolute;
top: -30px;
left: 0;
font-size: 14px;
font-weight: 900;
color: #64748b;
text-transform: uppercase;
letter-spacing: 0.1em;
}
/* Header/Footer Mockup */
.slide-header { height: 80px; border-bottom: 1px solid #f1f5f9; display: flex; align-items: center; px: 40px; padding: 0 40px; }
.slide-footer { height: 100px; bg-slate-900: #0f172a; background: #0f172a; display: flex; align-items: center; padding: 0 40px; color: white; }
.slide-body { flex: 1; position: relative; overflow: hidden; }
</style>
</head>
<body>
<div style="max-width: 1280px; margin: 0 auto;">
<!-- LAYOUT 1 PREVIEW -->
<div style="position: relative; margin-top: 50px;">
<div class="label">Layout 1: Focus Split (single)</div>
<div class="slide-container">
<div class="slide-header">
<h1 class="text-3xl font-black text-slate-900">DX 실행 체계 구축 방안</h1>
</div>
<div class="slide-body">
<div class="w-full h-full flex gap-8 p-10 bg-white">
<div class="flex-[3] flex flex-col justify-center space-y-6">
<div class="space-y-2">
<div class="w-12 h-1 bg-blue-600 rounded-full"></div>
<h2 class="text-4xl font-black text-slate-900 leading-tight">DX 실행 필수 요건</h2>
</div>
<p class="text-xl text-slate-600 leading-relaxed font-medium">
조직 전반의 DX 역량 강화 필요 및 전담 조직 구성과 KPI 설정을 통한 체계적인 실행력 확보가 필수적입니다.
</p>
<div class="flex gap-4 pt-4">
<div class="px-4 py-2 bg-slate-50 border border-slate-100 rounded-xl text-sm font-bold text-slate-400 uppercase tracking-widest">Key Insight</div>
</div>
</div>
<div class="flex-[2] relative">
<div class="absolute inset-0 bg-gradient-to-br from-blue-50 to-indigo-50 rounded-[2rem] border-2 border-white shadow-inner flex flex-col items-center justify-center p-8 text-center">
<div class="w-16 h-16 bg-white rounded-2xl shadow-lg flex items-center justify-center mb-6">
<div class="w-8 h-8 bg-blue-600 rounded-lg"></div>
</div>
<h3 class="text-2xl font-bold text-slate-800 mb-3">Strategic Impact</h3>
<p class="text-sm text-slate-500 font-medium leading-normal">
데이터 기반 의사결정 체계 구축을 통한 업무 효율성 30% 향상 기대
</p>
</div>
</div>
</div>
</div>
<div class="slide-footer">
<div class="px-3 py-1 bg-blue-600 font-black text-[12px] rounded uppercase mr-6">Summary</div>
<p class="text-xl font-bold opacity-80 italic">"성공적인 DX를 위해서는 기술보다 조직과 문화의 변화가 우선되어야 합니다."</p>
</div>
</div>
</div>
<!-- LAYOUT 2 PREVIEW -->
<div style="position: relative; margin-top: 80px;">
<div class="label">Layout 2: Quadrant Grid (grid-2x2)</div>
<div class="slide-container">
<div class="slide-header">
<h1 class="text-3xl font-black text-slate-900">DX 추진 전략 프레임워크</h1>
</div>
<div class="slide-body">
<div class="w-full h-full grid grid-cols-2 grid-rows-2 gap-8 p-10 bg-white">
<!-- Item 1 -->
<div class="p-8 rounded-[1.5rem] border-2 border-slate-50 bg-slate-50/30 flex flex-col justify-between">
<div class="space-y-3">
<div class="flex items-center gap-3">
<span class="flex items-center justify-center w-8 h-8 rounded-full bg-slate-900 text-white text-sm font-black">01</span>
<h3 class="text-2xl font-black text-slate-800">Strategy</h3>
</div>
<p class="text-base text-slate-500 font-medium pl-11">디지털 비전 수립 및 중장기 로드맵 확정</p>
</div>
<div class="pl-11 pt-4">
<div class="w-full h-1.5 bg-slate-100 rounded-full overflow-hidden">
<div class="w-2/3 h-full bg-blue-500 rounded-full"></div>
</div>
</div>
</div>
<!-- Item 2 -->
<div class="p-8 rounded-[1.5rem] border-2 border-slate-50 bg-slate-50/30 flex flex-col justify-between">
<div class="space-y-3">
<div class="flex items-center gap-3">
<span class="flex items-center justify-center w-8 h-8 rounded-full bg-slate-900 text-white text-sm font-black">02</span>
<h3 class="text-2xl font-black text-slate-800">Operations</h3>
</div>
<p class="text-base text-slate-500 font-medium pl-11">프로세스 자동화 및 지능형 운영 체계 도입</p>
</div>
<div class="pl-11 pt-4">
<div class="w-full h-1.5 bg-slate-100 rounded-full overflow-hidden">
<div class="w-1/2 h-full bg-blue-500 rounded-full"></div>
</div>
</div>
</div>
<!-- Item 3 -->
<div class="p-8 rounded-[1.5rem] border-2 border-slate-50 bg-slate-50/30 flex flex-col justify-between">
<div class="space-y-3">
<div class="flex items-center gap-3">
<span class="flex items-center justify-center w-8 h-8 rounded-full bg-slate-900 text-white text-sm font-black">03</span>
<h3 class="text-2xl font-black text-slate-800">Technology</h3>
</div>
<p class="text-base text-slate-500 font-medium pl-11">클라우드 네이티브 아키텍처 및 보안 강화</p>
</div>
<div class="pl-11 pt-4">
<div class="w-full h-1.5 bg-slate-100 rounded-full overflow-hidden">
<div class="w-3/4 h-full bg-blue-500 rounded-full"></div>
</div>
</div>
</div>
<!-- Item 4 -->
<div class="p-8 rounded-[1.5rem] border-2 border-slate-50 bg-slate-50/30 flex flex-col justify-between">
<div class="space-y-3">
<div class="flex items-center gap-3">
<span class="flex items-center justify-center w-8 h-8 rounded-full bg-slate-900 text-white text-sm font-black">04</span>
<h3 class="text-2xl font-black text-slate-800">Culture</h3>
</div>
<p class="text-base text-slate-500 font-medium pl-11">애자일 방식 도입 및 데이터 리터러시 교육</p>
</div>
<div class="pl-11 pt-4">
<div class="w-full h-1.5 bg-slate-100 rounded-full overflow-hidden">
<div class="w-full h-full bg-blue-500 rounded-full"></div>
</div>
</div>
</div>
</div>
</div>
<div class="slide-footer">
<div class="px-3 py-1 bg-blue-600 font-black text-[12px] rounded uppercase mr-6">Summary</div>
<p class="text-xl font-bold opacity-80 italic">"기술, 전략, 운영, 문화 4대 요소의 균형 잡힌 발전이 DX 성공의 열쇠입니다."</p>
</div>
</div>
</div>
</div>
</body>
</html>
+33
View File
@@ -0,0 +1,33 @@
import express from "express";
import { createServer } from "http";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
async function startServer() {
const app = express();
const server = createServer(app);
// Serve static files from dist/public in production
const staticPath =
process.env.NODE_ENV === "production"
? path.resolve(__dirname, "public")
: path.resolve(__dirname, "..", "dist", "public");
app.use(express.static(staticPath));
// Handle client-side routing - serve index.html for all routes
app.get("*", (_req, res) => {
res.sendFile(path.join(staticPath, "index.html"));
});
const port = process.env.PORT || 3000;
server.listen(port, () => {
console.log(`Server running on http://localhost:${port}/`);
});
}
startServer().catch(console.error);
+2
View File
@@ -0,0 +1,2 @@
export const COOKIE_NAME = "app_session_id";
export const ONE_YEAR_MS = 1000 * 60 * 60 * 24 * 365;
@@ -0,0 +1,231 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Standard Slide Base & Body Layouts</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;900&display=swap');
body {
font-family: 'Inter', sans-serif;
background-color: #f1f5f9;
padding: 50px;
display: flex;
flex-direction: column;
align-items: center;
}
/* 16:9 Base Slide Container */
.slide-base {
width: 1280px;
height: 720px;
background: white;
box-shadow: 0 40px 100px -20px rgba(0,0,0,0.2);
border-radius: 16px;
overflow: hidden;
display: flex;
flex-direction: column;
position: relative;
margin-bottom: 80px;
}
/* 1. Header Area: Fixed 80px */
.header {
height: 80px;
min-height: 80px;
border-bottom: 1px solid #f1f5f9;
display: flex;
align-items: center;
padding: 0 40px; /* 제목 좌우 여백 */
}
.header h1 {
font-size: 32px; /* 하드코딩된 제목 크기 */
font-weight: 900;
color: #0f172a;
margin: 0;
}
/* 2. Footer Area: Fixed 100px */
.footer {
height: 100px;
min-height: 100px;
background: #0f172a;
display: flex;
align-items: center;
padding: 0 40px; /* footer 좌우 여백 */
color: white;
}
.footer-label {
padding: 4px 12px;
background: #2563eb;
font-size: 12px;
font-weight: 900;
text-transform: uppercase;
border-radius: 4px;
margin-right: 24px;
}
.footer-text {
font-size: 20px; /* 하드코딩된 하단 요약 크기 */
font-weight: 700;
font-style: italic;
opacity: 0.9;
margin: 0;
}
/* 3. Body Area: Flexible, but width matches footer's inner width */
.body-container {
flex: 1;
padding: 30px 40px; /* 상하 30px, 좌우 40px (footer와 정렬) */
display: flex;
flex-direction: column;
overflow: hidden;
}
.layout-label {
align-self: flex-start;
margin-bottom: 20px;
font-size: 14px;
font-weight: 900;
color: #64748b;
text-transform: uppercase;
}
</style>
</head>
<body>
<!-- SAMPLE 1: FOCUS SPLIT -->
<div class="layout-label">Layout 01: Focus Split (Body Only)</div>
<div class="slide-base">
<!-- HEADER (Fixed) -->
<div class="header">
<h1>DX 실행 필수 요건 및 추진 로드맵</h1>
</div>
<!-- BODY AREA -->
<div class="body-container">
<div class="w-full h-full flex gap-12">
<!-- Left: Content (65%) -->
<div class="flex-[6.5] flex flex-col justify-center space-y-6">
<div class="space-y-3">
<div class="w-12 h-1.5 bg-blue-600 rounded-full"></div>
<h2 style="font-size: 38px;" class="font-black text-slate-900 leading-tight">DX 역량 내재화</h2>
</div>
<p style="font-size: 22px;" class="text-slate-600 leading-relaxed font-medium">
단순 기술 도입을 넘어, 조직 전반의 데이터 문해력(Data Literacy) 확보와
애자일 방식의 전파를 통한 구조적 변화가 선행되어야 합니다.
</p>
<div class="pt-4">
<span style="font-size: 13px;" class="px-5 py-2.5 bg-slate-100 rounded-xl font-bold text-slate-500 uppercase tracking-widest border border-slate-200">
Core Strategy 2026
</span>
</div>
</div>
<!-- Right: Visual/Detail (35%) -->
<div class="flex-[3.5] flex items-center justify-center">
<div class="w-full h-full bg-slate-50 rounded-[2.5rem] border-2 border-slate-100 flex flex-col items-center justify-center p-10 text-center relative overflow-hidden shadow-inner">
<div class="absolute -top-10 -right-10 w-40 h-40 bg-blue-500/5 rounded-full"></div>
<div class="w-20 h-20 bg-white rounded-3xl shadow-xl flex items-center justify-center mb-8">
<div class="w-10 h-10 bg-blue-600 rounded-xl"></div>
</div>
<h3 style="font-size: 24px;" class="font-black text-slate-800 mb-4">Strategic Impact</h3>
<p style="font-size: 15px;" class="text-slate-500 font-bold leading-normal">
의사결정 속도 40% 단축 및<br>신규 서비스 출시 주기 2배 가속화
</p>
</div>
</div>
</div>
</div>
<!-- FOOTER (Fixed) -->
<div class="footer">
<div class="footer-label">Summary</div>
<p class="footer-text">"기술보다 조직의 변화가 성공적인 디지털 전환의 핵심입니다."</p>
</div>
</div>
<!-- SAMPLE 2: QUADRANT GRID -->
<div class="layout-label">Layout 02: Quadrant Grid (Body Only)</div>
<div class="slide-base">
<!-- HEADER (Fixed) -->
<div class="header">
<h1>4대 핵심 추진 영역 가시화</h1>
</div>
<!-- BODY AREA -->
<div class="body-container">
<div class="w-full h-full grid grid-cols-2 grid-rows-2 gap-8">
<!-- Card 1 -->
<div class="bg-slate-50/50 rounded-[2rem] border-2 border-slate-100 p-8 flex flex-col justify-between hover:border-blue-200 hover:bg-white transition-all">
<div class="space-y-4">
<div class="flex items-center gap-4">
<span style="font-size: 14px;" class="w-9 h-9 flex items-center justify-center rounded-full bg-slate-900 text-white font-black">01</span>
<h3 style="font-size: 24px;" class="font-black text-slate-800">Governance</h3>
</div>
<p style="font-size: 16px;" class="text-slate-500 font-bold pl-12">전사 DX 추진 거버넌스 수립 및 KPI 정렬</p>
</div>
<div class="pl-12 pt-4">
<div class="w-full h-2 bg-slate-200 rounded-full overflow-hidden">
<div class="w-2/3 h-full bg-blue-600"></div>
</div>
</div>
</div>
<!-- Card 2 -->
<div class="bg-slate-50/50 rounded-[2rem] border-2 border-slate-100 p-8 flex flex-col justify-between hover:border-blue-200 hover:bg-white transition-all">
<div class="space-y-4">
<div class="flex items-center gap-4">
<span style="font-size: 14px;" class="w-9 h-9 flex items-center justify-center rounded-full bg-slate-900 text-white font-black">02</span>
<h3 style="font-size: 24px;" class="font-black text-slate-800">Platform</h3>
</div>
<p style="font-size: 16px;" class="text-slate-500 font-bold pl-12">통합 데이터 플랫폼 구축 및 클라우드 전환</p>
</div>
<div class="pl-12 pt-4">
<div class="w-full h-2 bg-slate-200 rounded-full overflow-hidden">
<div class="w-1/2 h-full bg-blue-600"></div>
</div>
</div>
</div>
<!-- Card 3 -->
<div class="bg-slate-50/50 rounded-[2rem] border-2 border-slate-100 p-8 flex flex-col justify-between hover:border-blue-200 hover:bg-white transition-all">
<div class="space-y-4">
<div class="flex items-center gap-4">
<span style="font-size: 14px;" class="w-9 h-9 flex items-center justify-center rounded-full bg-slate-900 text-white font-black">03</span>
<h3 style="font-size: 24px;" class="font-black text-slate-800">Operation</h3>
</div>
<p style="font-size: 16px;" class="text-slate-500 font-bold pl-12">비즈니스 프로세스 자동화 및 AI 비서 도입</p>
</div>
<div class="pl-12 pt-4">
<div class="w-full h-2 bg-slate-200 rounded-full overflow-hidden">
<div class="w-4/5 h-full bg-blue-600"></div>
</div>
</div>
</div>
<!-- Card 4 -->
<div class="bg-slate-50/50 rounded-[2rem] border-2 border-slate-100 p-8 flex flex-col justify-between hover:border-blue-200 hover:bg-white transition-all">
<div class="space-y-4">
<div class="flex items-center gap-4">
<span style="font-size: 14px;" class="w-9 h-9 flex items-center justify-center rounded-full bg-slate-900 text-white font-black">04</span>
<h3 style="font-size: 24px;" class="font-black text-slate-800">Training</h3>
</div>
<p style="font-size: 16px;" class="text-slate-500 font-bold pl-12">전 임직원 디지털 리터러시 강화 교육 시행</p>
</div>
<div class="pl-12 pt-4">
<div class="w-full h-2 bg-slate-200 rounded-full overflow-hidden">
<div class="w-full h-full bg-blue-600"></div>
</div>
</div>
</div>
</div>
</div>
<!-- FOOTER (Fixed) -->
<div class="footer">
<div class="footer-label">Summary</div>
<p class="footer-text">"영역별 균형 있는 추진을 통해 디지털 전환 시너지를 극대화합니다."</p>
</div>
</div>
</body>
</html>
+23
View File
@@ -0,0 +1,23 @@
{
"include": ["client/src/**/*", "shared/**/*", "server/**/*"],
"exclude": ["node_modules", "build", "dist", "**/*.test.ts"],
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./node_modules/typescript/tsbuildinfo",
"noEmit": true,
"module": "ESNext",
"strict": true,
"lib": ["esnext", "dom", "dom.iterable"],
"jsx": "preserve",
"esModuleInterop": true,
"skipLibCheck": true,
"allowImportingTsExtensions": true,
"moduleResolution": "bundler",
"baseUrl": ".",
"types": ["node", "vite/client"],
"paths": {
"@/*": ["./client/src/*"],
"@shared/*": ["./shared/*"]
}
}
}
+22
View File
@@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["vite.config.ts"]
}
+541
View File
@@ -0,0 +1,541 @@
import { jsxLocPlugin } from "@builder.io/vite-plugin-jsx-loc";
import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";
import { spawn } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { defineConfig, type Plugin, type ViteDevServer } from "vite";
import { vitePluginManusRuntime } from "vite-plugin-manus-runtime";
// =============================================================================
// Manus Debug Collector - Vite Plugin
// Writes browser logs directly to files, trimmed when exceeding size limit
// =============================================================================
const PROJECT_ROOT = import.meta.dirname;
const LOG_DIR = path.join(PROJECT_ROOT, ".manus-logs");
const MAX_LOG_SIZE_BYTES = 1 * 1024 * 1024; // 1MB per log file
const TRIM_TARGET_BYTES = Math.floor(MAX_LOG_SIZE_BYTES * 0.6); // Trim to 60% to avoid constant re-trimming
type LogSource = "browserConsole" | "networkRequests" | "sessionReplay";
function ensureLogDir() {
if (!fs.existsSync(LOG_DIR)) {
fs.mkdirSync(LOG_DIR, { recursive: true });
}
}
function trimLogFile(logPath: string, maxSize: number) {
try {
if (!fs.existsSync(logPath) || fs.statSync(logPath).size <= maxSize) {
return;
}
const lines = fs.readFileSync(logPath, "utf-8").split("\n");
const keptLines: string[] = [];
let keptBytes = 0;
// Keep newest lines (from end) that fit within 60% of maxSize
const targetSize = TRIM_TARGET_BYTES;
for (let i = lines.length - 1; i >= 0; i--) {
const lineBytes = Buffer.byteLength(`${lines[i]}\n`, "utf-8");
if (keptBytes + lineBytes > targetSize) break;
keptLines.unshift(lines[i]);
keptBytes += lineBytes;
}
fs.writeFileSync(logPath, keptLines.join("\n"), "utf-8");
} catch {
/* ignore trim errors */
}
}
function writeToLogFile(source: LogSource, entries: unknown[]) {
if (entries.length === 0) return;
ensureLogDir();
const logPath = path.join(LOG_DIR, `${source}.log`);
// Format entries with timestamps
const lines = entries.map((entry) => {
const ts = new Date().toISOString();
return `[${ts}] ${JSON.stringify(entry)}`;
});
// Append to log file
fs.appendFileSync(logPath, `${lines.join("\n")}\n`, "utf-8");
// Trim if exceeds max size
trimLogFile(logPath, MAX_LOG_SIZE_BYTES);
}
/**
* Vite plugin to collect browser debug logs
* - POST /__manus__/logs: Browser sends logs, written directly to files
* - Files: browserConsole.log, networkRequests.log, sessionReplay.log
* - Auto-trimmed when exceeding 1MB (keeps newest entries)
*/
function vitePluginManusDebugCollector(): Plugin {
return {
name: "manus-debug-collector",
transformIndexHtml(html) {
if (process.env.NODE_ENV === "production") {
return html;
}
return {
html,
tags: [
{
tag: "script",
attrs: {
src: "/__manus__/debug-collector.js",
defer: true,
},
injectTo: "head",
},
],
};
},
configureServer(server: ViteDevServer) {
// POST /__manus__/logs: Browser sends logs (written directly to files)
server.middlewares.use("/__manus__/logs", (req, res, next) => {
if (req.method !== "POST") {
return next();
}
const handlePayload = (payload: any) => {
// Write logs directly to files
if (payload.consoleLogs?.length > 0) {
writeToLogFile("browserConsole", payload.consoleLogs);
}
if (payload.networkRequests?.length > 0) {
writeToLogFile("networkRequests", payload.networkRequests);
}
if (payload.sessionEvents?.length > 0) {
writeToLogFile("sessionReplay", payload.sessionEvents);
}
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ success: true }));
};
const reqBody = (req as { body?: unknown }).body;
if (reqBody && typeof reqBody === "object") {
try {
handlePayload(reqBody);
} catch (e) {
res.writeHead(400, { "Content-Type": "application/json" });
res.end(JSON.stringify({ success: false, error: String(e) }));
}
return;
}
let body = "";
req.on("data", (chunk) => {
body += chunk.toString();
});
req.on("end", () => {
try {
const payload = JSON.parse(body);
handlePayload(payload);
} catch (e) {
res.writeHead(400, { "Content-Type": "application/json" });
res.end(JSON.stringify({ success: false, error: String(e) }));
}
});
});
},
};
}
function vitePluginStorageProxy(): Plugin {
return {
name: "manus-storage-proxy",
configureServer(server: ViteDevServer) {
server.middlewares.use("/manus-storage", async (req, res) => {
const key = req.url?.replace(/^\//, "");
if (!key) {
res.writeHead(400, { "Content-Type": "text/plain" });
res.end("Missing storage key");
return;
}
const forgeBaseUrl = (process.env.BUILT_IN_FORGE_API_URL || "").replace(/\/+$/, "");
const forgeKey = process.env.BUILT_IN_FORGE_API_KEY;
if (!forgeBaseUrl || !forgeKey) {
res.writeHead(500, { "Content-Type": "text/plain" });
res.end("Storage proxy not configured");
return;
}
try {
const forgeUrl = new URL("v1/storage/presign/get", forgeBaseUrl + "/");
forgeUrl.searchParams.set("path", key);
const forgeResp = await fetch(forgeUrl, {
headers: { Authorization: `Bearer ${forgeKey}` },
});
if (!forgeResp.ok) {
res.writeHead(502, { "Content-Type": "text/plain" });
res.end("Storage backend error");
return;
}
const { url } = (await forgeResp.json()) as { url: string };
if (!url) {
res.writeHead(502, { "Content-Type": "text/plain" });
res.end("Empty signed URL");
return;
}
res.writeHead(307, { Location: url, "Cache-Control": "no-store" });
res.end();
} catch {
res.writeHead(502, { "Content-Type": "text/plain" });
res.end("Storage proxy error");
}
});
},
};
}
// =============================================================================
// Phase Z API Plugin — MDX 업로드 → 파이프라인 실행 → 결과 노출
//
// Endpoints (vite dev middleware) :
// POST /api/run multipart/JSON body {filename, content} → run_id
// GET /data/runs/{run_id}/{path} → {DESIGN_AGENT_ROOT}/data/runs/{run_id}/phase_z2/{path}
//
// 환경 변수 (선택) :
// DESIGN_AGENT_ROOT python pipeline 실행 cwd. default = D:/ad-hoc/kei/design_agent
// =============================================================================
function vitePluginPhaseZApi(): Plugin {
const DESIGN_AGENT_ROOT =
process.env.DESIGN_AGENT_ROOT || "D:\\ad-hoc\\kei\\design_agent";
const UPLOADS_DIR = path.join(DESIGN_AGENT_ROOT, "samples", "uploads");
const RUNS_DIR = path.join(DESIGN_AGENT_ROOT, "data", "runs");
return {
name: "phase-z-api",
configureServer(server: ViteDevServer) {
// ── POST /api/run — MDX 업로드 → 파이프라인 실행 (sync) ──
server.middlewares.use("/api/run", (req, res, next) => {
if (req.method !== "POST") return next();
let body = "";
req.on("data", (chunk) => {
body += chunk.toString();
});
req.on("end", () => {
let payload: {
filename?: string;
content?: string;
overrides?: {
layout?: string;
frames?: Record<string, string>; // unit_id → template_id
zoneGeometries?: Record<string, { x: number; y: number; w: number; h: number }>; // zone_id → bbox (slide-body 내부 0~1)
// IMP-08 B-3 : zone_id -> list of canonical section_id assignments
// (e.g., "top": ["03-1-sub-1"]). Forwarded as --override-section-assignment.
zoneSections?: Record<string, string[]>;
};
};
try {
payload = JSON.parse(body);
} catch (e) {
res.writeHead(400, { "Content-Type": "application/json" });
res.end(
JSON.stringify({ success: false, error: `bad JSON: ${String(e)}` })
);
return;
}
const { filename, content, overrides } = payload;
if (!filename || typeof content !== "string") {
res.writeHead(400, { "Content-Type": "application/json" });
res.end(
JSON.stringify({
success: false,
error: "missing filename or content",
})
);
return;
}
// Security: filename 정규화 (path 분리 / .. 차단)
const safeName = filename.replace(/[\\/]/g, "_").replace(/\.\./g, "_");
if (!safeName.match(/\.mdx?$/i)) {
res.writeHead(400, { "Content-Type": "application/json" });
res.end(
JSON.stringify({
success: false,
error: "filename must end with .mdx or .md",
})
);
return;
}
// 1. MDX 저장
if (!fs.existsSync(UPLOADS_DIR)) {
fs.mkdirSync(UPLOADS_DIR, { recursive: true });
}
const mdxPath = path.join(UPLOADS_DIR, safeName);
fs.writeFileSync(mdxPath, content, "utf-8");
// 2. run_id 생성 (basename + timestamp)
const baseName = safeName
.replace(/\.mdx?$/i, "")
.replace(/[^a-zA-Z0-9_]/g, "_");
const ts = new Date()
.toISOString()
.replace(/[-:T]/g, "")
.replace(/\..+$/, "")
.slice(0, 14); // YYYYMMDDHHMMSS
const runId = `${baseName}_${ts}`;
// 3. python -m src.phase_z2_pipeline {mdx_path} {run_id} (cwd=DESIGN_AGENT_ROOT)
// shell: false → argv 그대로 전달 (파일명 공백/한글 안전).
// Windows 에서 .exe 확장자 자동 탐색을 위해 python.exe 명시.
// Step D : overrides 가 들어오면 --override-layout / --override-frame 인자로 forward.
const cliArgs = ["-m", "src.phase_z2_pipeline", mdxPath, runId];
if (overrides?.layout && typeof overrides.layout === "string") {
cliArgs.push("--override-layout", overrides.layout);
}
if (overrides?.frames && typeof overrides.frames === "object") {
for (const [unitId, templateId] of Object.entries(overrides.frames)) {
if (typeof templateId === "string" && templateId) {
cliArgs.push("--override-frame", `${unitId}=${templateId}`);
}
}
}
if (overrides?.zoneGeometries && typeof overrides.zoneGeometries === "object") {
for (const [zoneId, geom] of Object.entries(overrides.zoneGeometries)) {
if (geom && typeof geom === "object") {
const { x, y, w, h } = geom;
cliArgs.push(
"--override-zone-geometry",
`${zoneId}=${x},${y},${w},${h}`
);
}
}
}
// IMP-08 B-3 — zoneSections override forward to CLI.
// Each entry becomes `--override-section-assignment ZONE=sid[,sid]`.
// Empty arrays and non-string sids are filtered out so the backend
// never receives bogus assignments from a partially-built UI state.
if (overrides?.zoneSections && typeof overrides.zoneSections === "object") {
for (const [zoneId, sids] of Object.entries(overrides.zoneSections)) {
if (!Array.isArray(sids)) continue;
const cleaned = sids.filter((s) => typeof s === "string" && s.trim());
if (cleaned.length === 0) continue;
cliArgs.push(
"--override-section-assignment",
`${zoneId}=${cleaned.join(",")}`
);
}
}
console.log(
`[phase-z-api] spawn pipeline: run_id=${runId}, mdx=${mdxPath}, args=${JSON.stringify(cliArgs.slice(2))}`
);
const pythonExe = process.platform === "win32" ? "python.exe" : "python";
// 2026-05-14 — env toggle forward (보고용 일회성).
// PHASE_Z_ALLOW_RESTRUCTURE / PHASE_Z_ALLOW_REJECT : status 통과
// PHASE_Z_MAX_RANK=32 : V4 fallback chain 의 max_rank 확대 (등록 frame 까지 검색)
// 04-1 (all reject) / 05-2 (rank 1~3 미등록) 등 자동 매칭 가능.
const proc = spawn(pythonExe, cliArgs, {
cwd: DESIGN_AGENT_ROOT,
shell: false,
env: {
...process.env,
PHASE_Z_ALLOW_RESTRUCTURE: "1",
PHASE_Z_ALLOW_REJECT: "1",
PHASE_Z_MAX_RANK: "32",
},
});
let stdout = "";
let stderr = "";
proc.stdout.on("data", (chunk) => {
stdout += chunk.toString();
});
proc.stderr.on("data", (chunk) => {
stderr += chunk.toString();
});
proc.on("error", (err) => {
res.writeHead(500, { "Content-Type": "application/json" });
res.end(
JSON.stringify({
success: false,
error: `spawn failed: ${err.message}`,
})
);
});
proc.on("exit", (code) => {
const outDir = path.join(RUNS_DIR, runId, "phase_z2");
const finalHtmlExists = fs.existsSync(path.join(outDir, "final.html"));
const previewExists = fs.existsSync(path.join(outDir, "preview.png"));
// 2026-05-14 — success 판정 보완.
// exit_code 0 → full PASS
// exit_code != 0 → status enum 차이 (visual_regression / partial_coverage 등)
// 다만 final.html 존재 시 frontend 는 표시 가능 (clipping warning 만).
// = (exit_code 0) OR (final.html 존재) 모두 success=true.
const success = code === 0 || finalHtmlExists;
res.writeHead(success ? 200 : 500, {
"Content-Type": "application/json",
});
res.end(
JSON.stringify({
success,
run_id: runId,
exit_code: code,
final_html_exists: finalHtmlExists,
preview_exists: previewExists,
stdout: stdout.slice(-3000),
stderr: stderr.slice(-3000),
})
);
});
});
});
// ── GET /api/sample-mdx → samples/mdx/{03|04|05} (데모) ──
// 페이지 로드 시 frontend 가 자동 fetch — 상대방에게 mdx 파일 공유 안 해도 되게.
// 2026-05-14 — query param `?mdx=04` / `?mdx=05` 추가 (default = 03).
// 04 / 05 도 frontend simulation 가능하도록 frame/layout override 적용 path 유지.
const SAMPLE_MDX_MAP: Record<string, string> = {
"03": "03. DX 시행을 위한 필수 요건 및 혁신 방안.mdx",
"04": "04. DX 지연 요인.mdx",
"05": "05. 설계 방식의 왜곡.mdx",
};
server.middlewares.use("/api/sample-mdx", (req, res, next) => {
if (req.method !== "GET") return next();
const url = new URL(req.url || "/", "http://x");
const which = url.searchParams.get("mdx") || "03";
const filename = SAMPLE_MDX_MAP[which] || SAMPLE_MDX_MAP["03"];
const samplePath = path.join(
DESIGN_AGENT_ROOT,
"samples",
"mdx",
filename
);
if (!fs.existsSync(samplePath)) {
res.writeHead(404);
res.end("sample mdx not found");
return;
}
res.setHeader("Content-Type", "text/markdown; charset=utf-8");
res.setHeader("X-Mdx-Filename", encodeURIComponent(filename));
fs.createReadStream(samplePath).pipe(res);
});
// ── GET /frame-preview/{frame_number} → data/figma_previews/{NN}.png ──
// V4 후보 카드 thumbnail. data/figma_previews/ 는 frame_number 1~32 모두 존재 (Figma original export).
// 우선 figma_to_html_agent/blocks/{frame_number}/preview.png 시도해서 더 detail 한 렌더 결과 있으면 사용 — 단 frame_id 와 frame_number 가 다른 식별자라 path 매핑이 없으므로 일단 figma_previews 만 사용.
server.middlewares.use("/frame-preview", (req, res, next) => {
if (req.method !== "GET") return next();
const url = (req.url || "").split("?")[0];
const arg = url.replace(/^\//, "").replace(/[^0-9]/g, "");
if (!arg) return next();
// 1-digit / 2-digit 모두 zero-pad 시도 (e.g., "13" → "13.png", "5" → "05.png")
const padded = arg.padStart(2, "0");
const previewPath = path.join(
DESIGN_AGENT_ROOT,
"data",
"figma_previews",
`${padded}.png`
);
if (!fs.existsSync(previewPath)) {
res.writeHead(404);
res.end("frame preview not found");
return;
}
res.setHeader("Content-Type", "image/png");
fs.createReadStream(previewPath).pipe(res);
});
// ── GET /data/runs/{run_id}/{path} → {RUNS_DIR}/{run_id}/phase_z2/{path} ──
server.middlewares.use("/data/runs", (req, res, next) => {
if (req.method !== "GET") return next();
const url = req.url || "";
if (url.includes("..") || url.includes("\\")) {
res.writeHead(400);
res.end("Bad Request");
return;
}
const segments = url.split("?")[0].split("/").filter((s) => s.length > 0);
if (segments.length < 2) return next();
const [runId, ...rest] = segments;
const filePath = path.join(RUNS_DIR, runId, "phase_z2", ...rest);
if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
// Fallback to next middleware (vite default static — client/public)
return next();
}
const ext = path.extname(filePath).toLowerCase();
const mimeMap: Record<string, string> = {
".html": "text/html; charset=utf-8",
".json": "application/json; charset=utf-8",
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".svg": "image/svg+xml",
".md": "text/markdown; charset=utf-8",
".txt": "text/plain; charset=utf-8",
};
res.setHeader("Content-Type", mimeMap[ext] || "application/octet-stream");
fs.createReadStream(filePath).pipe(res);
});
},
};
}
const plugins = [react(), tailwindcss(), jsxLocPlugin(), vitePluginManusRuntime(), vitePluginManusDebugCollector(), vitePluginStorageProxy(), vitePluginPhaseZApi()];
export default defineConfig({
plugins,
resolve: {
alias: {
"@": path.resolve(import.meta.dirname, "client", "src"),
"@shared": path.resolve(import.meta.dirname, "shared"),
"@assets": path.resolve(import.meta.dirname, "attached_assets"),
},
},
envDir: path.resolve(import.meta.dirname),
root: path.resolve(import.meta.dirname, "client"),
build: {
outDir: path.resolve(import.meta.dirname, "dist/public"),
emptyOutDir: true,
},
server: {
port: 3000,
strictPort: false, // Will find next available port if 3000 is busy
host: true,
allowedHosts: [
".manuspre.computer",
".manus.computer",
".manus-asia.computer",
".manuscomputer.ai",
".manusvm.computer",
"localhost",
"127.0.0.1",
],
fs: {
strict: true,
deny: ["**/.*"],
},
},
});
+578
View File
@@ -0,0 +1,578 @@
# Pipeline 개선 — 매칭 시스템 통합 (Redesign)
> **작성일**: 2026-04-28
> **목적**: 매칭 시스템 (V1~V4) 테스트 결과를 기존 design_agent pipeline 에 통합. AI 호출을 줄이고 결정론적 매칭 + 정밀한 공간 관리를 결합.
> **상태**: 설계 단계. 실행은 사용자 승인 후 단계적 진행.
---
## 1. 배경 / 문제의식
### 기존 pipeline 의 한계
| 문제 | 현황 |
|---|---|
| AI 호출 과다 | Stage 1A / 1B / 1B-ST / 1.7 / 1.8 / 2 / 4 — 5~6 회 호출 |
| Type A/B/B'/B'' 하드코딩 | 콘텐츠별 전용 코드 분기 (오답노트 #2 위반 우려) |
| 블록 catalog 50+ 개 vs 실제 사용 7.9% | Phase P 결과 — 다양성 부족 |
| 유령 블록 / overflow 출력 | Phase Q 에서 일부 해결 |
### 매칭 시스템 (V1~V4) 테스트 결과
`tests/matching/` 에서 별도 검증한 결과:
| 항목 | 결과 |
|---|---|
| TARGET 정답률 | 3/4 (75%) — Logistic Regression 가중치 학습 + LOOCV 4/4 검증 |
| BM25 / IDF 비교 | 현 방식 우위 (4/4 vs 3/4) |
| V4 slot 축 ablation | Top-1 매칭 7/7 동일 — slot 축 frame 선별 무영향 확인 |
| 발견된 약점 | 8 가지 (`tests/PROGRESS.md` 참조) |
### 통합 필요성
매칭 시스템이 **콘텐츠 분석 / 디자인 추천** 부분을 코드로 대체 가능함을 확인. 단, 1280×720 안 정밀 공간 관리는 매칭 시스템이 다루지 않으므로 기존 pipeline 의 공간 관리 로직 (`space_allocator`, `fit_verifier`, `slide_measurer`) 은 유지 필요.
**콘텐츠 분석은 매칭 시스템, 공간 관리는 기존 pipeline** 으로 책임 분리.
---
## 2. 영역 분리 — 3 가지
| 영역 | 무엇을 하나 | 누가 담당 |
|---|---|---|
| **A. 콘텐츠 분석 / 디자인 추천** | "이 MDX 콘텐츠에 어떤 디자인이 어울리나?" | **매칭 시스템 V1~V4 (신규)** |
| **B. 공간 관리 / 사이즈 조정** | "1280×720 안에 어떻게 끼워 넣나? overflow 안 나게?" | **기존 pipeline (유지)** |
| **C. HTML 생성 / 슬롯 채움** | "선택된 디자인에 MDX 텍스트를 어떻게 넣나?" | **기존 + V4 label 분기** |
### 핵심 원칙
- A 는 매칭 시스템으로 완전 대체 (AI 호출 줄임)
- B 는 절대 손대지 않음 (정밀한 공간 관리는 기존 로직이 검증됨)
- C 는 매칭 결과의 label 에 따라 분기 (코드 / AI 1회 / Sonnet 재구성)
---
## 3. 핵심 결정 사항 (확정)
### 3.1 처리 단위
```
MDX 1 파일 = 대목차 1개 = 슬라이드 1장
└ 중목차들 = 슬라이드 안의 frame 들 (조합)
└ 소목차들 = 더 작은 단위 frame 또는 슬롯
```
### 3.2 매칭 알고리즘 — 소→중→대 합치기 룰
```
[1단계] 모든 소목차에 V1~V4 매칭 시도
각 소목차의 best frame 도출
[2단계] 같은 중목차 내 소목차 매칭이 비슷하면 → 중목차로 묶어서 다시 매칭
더 큰 frame 단위로 합치기 가능한지 확인
[3단계] 중목차들이 비슷하면 → 대목차로 묶어서 매칭
슬라이드 1장 전체를 1 frame 으로 처리 가능한지 확인
→ 가장 적합한 합치기 단위 + frame 조합 채택
```
### 3.3 레이아웃 프리셋
기존 design_agent 의 4 가지 Type 으로 시작:
| 프리셋 | 조건 | 비고 |
|---|---|---|
| Type A | 참조 자료 (용어 정의 등) 별도 존재 | 기존 그대로 유지 (오답노트 #7) |
| Type B | 본문 흐름만 | 기존 그대로 |
| Type B' | 카드형 + 표 | 기존 그대로 |
| Type B'' | 색상바 + 여백 분리 | 기존 그대로 |
→ 4 개로 시작. 운영하면서 부족하면 추가.
### 3.4 V4 label 분기
매칭 결과의 label 이 후속 작업 비용을 결정:
| label | confidence | 후속 작업 | 비용 |
|---|---|---|---|
| use_as_is | ≥ 0.90 | 슬롯에 텍스트만 매핑 | 자동, AI 0회 |
| light_edit | ≥ 0.75 | AI 가 슬롯 텍스트 다듬기 | AI 1회 |
| restructure | ≥ 0.60 | 가장 유사 frame 참고 + Sonnet 변형 | 사람 + AI |
| reject | < 0.60 | 대안 frame 시도 → 그래도 안 되면 유사 frame 참고 | 사람 + AI |
### 3.5 자유 HTML 생성 금지
→ 항상 frame DB 의 어떤 frame 을 참고하여 생성. Phase R' 식 자유 디자인은 X.
### 3.6 텍스트 원문 보존 원칙 (절대 룰)
> **슬라이드 본문은 preview / 요약 가능하지만, MDX 원문은 popup / detail 에 무손실 보존한다.**
- 슬라이드 본문에 표시되는 것 = 일부 / 핵심 / preview 가능
- 단, 원문이 잘리거나 사라지지 않음 — 항상 팝업 / "자세히 보기" 에 무손실 저장
- "텍스트 압축 / trim / restructure" 같은 처리 금지 (오답노트 #5 준수)
- 안 들어가면 슬라이드를 키우는 게 아니라 → 본문은 preview, 팝업에 원문 보존
- AI 가 텍스트를 "줄여서 채워 넣지" 않는다 — preview 로 가공 후, 원문은 detail 에 보존
### 3.7 팝업 처리 룰
- MDX 에 팝업 콘텐츠 (`<details>`) 가 있으면 별도 보존
- 슬라이드 1장 룰 절대 유지 (2장으로 분리 X)
- 처리: **본문 요약 / 일부만 표시 + "자세히 보기" 클릭 → 팝업으로 전체**
- 전체를 팝업으로 빼는 것 X
- 팝업 콘텐츠도 MDX 원문 무손실 (3.6 원칙 적용)
---
## 4. 위계 + 용어 정리
### 4.1 슬라이드 위계
```
[ 슬라이드 ] 1280 × 720
├─ slide-title ← MDX 대목차 제목 (자동 매핑)
├─ slide-divider (고정)
├─ slide-body ≈ 1200 × 590 ─ ★ 여기에 콘텐츠
│ │
│ └─ 레이아웃 (Type A / B / B' / B'')
│ │
│ └─ Zone (top / bottom_l / bottom_r 등)
│ │
│ └─ 프레임 (Figma 디자인)
└─ slide-footer ← MDX 대목차 결론 (자동 매핑)
```
### 4.2 용어
| 용어 | 의미 | 단위 / 위치 |
|---|---|---|
| **슬라이드** | 1280×720 한 장 | 가장 큰 단위 |
| **slide-base** | 배경 + 제목 + 구분선 + 결론 pill (모든 슬라이드 공통 그릇) | `templates/blocks/slide-base.html` 고정 |
| **slide-body** | 본문 가용 영역 (≈ 1200×590) | slide-base 안 |
| **레이아웃 (Layout)** | Type A / B / B' / B'' (4 가지 프리셋) | slide-body 안 |
| **Zone (영역)** | 레이아웃이 결정한 콘텐츠 구역 (top / bottom 등) | 레이아웃 안 |
| **컨테이너 (Container)** | zone 의 px 명세 (코드 레벨 표현) | zone 의 구체화 |
| **프레임 (Frame)** | Figma 디자인 단위 (= 기존 "블록") | zone 안 |
### 4.3 MDX → 슬라이드 매핑
| MDX 위치 | 슬라이드 위치 |
|---|---|
| `# 대목차 제목` | `slide-title` |
| 본문 (`##` / `###` 중·소목차) | `slide-body` 안 — 레이아웃 / zone / 프레임 |
| `# 대목차 결론` (있을 시) | `slide-footer` |
| `<details>` 팝업 콘텐츠 | 슬라이드 위 별도 레이어 |
### 4.4 매칭 시스템 (V1~V4) 의 frame 단위 — 명확화
- 매칭 시스템에서 **frame 32 개를 슬라이드 1장 단위로 검증** 함 (예: Frame 18 = BIM/DX 비교 슬라이드 통째로)
- 새 흐름에서는 **frame = zone 안 디자인 단위**
- → frame DB 라벨링 재검토 필요 (사이즈 분류: "슬라이드 전체 / zone 1 개 / 작은 박스")
- 8.1 항목 (32 frame 사이즈 라벨링) 의 핵심 작업
---
## 5. 새 Pipeline Flow
```
═══════════════════════════════════════════════════════════════
[전처리 — 한 번만, 결과 캐싱]
═══════════════════════════════════════════════════════════════
T-0. Figma frame DB 구축
· 각 frame 의 키워드 (핵심/세트/연관) 라벨링 ✅ 완료
· 각 frame 의 구조 (layout, family, relation_type,
cardinality, content_affinity,
structure_intent, slots,
alternative_patterns) 라벨링 ✅ 완료
· 각 frame 의 사이즈 비율 (전체 / 절반 / 1/3 / 박스) ✅ 대체 완료 (Zone 적용 분류 — `docs/architecture/FRAME-INTEGRATION-MAP.md` 의 `zone_direct/adapt/extract/reference_only`)
· 각 frame 의 스타일 / 시각 언어 인벤토리 ✅ 완료 (`docs/architecture/PHASE-Z-FRAME-STYLE-INVENTORY.md`)
T-1. (새 frame 추가 시) 자동 라벨링 룰
· 새 Figma frame 입력 → V3 의 detect_mdx_v2_profile 로 자동 감지
· 사람이 검수 후 DB 추가
T-2. 레이아웃 프리셋 정의 (4 개)
· 각 프리셋의 grid / area 정의
· 어떤 frame 사이즈 조합에 어울리나 메타 정보
═══════════════════════════════════════════════════════════════
[실행 — MDX 1 파일 처리 = 슬라이드 1 장 생성]
═══════════════════════════════════════════════════════════════
STAGE 1) MDX 분석 + 레이아웃 매칭 [코드]
· MDX 정규화 + 외부 컴포넌트 인라인 (Phase Y)
· 팝업 콘텐츠 (<details>) 별도 보존
· 대 / 중 / 소목차 트리 추출
· 콘텐츠 성격 분석 (V3 의 detect_mdx_v2_profile)
· 4 가지 레이아웃 (Type A / B / B' / B'') 중 1 개 결정
· MDX 대목차 제목 → slide-title
· MDX 대목차 결론 → slide-footer
STAGE 2) Zone 별 텍스트 1 차 배치 [코드]
· 레이아웃이 결정한 zone 들에 콘텐츠 분배
· 어떤 중 / 소목차가 어떤 zone 에 갈지 결정
· 컨테이너 (zone 의 px) 계산 — space_allocator.py
STAGE 3) Zone 별 프레임 매칭 (V1~V4 매칭 시스템) [코드 + label 분기 AI]
┌──────────────────────────────────────────────┐
│ 각 zone 의 콘텐츠와 Figma 프레임 DB 매칭 │
│ V1 키워드 → V2 의미 → V3 구조 → V4 종합 판정 │
│ │
│ 매칭 결과 분기: │
│ ├ 매칭 완벽 (use_as_is) → 텍스트 업데이트 │
│ ├ 매칭 어정쩡 (light_edit │
│ │ / restructure) → 디자인 참고 │
│ │ 재구성 (Sonnet) │
│ └ 매칭 안 됨 (reject) → 디자인 컨셉 │
│ 바탕 재구성 │
│ │
│ 자유 디자인 금지 — 항상 프레임 DB 참고 │
└──────────────────────────────────────────────┘
STAGE 4) 프레임 내용 검토 + 컨테이너 조정 [코드 + AI fallback]
· zone 별 검증 (넘침 / 공란 / 적정 / 불균형)
· 보정:
├ 넘침 → 본문 미리보기 + "자세히 보기" 팝업
│ (MDX 원문 절대 줄이지 않음 — 3.6 원칙)
├ 공란 → MDX 팝업 콘텐츠 있으면 일부 끌어옴
├ 적정 → 그대로
└ 불균형 → 레이아웃 자체 부적절 → STAGE 1 회귀
(5 차 Fallback — 6 장 참조)
STAGE 5) HTML 조립 + 검증 + 출력 [코드 + AI]
· slide-base.html (배경 + 제목 + 구분선 + 결론 pill)
+ slide-body 안 (레이아웃 + zone + 프레임)
+ slide-title / slide-footer 채움
+ 팝업 레이어
· Jinja2 렌더링
· 실측 검증 (Selenium) — 넘침 차단
· 시각 검증 (Vision — Opus) — 품질 평가
· final.html 출력
```
---
## 6. 컨테이너 검증 + Fallback 룰 (STAGE 4 상세)
### 6.1 검증 케이스 분류
```
[모든 컨테이너 검증 결과 종합]
케이스 1) 모두 적정
→ 다음 단계 진행
케이스 2) 일부 Overflow + 나머지 적정
→ 본문 요약 + "자세히 보기" 팝업 처리
케이스 3) 일부 Underflow (특정 컨테이너만 공란) + 나머지 정상
❗ 레이아웃 잘못 → STAGE 1 회귀 (레이아웃 재선택)
케이스 4) 일부 Overflow + 일부 Underflow 동시
❗ 레이아웃 잘못 (불균형) → STAGE 1 회귀 (레이아웃 재선택)
케이스 5) 모두 Underflow + 채울 콘텐츠 없음
✅ 공란 허용 (콘텐츠 자체가 적은 슬라이드)
```
### 6.2 5 차 Fallback (불균형 검출 시)
```
[1차] 매칭 → 적합 프리셋 → 검증
OK → 종료
불균형 → 2차
[2차] 다른 프리셋 시도 (예: Type B → Type B')
또는 frame 합치기 단위 변경 (소→중 또는 중→대)
OK → 종료
불균형 → 3차
[3차] 매칭 결과 자체 변경 (Top-1 → Top-2 frame)
OK → 종료
불균형 → 4차
[4차] AI 콘텐츠 조정 의뢰 (Sonnet 1회)
현재 매칭된 frame / zone / container 는 유지한 채,
zone 안 콘텐츠 분량과 슬롯 매핑만 AI 로 조정한다.
· 긴 텍스트 → 본문 preview + 팝업 원문 분리 제안
· 슬롯 의미 매핑 미세 조정
· 불필요한 반복 표현을 preview 에서 정리
· 원문은 popup / detail 에 무손실 보존
⚠️ AI 는 zone 안 콘텐츠만 조정한다.
⚠️ 레이아웃 / 프리셋 / 새 frame 결정 / HTML 구조 생성은 코드만 수행한다.
OK → 종료
안 되면 → 5차
[5차] 단일 프리셋 강제 (Type A 또는 가장 큰 frame 만 사용)
나머지 콘텐츠 → "자세히 보기" 팝업
OK → 종료
그래도 안 되면 → 사람 개입 알림
```
### 6.3 Fallback 단계별 비율 추정
| 단계 | 종료 비율 (가설) | 비용 |
|---|---|---|
| 1차 | 80%+ | 낮음 (코드만) |
| 2~3차 | 15% | 낮음 (코드만) |
| 4차 (AI) | 4% | 중간 |
| 5차 (단일 + 팝업) | 1% 이하 | 낮음 |
| 사람 개입 | 매우 드물게 | 최후 수단 |
→ 실제 비율은 MDX 데이터로 검증 필요. 일단 가설.
---
## 7. 단계적 진행 계획
### Phase Z-0 — 매칭 시스템 (✅ 완료)
```
✅ V1~V4 매칭 시스템 구축
✅ 32 frame 키워드 + 구조 라벨링
✅ TARGET 3/4 정답
✅ 보고서 (DECK 1~7)
```
### Phase Z-1 사전 작업 — 진행 중
```
✅ 완료 (2026-04-28)
· Frame Integration Map (32 frame Zone 적용 분류)
→ docs/architecture/FRAME-INTEGRATION-MAP.md
· Frame Style Inventory (32 frame + 18 token + 6 legacy)
→ docs/architecture/PHASE-Z-FRAME-STYLE-INVENTORY.md
⬜ 미진행 (Phase Z-1 본격 진입 전)
· catalog / runtime 설계 prep
· slide-base 검증
⚠️ 미실행 / 의도적으로 보류 (승인 전)
· 기존 templates/blocks 삭제 / 교체
· catalog / runtime 구현
· templates/styles/frame-patterns 신규 파일 생성
· 새 token (gap_candidate) 추가
```
### Phase Z-1 — 통합 prototype (본격)
```
[목표] MDX 03 (회귀 기준) 으로 매칭 시스템 + 기존 pipeline 통합 검증
작업:
· Stage 1.7 (블록 선택) 만 V4 로 교체
· 32 frame ↔ Type B/B'/B'' 매핑 테이블 작성
· MDX 03 결과 기존과 비교 (회귀 통과)
완료 기준:
· MDX 03 기존 결과 대비 overflow 없음
· 텍스트 누락 없음 (MDX 원문 무손실 보존, 3.6 원칙)
· AI 호출 수 감소 (Stage 1.7 의 Kei 1회 제거)
· 옵션 플래그 off 시 동일 경로 복귀 (회귀 방지)
리스크: 낮음 (한 곳만 교체)
산출물: 매칭 시스템이 기존 pipeline 안에서 작동 확인
```
### Phase Z-2 — 매칭 + 프리셋 통합
```
[목표] Type A/B/B'/B'' 프리셋과 매칭 결과 연결
작업:
· 매칭 결과 → 4 프리셋 중 1 개 자동 선택 룰
· 합치기 룰 (소→중→대) 구현
· MDX 02, 01 적용 검증
완료 기준:
· MDX 03 / 02 / 01 모두 매칭 + 프리셋 자동 선택 작동
· 합치기 룰이 소목차 → 중목차 → 대목차 순서로 작동
· MDX 원문 무손실 유지 (3.6 원칙)
리스크: 중간
산출물: MDX 03/02/01 모두 매칭 + 프리셋 자동
```
### Phase Z-3 — 컨테이너 검증 + Fallback
```
[목표] 컨테이너 별 검증 + 5 차 Fallback 로직
작업:
· 불균형 검출 룰 (Overflow / Underflow / 동시)
· STAGE 4 의 1~5 차 Fallback 단계 구현
· 팝업 처리 룰 (안 들어가면 자세히 보기)
완료 기준:
· 컨테이너 별 검증 (Overflow / Underflow / 불균형) 작동
· Fallback 5 차 단계 작동 (각 단계 독립 검증)
· 팝업 처리 — preview 본문 + 무손실 팝업
리스크: 중간 ~ 높음
산출물: 안정적 자동 처리
```
### Phase Z-4 — 전체 통합 + 검증
```
[목표] 새 pipeline 으로 모든 MDX 처리 + 회귀 확인
작업:
· MDX 03 / 02 / 01 회귀
· Selenium + Vision 검증
· AI 호출 수 / 처리 시간 측정
완료 기준:
· MDX 03 / 02 / 01 모두 새 pipeline 통과
· Vision 품질 평가 합격
· AI 호출 수 / 처리 시간 기존 대비 감소
산출물: 새 pipeline 완성
```
---
## 8. 검토 / 결정 필요한 항목
### 8.1 32 frame 의 사이즈 라벨링
frame DB 에 "이 frame 은 슬라이드 전체 / 위 절반 / 좌측 1/3 / 작은 박스" 같은 사이즈 분류 필요.
| 옵션 | 방법 |
|---|---|
| (a) 사용자 직접 분류 | 정확하지만 시간 소요 |
| (b) Figma 캔버스 사이즈 자동 추정 | 빠르지만 부정확 가능 |
| (c) 매칭 시스템의 기존 라벨 (layout) 활용 + 보완 | 절충 |
**추천 (c)** : 기존 layout 라벨 (compare-rows / table-2col / cards-3col 등) 을 사이즈 라벨에 매핑하는 룰 작성.
### 8.2 프리셋 자동 선택 룰
frame 들의 사이즈 / 개수 → 4 프리셋 중 1 개 선택하는 룰.
예시:
- frame 1 개 + 사이즈 = 슬라이드 전체 → Type A 또는 Type B 단일
- frame 2 개 + 사이즈 = 위/아래 절반 → Type B (상단 + 하단)
- frame 2 개 + 사이즈 = 좌/우 절반 → Type A (사이드바)
### 8.3 합치기 룰 종료 조건
소→중→대 합치기 룰에서 어디까지 합칠지 결정:
- 소목차 매칭 결과가 "비슷" 하다는 기준은?
- 같은 frame_id ? 같은 layout family ? V4 axes 일부 일치 ?
### 8.4 슬롯 매핑 — 코드 + AI 하이브리드 비율
- 어디까지 코드 휴리스틱? (제목 → title 같은 명확한 것)
- 어디부터 AI? (의미 매핑 / 사이즈 조정 / 텍스트 다듬기)
---
## 9. 회귀 방지 / 안전 원칙
### 9.1 기존 작동 코드 보존
- **Type A 코드** (오답노트 #7) — 절대 건드리지 않음
- **공간 관리 로직** (`space_allocator`, `fit_verifier`, `slide_measurer`) — 그대로 유지
- **Phase Y 진행 중 작업** — MDX 외부 컴포넌트 처리 그대로
### 9.2 회귀 검증
- 단계마다 **MDX 03 (회귀 기준)** 결과 기존과 비교
- 변경 전 / 변경 후 다음 항목 측정:
- 최종 HTML 의 시각 결과 (스크린샷 비교)
- AI 호출 수
- 처리 시간
- overflow 발생 여부
### 9.3 옵션 플래그 도입
```
USE_MATCHING_SYSTEM = False # 기본값
```
- 새 기능은 플래그로 도입
- 문제 발생 시 즉시 기존 경로로 fallback
- 안정화 후 기본값 True
### 9.4 핵심 원칙 (오답노트.md 준수)
- **거짓말 금지** — 못 하면 못 한다고 명시
- **하드코딩 금지** — 결과물 고치지 말고 프로세스 고침
- **검증 없이 넘어가지 마라** — 단계마다 실측 + 회귀
- **텍스트 원문 무손실 보존** — 슬라이드 본문은 preview / 일부만 표시 가능, MDX 원문은 팝업 / detail 에 무손실 보존 (3.6 원칙)
- **프로세스 만들어라** — 매번 사고하여 판단 (AI 든 코드든)
---
## 10. 참고 문서
### 우선순위 — 충돌 시 어느 문서가 최신인가
**매칭 시스템 관련**:
- ✅ 최신 기준 = `tests/PIPELINE.md` (V1~V4 통합 정리)
- ⚠️ `tests/matching/CURRENT_STATUS.md` 등 옛 문서는 **과거 기록 (참조 X)**
- 옛 문서에 "V2/V3/V4 미완료" 로 적혀 있어도 무시. 실제는 모두 완료.
**design_agent 전체**:
- ✅ 최신 기준 = `PIPELINE.md` + 이 문서 (`IMPROVEMENT-REDESIGN.md`)
- ⚠️ `ARCHITECTURE_OVERVIEW.md`**deprecated** (2026-03-27 스냅샷, Type A/B 분기 등 미반영)
### 매칭 시스템 (V1~V4)
| 문서 | 위치 |
|---|---|
| 매칭 시스템 V1~V4 통합 정리 | `tests/PIPELINE.md` |
| 매칭 시스템 진행 / 약점 | `tests/PROGRESS.md` |
| 매칭 시스템 단계별 계획 | `tests/PLAN.md` |
| 매칭 시스템 코드 + 결과 + 보고서 | `tests/pipeline/` |
| 매칭 시스템 원본 (보존) | `tests/matching/` |
### 기존 design_agent
| 문서 | 위치 |
|---|---|
| 현재 pipeline 흐름 | `PIPELINE.md` |
| 전체 Phase 이력 | `PROGRESS.md` |
| 단계별 계획 | `PLAN.md` |
| 절대 원칙 | `오답노트.md` |
| 프로젝트 규칙 | `CLAUDE.md` |
| README | `README.md` |
### 보고서 (임원 보고용)
| 문서 | 위치 |
|---|---|
| DECK 1~7 (TARGET / Holdout / 방법 / DB / 키워드) | `tests/pipeline/reports/DECK_*.html` |
---
## 11. 리스크 + 대응 방안
설계안에서 실행계획으로 넘어갈 때 고려해야 할 리스크.
| # | 리스크 | 대응 방안 |
|---|---|---|
| 1 | **V4 가 디자인 적합성은 보지만 공간 적합성은 보지 않음** | 기존 공간 관리 (B 영역, `space_allocator` / `fit_verifier`) 그대로 유지. STAGE 4 컨테이너 검증으로 보완. V4 confidence 와 별개로 컨테이너 단위 overflow / underflow 측정 |
| 2 | **slot 의미 매핑 부재** (BIM → col_a_label 같은 매핑 없음) | STAGE 3 (zone 별 프레임 매칭) 의 슬롯 매핑에 AI 1회 호출 (Sonnet). 또는 frame DB 에 매핑 룰 사전 정의. 매칭 시스템의 slot 축 ablation 결과 — 이 영역은 별도 작업 필요 |
| 3 | **32 frame DB 의 사이즈 라벨 부족** | 8.1 항목 결정 후 라벨링 작업 (사용자 직접 또는 매칭 시스템의 layout 라벨 활용). Phase Z-1 시작 전 완료 필요 |
| 4 | **기존 Type B'/B'' 하드코딩 관성 재발 위험** | 4 프리셋 안에서만 조합. 새 콘텐츠별 전용 코드 절대 금지 (오답노트 #2). 새 변형 필요 시 — 코드 분기 추가 X, frame DB 또는 프리셋 추가로 해결 |
| 5 | **보고서용 매칭 성능 ≠ 실제 렌더 품질** | TARGET 3/4 정답률은 매칭 단독 성능. 실제 슬라이드 품질은 Phase Z-1 ~ Z-4 단계마다 MDX 03 실 렌더 + Vision 평가 회귀 |
| 6 | **MDX 분석 키워드 사전의 부정확성** (V3) | Hybrid 룰 — 코드 자동 + Kei fallback (신뢰도 낮을 때). 또는 추후 LLM 분석으로 교체 (`tests/PROGRESS.md` 의 Phase E.1, E.2) |
| 7 | **합치기 룰 (소→중→대) 무한 재시도 위험** | Fallback 5 차로 명확히 종료 (STAGE 4). 각 단계 최대 1 회 시도. 5 차 후엔 사람 개입 알림 |
| 8 | **매칭 시스템의 02-2.2 매칭 실패 사례** | 매칭 시스템 자체 약점 (`tests/PROGRESS.md` 약점 #1). Phase Z-1 진행 전 frame 14 의 anchor_sets 재라벨링 필요 (사전 작업) |
---
## 다음 단계
1. **이 문서 검토** — 사용자 + 협업자
2. **검토 사항 (7장) 결정** — 4 가지 항목
3. **리스크 대응 (11장) 사전 작업** — 32 frame 사이즈 라벨링 + frame 14 재라벨링
4. **Phase Z-1 시작** — 통합 prototype
5. **단계별 회귀 검증** — MDX 03 기준
+304
View File
@@ -0,0 +1,304 @@
# Design Agent 파이프라인 현황
> **최종 갱신:** 2026-04-13
> **목적:** 새 세션의 AI가 이 문서만 읽으면 파이프라인 전체를 이해하고 작업할 수 있도록 한다.
---
## 1. 전체 흐름 요약
```
MDX 입력
[Stage 0] MDX 정규화 (코드)
[Stage 1A] Kei 실장 — 꼭지 추출 (AI: Opus)
→ layout_template: A 또는 B 선택
[Stage 1B] 컨셉 구체화 (AI: Opus)
→ relation_type, expression_hint, source_data
[Stage 1B-ST] 구조화 텍스트 생성 (AI: Opus)
→ structured_text per topic
[Stage 1.5a] 컨테이너 계산 (코드: 결정론적)
→ FontHierarchy, ContainerSpec, Preset
[Stage 1.7] 블록 레퍼런스 선택 (코드 + AI 1회)
→ relation_type → 카테고리 → 필터 → 블록 결정
[Stage 1.8] 적합성 검증 + 보강 (코드 + Selenium + AI)
→ overflow 감지 → Kei 에스컬레이션 → 재배분
[Stage 1.5b] 디자인 예산 계산 (코드)
[Stage 2] HTML 생성 (Type에 따라 다름)
→ Type B/B'/B'': block_assembler (코드)
→ Type A: Sonnet 재구성 (AI, 미완성)
[Stage 3] 렌더링 조립 (Type A만, Jinja2)
[Stage 4] 검증 (Selenium + Opus Vision)
→ overflow 측정 + 스크린샷 품질 평가
최종 HTML 출력 (data/runs/{id}/final.html)
```
---
## 2. 레이아웃 유형 (Type A / B / B' / B'')
### 2.1 Kei가 선택하는 유형: A와 B
Kei 프롬프트(`src/kei_client.py:34-46`)에서 A 또는 B를 선택한다.
| 유형 | 조건 | Zone 구조 |
|------|------|-----------|
| **Type A** | 참조자료(용어 정의, 부록 등)가 별도로 존재 | body(배경+본심) + sidebar(첨부) + footer(결론) |
| **Type B** | 본문 흐름만. 배경/첨부가 없거나 억지로 만들어야 하면 | top + bottom_left + bottom_right + footer |
### 2.2 Type B 변형: B'과 B''
B'과 B''은 **Kei가 선택하지 않는다.** 특정 MDX 테스트 과정에서 하드코딩한 변형이다.
| 변형 | 생성 경위 | 차이점 | 코드 위치 |
|------|----------|--------|----------|
| **B** | 범용 | 상단(전체폭 텍스트+이미지) + 하단 2분할 + 결론 | `block_assembler.py:461` `_assemble_slide_html_type_b()` |
| **B'** | 03번 MDX 테스트 중 생성 | 상단이 세로 카드 형태 + 하단에 표 렌더링 + 불릿 전용 | `block_assembler.py:885` `_assemble_slide_html_type_b_prime()` |
| **B''** | B'에서 스타일 변형 | border/gradient 없음. 색상바+여백으로 구분 | `block_assembler_b2.py:9` `_assemble_slide_html_type_b_double_prime()` |
**분기 코드** (`block_assembler.py:370-378`):
```python
if ctx.analysis.layout_template == "B":
return _assemble_slide_html_type_b(ctx, title_text)
if ctx.analysis.layout_template == "B'":
return _assemble_slide_html_type_b_prime(ctx, title_text)
if ctx.analysis.layout_template == "B''":
return _assemble_slide_html_type_b_double_prime(ctx, title_text)
```
### 2.3 향후 방향
B'/B''은 **범용화가 필요하다.** 현재는 03번 콘텐츠 구조(카드형+표)를 B 조립 함수가 커버하지 못해서 만든 땜질이다. 궁극적으로는 B 하나로 다양한 콘텐츠 구조를 커버하거나, AI가 서브타입을 판단하게 해야 한다.
---
## 3. MDX 샘플 ↔ 유형 매핑
| MDX | 파일 | 콘텐츠 성격 | 선택 유형 | 상태 |
|-----|------|-----------|----------|------|
| **01번** | `samples/mdx/01. 건설산업 DX의 올바른 이해(0127).mdx` | 용어 혼용 문제 + 용어 정의(참조) | **Type A** | ⚠ Stage 2 미완성 (Sonnet 의존) |
| **02번** | `samples/mdx/02. DX의 시행 목표 및 기대효과.mdx` | 본문 흐름 (3대 목표) | **Type B** | ✅ 동작 |
| **03번** | `samples/mdx/03. DX 시행을 위한 필수 요건 및 혁신 방안.mdx` | 카드형 구조 + 표 + 불릿 | **Type B'** | ✅ 동작 (하드코딩) |
---
## 4. 단계별 상세
### Stage 0: MDX 정규화
- **파일:** `src/mdx_normalizer.py``normalize_mdx_content()`
- **입력:** raw MDX 텍스트
- **출력:** `NormalizedContent` (sections, images, tables 분리)
### Stage 1A: Kei 실장 — 꼭지 추출
- **파일:** `src/kei_client.py``classify_content()`
- **AI:** Opus (Kei API)
- **입력:** 정규화된 텍스트
- **출력:** `Analysis` (title, core_message, layout_template, total_pages, page_structure, topics)
- **핵심 판단:**
- 꼭지 5개 이내 추출
- 각 꼭지에 purpose, layer, role, emphasis, direction 부여
- layout_template = "A" 또는 "B" 선택
- page_structure에 역할별 weight(비중) 배정
### Stage 1B: 컨셉 구체화
- **파일:** `src/kei_client.py``refine_concepts()`
- **AI:** Opus
- **출력:** topics에 relation_type, expression_hint, source_data 추가
### Stage 1B-ST: 구조화 텍스트 생성
- **파일:** `src/kei_client.py``generate_structured_text()`
- **AI:** Opus
- **출력:** topic별 structured_text (마크다운 형태)
### Stage 1.5a: 컨테이너 계산 (결정론적)
- **파일:** `src/space_allocator.py`
- **함수:**
- Type A → `calculate_container_specs()`
- Type B/B'/B'' → `build_containers_type_b()`
- 공통 → `calculate_font_hierarchy()`, `select_preset()`
- **입력:** page_structure의 weight, slide 크기(1280×720)
- **출력:** 역할별 `ContainerSpec` (width_px, height_px, zone)
- **로직:** weight × available_px = 각 zone px 확정
### Stage 1.7: 블록 레퍼런스 선택
- **파일:** `src/block_reference.py``select_and_generate_references()`
- **로직 (코드 결정론적 + AI 1회):**
1. relation_type → 블록 카테고리 매핑
2. expression_hint 키워드 매칭
3. 컨테이너 크기 적합성 필터
4. role/zone 제약 (sidebar → visuals/media 제외)
5. catalog.yaml 존재 검증 (유령 블록 차단)
6. 후보 2-3개 → Kei 1회 호출로 최종 선택
- **출력:** 역할별 `BlockReference` (block_id, design_reference_html)
### Stage 1.8: 적합성 검증 + 보강
- **파일:** `src/fit_verifier.py``calculate_fit()`
- **로직:**
1. 텍스트 분량 vs 할당 공간 계산
2. Selenium으로 실제 높이 측정 (3회 루프)
3. overflow 시 → Kei 에스컬레이션 (`call_kei_fit_escalation()`)
- 팝업 분리 판단, zone 간 재배분
4. 보강 제안: bold 키워드, 팝업 요약 등
### Stage 2: HTML 생성
**Type B/B'/B'' (코드 조립):**
- **파일:** `src/block_assembler.py``assemble_slide_html()`
- 역할별 `assemble_role_html()` 호출 → 블록 HTML 조립
- structured_text + design_reference_html 결합
- 이미지/팝업 embed
- **즉시 완성 HTML 반환**
**Type A (AI 재구성, 미완성):**
- **파일:** `src/content_verifier.py``generate_with_retry()`
- Sonnet에 phase_t_context 전달 → CSS + 레이아웃 생성
- **현재 검증 불완전**
### Stage 3: 렌더링 조립 (Type A만)
- **파일:** `src/renderer.py``render_slide_from_html()`
- Type B는 Stage 2에서 완전한 HTML이므로 스킵
### Stage 4: 검증
- **파일:** `src/slide_measurer.py`
- `measure_rendered_heights()` — Selenium 실측
- `capture_slide_screenshot()` — 스크린샷 캡처
- **파일:** `src/kei_client.py``vision_quality_gate()`
- Opus 멀티모달: 스크린샷 보고 시각 품질 평가
---
## 5. 핵심 파일 맵
```
src/
├── main.py ← FastAPI 서버, POST /api/generate
├── pipeline.py ← 파이프라인 오케스트레이터 (generate_slide)
├── pipeline_context.py ← PipelineContext 데이터 클래스
├── config.py ← 설정 (API key, 슬라이드 크기)
├── mdx_normalizer.py ← Stage 0: MDX → NormalizedContent
├── kei_client.py ← Stage 1A/1B/1B-ST: Kei API 호출 + 프롬프트
├── space_allocator.py ← Stage 1.5a: 컨테이너 px 계산
├── block_reference.py ← Stage 1.7: 블록 선택 (relation_type 기반)
├── fit_verifier.py ← Stage 1.8: 적합성 검증 + Selenium 루프
├── block_assembler.py ← Stage 2: Type B/B' HTML 조립
├── block_assembler_b2.py ← Stage 2: Type B'' HTML 조립
├── content_verifier.py ← Stage 2: Type A HTML (Sonnet, 미완성)
├── renderer.py ← Stage 3: Jinja2 렌더링 (Type A만)
├── slide_measurer.py ← Stage 4: Selenium 측정 + 스크린샷
├── validators.py ← Kei 응답 검증 (A/B별 구조 확인)
├── image_utils.py ← 이미지 크기 측정 + data URI 변환
├── svg_calculator.py ← SVG 다이어그램 좌표 계산
└── sse_utils.py ← SSE 스트리밍 유틸
templates/
├── slide-base.html ← 슬라이드 기본 구조 (Jinja2, CSS Grid)
├── catalog.yaml ← 블록 라이브러리 정의 (50+개)
└── blocks/ ← 블록 HTML 템플릿
├── headers/ (8개)
├── cards/ (17개)
├── emphasis/ (12개)
├── tables/ (8개)
├── visuals/ (6개)
├── media/ (4개)
└── BEPs/ (6개)
```
---
## 6. 데이터 흐름 (PipelineContext)
```
PipelineContext:
raw_content ← 원본 MDX
normalized ← NormalizedContent (sections, images, tables)
analysis ← Analysis (title, core_message, layout_template, page_structure, topics)
topics ← list[Topic] (relation_type, expression_hint, structured_text 포함)
page_structure ← PageStructure (roles → {topic_ids, weight, zone})
containers ← dict[role → ContainerSpec(width_px, height_px)]
font_hierarchy ← FontHierarchy (key_msg, core, bg, sidebar 폰트 크기)
references ← dict[role → list[BlockReference]]
sub_layouts ← dict[role → SubLayout]
fit_result ← 역할별 fit_status, 재배분값
enhancement_result ← bold_keywords, popup_summaries 등
generated_html ← Stage 2 출력
rendered_html ← Stage 3 출력 (완전 HTML)
measurement ← Selenium 측정값
quality_score ← 0-100
```
---
## 7. 현재 구현 상태 (Phase Y-11~13, 2026-04-15)
> Phase Y: slide-base 기반 파이프라인 재설계. 상세: `docs/history/PHASE-Y-PLAN.md`
### 파이프라인 흐름 (현재)
```
[Stage 0] MDX → normalized.sections (source of truth)
[Stage 1A] Kei 꼭지 추출 (영역/zone 판단 안 함)
[Phase Y] 코드: normalized → 대목차 추출 → group schema 분류 → 블록 매칭 → 영역 확정
[Stage 1.5a] space_allocator: weight → zone px (% 기반)
[Stage 1.7] block_reference: tag_match → schema_match → fallback 순서
[Stage 1.8] assembler(measure_mode) → Selenium 측정 → fit 루프
[Stage 2] assembler(slide-base + 블록) → final HTML
[Stage 4] Selenium overflow + 비전 (-1 미평가)
```
### MDX별 상태
| MDX | 상태 | 비고 |
|-----|------|------|
| **03** | ✅ 동작 | prerequisites-3col + pp2. 텍스트 누락 없음. 회귀 기준. |
| **02** | ⚠ schema 1차 | top: parallel_3_with_image. bottom: 분류 정교화 필요. |
| **01** | ⬜ 미착수 | Type A. 별도 작업. |
### 핵심 원칙 (확립됨)
- source of truth = normalized.sections (Stage 0)
- 영역 = 코드가 결정 (Kei 아님). sub_titles 기반 + group schema.
- 블록 CSS에 최종 고정값. slide_font_css는 공통 레이아웃 계약만.
- zone = % 기반, block = height:100%.
- 글씨 크기 고정. fit은 padding → 내용량 → font 1단계(responsive tier).
- 기존 경로 삭제 금지. 새 schema 점진적 추가. MDX 03 회귀 기준.
- 하드코딩 금지. 프로세스가 결과를 만드는 구조.
3. **블록 글씨 크기 하드코딩 (px 고정)**
- 블록 CSS에 font-size가 Figma 원본 px로 고정
- 컨테이너 크기에 따라 조정 불가 → overflow 원인
- CSS 변수(`var(--block-font-heading)`)로 전환 → assembler가 zone 크기에 따라 계산
### 미해결 프로세스
1. **overflow 시 font 조정 루프** — 재배분만으로 부족할 때 font/padding 줄이기 (Y-5)
2. **Sonnet redesign 경로** — tag 매칭 실패 시 블록 단위 redesign → 저장 (Y-6)
---
## 8. 검증 계획
업데이트된 템플릿이 파이프라인에서 제대로 동작하는지 확인한다.
| MDX | 유형 | 검증 포인트 |
|-----|------|-----------|
| **01번** | Type A | 업데이트된 블록 + slide-base.html로 조립 정상 동작 |
| **02번** | Type B | 업데이트된 블록 선택 + 조립 + overflow 없음 |
| **03번** | Type B' | 카드/표 구조가 업데이트된 템플릿으로 정상 렌더링 |
### 검증 방법
1. 각 MDX를 파이프라인에 투입
2. 중간 산출물(step1_analysis.json 등) 확인 — 블록 선택이 의도대로인지
3. 최종 HTML(final.html) 렌더링 — overflow, 시각 품질 확인
4. 업데이트 전/후 비교
+510
View File
@@ -0,0 +1,510 @@
# Design Agent — 실행 계획
## Phase 1: 기반 구축
### DA-1: 프로젝트 셋업
- **파일:** pyproject.toml, .env, .gitignore
- **내용:** Python 환경, 의존성 정의, 환경 변수
- **의존성:** 없음
- **완료 기준:** `pip install -e .` 성공
### DA-2: FastAPI 서버 기본 구조
- **파일:** src/main.py, src/config.py
- **내용:** FastAPI 앱, CORS, health endpoint, 설정 관리
- **의존성:** DA-1
- **완료 기준:** `uvicorn src.main:app --reload` 정상 시작, `/api/health` 200 반환
### DA-3: 디자인 토큰 + 기본 CSS
- **파일:** static/tokens.css, static/base.css
- **내용:** CLAUDE.md에 정의된 디자인 토큰을 CSS 변수로 구현, Pretendard 폰트 설정, 16:9 슬라이드 컨테이너
- **의존성:** 없음
- **완료 기준:** 빈 슬라이드가 16:9 비율로 렌더링, Pretendard 폰트 적용 확인
---
## Phase 2: 블록 템플릿 제작
### DA-4: 블록 템플릿 — 비교 (comparison)
- **파일:** templates/blocks/comparison.html
- **내용:** 2단 병렬 레이아웃, Jinja2 슬롯 ({{left_title}}, {{left_content}}, {{right_title}}, {{right_content}})
- **의존성:** DA-3
- **완료 기준:** 더미 데이터로 렌더링 시 2단 비교 표시, 디자인 토큰 적용
### DA-5: 블록 템플릿 — 카드 그리드 (card-grid)
- **파일:** templates/blocks/card-grid.html
- **내용:** 2~4열 카드 배열, Jinja2 슬롯 ({{cards[n].icon}}, {{cards[n].title}}, {{cards[n].description}})
- **의존성:** DA-3
- **완료 기준:** 3개 카드 렌더링, 카드 수에 따라 자동 배열
### DA-6: 블록 템플릿 — 관계도 (relationship)
- **파일:** templates/blocks/relationship.html
- **내용:** 벤 다이어그램 (CSS 원형), Jinja2 슬롯 ({{center}}, {{items[n]}})
- **의존성:** DA-3
- **완료 기준:** 3원 벤 다이어그램 렌더링, 라벨 표시
### DA-7: 블록 템플릿 — 프로세스 (process)
- **파일:** templates/blocks/process.html
- **내용:** 가로 단계 흐름, Jinja2 슬롯 ({{steps[n].number}}, {{steps[n].title}}, {{steps[n].description}})
- **의존성:** DA-3
- **완료 기준:** 4단계 프로세스 렌더링, 연결선 표시
### DA-8: 블록 템플릿 — 강조 인용 (quote-block)
- **파일:** templates/blocks/quote-block.html
- **내용:** 배경색 + 좌측 라인 + 인용 텍스트, Jinja2 슬롯 ({{quote_text}}, {{source}})
- **의존성:** DA-3
- **완료 기준:** 인용 블록 렌더링, 강조 스타일 적용
### DA-9: 블록 템플릿 — 결론 바 (conclusion-bar)
- **파일:** templates/blocks/conclusion-bar.html
- **내용:** 하단 전체 폭 강조 영역, Jinja2 슬롯 ({{conclusion_text}})
- **의존성:** DA-3
- **완료 기준:** 결론 바 렌더링, 강조 색상 적용
### DA-10: 블록 템플릿 — 비교 테이블 (comparison-table)
- **파일:** templates/blocks/comparison-table.html
- **내용:** 다항목 비교 테이블, Jinja2 슬롯 ({{headers}}, {{rows}})
- **의존성:** DA-3
- **완료 기준:** 5행 3열 테이블 렌더링
### DA-11: 슬라이드 조합 렌더러
- **파일:** src/renderer.py, templates/slide-base.html
- **내용:** Jinja2로 블록 조합 → HTML 생성. grid-template-areas로 블록 배치. 다중 페이지 지원.
- **다중 페이지:** `.slide` div 여러 개 + `page-break-after: always` (인쇄 시 페이지 분리)
- **의존성:** DA-4 ~ DA-10
- **완료 기준:** JSON 블록 배치 명세 → 완성 HTML 출력 (1페이지 또는 다중 페이지)
---
## Phase 3: AI 파이프라인 연결
### DA-12: 1단계 — Kei 실장 (꼭지 추출 + 분석)
- **파일:** src/kei_client.py
- **내용:** 본문에서 핵심 꼭지 추출 + 다단계 분석
- 꼭지 추출: 본문에서 2~5개 핵심 파트 식별 (1페이지 적정: 5개)
- 페이지 분리: 5개 초과 + 레이어 동등 → 2페이지 (의미 기반 분할 2/3, 3/4 등)
- 5개 + 내용 많음 → 세부 내용은 자세히보기 대상
- 레이어 수준: 각 꼭지가 도입/핵심/보조/결론 중 어디인지
- 강조 판단: 어떤 꼭지를 시각적으로 눈에 띄게 할 것인가
- 배치 방향: 세로로 긴 꼭지, 가로로 나열할 꼭지 판단
- 이미지 판단: 몇 개, 어떤 꼭지 소속, 핵심/보조, 텍스트 포함 여부
- 표 판단: 행/열 규모, 전체 표시 가능 여부
- 상세 콘텐츠 판단: 자세히보기 대상 식별
- **기술:** Anthropic API (Sonnet)
- **의존성:** DA-2
- **완료 기준:** 꼭지 목록 + 레이어 + 강조 + 배치 + 이미지/표/상세 판단 JSON
### DA-13a: 2단계 Step A — 레이아웃 프리셋 선택 (규칙 기반)
- **파일:** src/design_director.py (`select_preset()` 함수)
- **내용:** 실장의 role 분석을 보고 레이아웃 프리셋을 자동 선택
- reference 꼭지 있음 → `sidebar-right` (65:35)
- 모든 flow가 대등 비교 → `two-column` (50:50)
- 고강조 1개 + 나머지 보조 → `hero-detail`
- 나머지 → `single-column`
- **기술:** Python 규칙 코드 (LLM 불필요)
- **의존성:** DA-12
- **완료 기준:** 프리셋 이름 + CSS grid 반환
### DA-13b: 2단계 Step B — 프리셋 내 블록 매핑 (Sonnet)
- **파일:** src/design_director.py
- **내용:** 선택된 프리셋의 zone에 꼭지를 배정 + 블록 타입 선택 + 글자 수 가이드
- 프롬프트에 선택된 프리셋의 CSS grid가 포함됨
- flow 꼭지 → body/main zone
- reference 꼭지 → sidebar zone
- detail_target → popup 연결
- catalog에서 블록 타입 선택
- 이미지/표 배치 판단
- **기술:** Anthropic API (Sonnet) + Pillow
- **의존성:** DA-13a
- **완료 기준:** zone별 블록 배정 + 글자 수 가이드 JSON
### DA-13c: 3단계 — Kei 텍스트 편집자 (텍스트 정리)
- **파일:** src/content_editor.py
- **내용:** 팀장의 글자 수 가이드 참고하되 내용 의미 우선
- 전체 컨텍스트와 핵심 용어 유지
- 세련된 표현으로 편집 (의미 > 글자 수)
- 출처 보존, 개조식, 날조 금지
- 표 내용 편집 (핵심 행/열 선택, 요약)
- 자세히보기 대상: 요약 버전 + 상세 버전 둘 다 작성
- **기술:** Anthropic API (Sonnet)
- **의존성:** DA-13b
- **완료 기준:** 슬롯별 텍스트 JSON. 핵심 용어 보존. 자세히보기 포함.
### DA-14: 4단계 — 디자인 실무자 (디자인 조정 + HTML 조립) + 5단계 재검토
- **파일:** src/pipeline.py, src/renderer.py
- **내용:**
- 4단계 (AI + 코드): 편집자 텍스트에 맞게 디자인 조정 (폰트/여백/박스 — 텍스트 자르지 않음)
+ Jinja2 HTML 조립, 이미지 object-fit:contain, 표 container query, `<details>` 접기, 인쇄 펼침 JS
- 5단계 (AI): 팀장이 전체 균형 재검토 → 채움 비율, 블록 균형, 이미지/표 크기 점검 → 2차 조정
- **기술:** Anthropic API Sonnet (디자인 조정 + 재검토) + Jinja2/CSS (조립)
- **의존성:** DA-11, DA-12, DA-13a, DA-13b, DA-13c
- **완료 기준:** 텍스트 입력 → 균형 잡힌 슬라이드 HTML (이미지/표/자세히보기 포함, 재검토 완료)
---
## Phase 4: UI + 출력
### DA-15: 프론트엔드 — 콘텐츠 입력 + 미리보기
- **파일:** static/index.html (별도 HTML 파일), main.py (FileResponse로 서빙)
- **내용:** 텍스트 입력 영역 + iframe 미리보기 + HTML 다운로드 버튼
- **기술:** FileResponse (FastAPI 내장), fetch API + 수동 SSE 파싱
- **의존성:** DA-14
- **완료 기준:** 텍스트 붙여넣기 → 슬라이드 미리보기 표시 + HTML 다운로드
- **주의:** HTML/JS를 Python 문자열에 넣지 않는다 (이스케이프 충돌 방지)
---
## 버그 수정
### BF-2: 블록 내용 비어있음 (렌더러 Jinja2 include 문제)
- **파일:** src/renderer.py, templates/slide-base.html
- **내용:** `include` → 블록별 개별 `render()` 후 HTML 삽입
- **기술:** Jinja2 `get_template().render()` (내장)
- **의존성:** 없음 (기존 코드 수정만)
- **완료 기준:** 콘텐츠 입력 → 슬라이드에 텍스트가 표시됨
### BF-3: 한글 깨짐 (다운로드 파일)
- **파일:** static/index.html
- **내용:** download() Blob에 UTF-8 BOM 추가
- **기술:** JavaScript `'\uFEFF'` 1줄
- **의존성:** 없음
- **완료 기준:** 다운로드한 HTML 파일에서 한글 정상 표시
### BF-4: body 블록 겹침 (같은 area에 여러 div)
- **파일:** src/renderer.py
- **내용:** 같은 area의 블록을 하나의 div로 그룹핑 (OrderedDict + flex-column)
- **기술:** Python OrderedDict (내장)
- **의존성:** BF-5 (area명 통일 선행)
- **완료 기준:** body에 4개 블록이 세로로 쌓여서 보임 (겹침 없음)
- **상태:** 코드 수정 완료, md 반영 중
### BF-5: 제목 안 보임 (area명 불일치)
- **파일:** src/design_director.py (LAYOUT_PRESETS)
- **내용:** 프리셋 4개의 area명 `title``header`로 통일 (slide-base.html이 `header` 사용)
- **기술:** 문자열 교체
- **의존성:** 없음
- **완료 기준:** 슬라이드에 제목이 표시됨
- **상태:** sidebar-right 프리셋 수정 완료, 나머지 3개 확인 필요
### BF-6: sidebar 카드 3열 찢어짐
- **파일:** src/design_director.py (STEP_B_PROMPT)
- **내용:** 팀장 Step B 프롬프트에 "sidebar zone은 전체 너비의 35%로 좁다. card-grid 배치 시 카드 열 수를 공간에 맞게 판단하라" 추가
- **기술:** 프롬프트 엔지니어링
- **의존성:** 없음
- **완료 기준:** sidebar의 카드가 1열 세로로 배치됨
- **상태:** 미수정
### BF-7: body 블록 텍스트 비어있음 (content_editor 매칭 오류)
- **파일:** src/content_editor.py
- **내용:** 같은 area에 여러 블록이 있을 때 첫 번째만 매칭되는 문제. `break` 제거 + area+topic_id로 정확 매칭. 편집자 프롬프트 출력 형식에 `topic_id` 추가.
- **기술:** Python 조건문 수정
- **의존성:** 없음
- **완료 기준:** body의 모든 블록에 텍스트가 채워짐
- **상태:** 미수정
### BF-8: 컨테이너 예산 기반 블록 배치 (프레임 넘침 방지)
- **파일:** src/design_director.py, templates/catalog.yaml, static/base.css, templates/blocks/visuals/*.html
- **내용:**
- 근본 원인: 팀장이 콘텐츠 중심으로 블록 선택 → 높이 고려 없이 body에 4개 블록 쌓음 → 720px 초과 → overflow:hidden으로 잘림
- 해결: 컨테이너(zone) 크기 예산을 먼저 확인하고, 예산 안에서 블록을 선택하는 사고 순서로 전환
- LAYOUT_PRESETS: zone별 budget_px + width_pct 추가
- STEP_B_PROMPT: 4단계 사고 순서 (컨테이너 확인→배정→블록 선택+높이 계산→검증)
- catalog.yaml: 블록별 height_cost 추가 (compact ~70px / medium ~150px / large ~200px / xlarge ~400px)
- base.css: area 컨테이너에 overflow:hidden + min-height:0 안전망
- 시각화 블록 CSS: flex-shrink + responsive SVG
- **기술:** 프롬프트 엔지니어링 + CSS 안전망
- **의존성:** 없음
- **완료 기준:** body 영역 블록이 720px 프레임 안에 모두 보임. 넘침 없음.
- **한계:** 프롬프트만으로는 Sonnet이 grid를 무시하는 문제를 방지할 수 없음 → BF-9 필요
### BF-9: grid와 Sonnet의 역할 분리 (설계 수정)
- **파일:** src/design_director.py
- **내용:**
- 설계 오류: Step B에서 Sonnet에게 grid 값을 출력하라고 요구 → Sonnet이 자기만의 grid를 생성해버림
- 근본 원인: grid는 코드(Step A)가 결정하는 것인데 Sonnet에게 에코를 요구한 것 자체가 잘못
- 해결:
- Step B 프롬프트에서 grid 출력 요구 제거. Sonnet은 `blocks` 배열만 출력
- `create_layout_concept()`에서 grid 값은 프리셋에서 직접 가져옴 (Sonnet 출력 무시)
- Sonnet이 출력한 area명이 프리셋 zone에 없으면 가장 가까운 zone으로 코드 매핑
- 원칙: **코드가 결정한 것은 코드가 유지한다. Sonnet은 콘텐츠 판단만.**
- **기술:** Python 코드 수정 + 프롬프트 출력 형식 변경
- **의존성:** BF-8 (프리셋에 zone 정보 필요)
- **완료 기준:** Sonnet 출력에 grid 값이 없음. 최종 HTML의 grid는 항상 프리셋과 100% 일치.
### BF-10: _CATALOG_MAP 캐시 갱신 문제
- **파일:** src/renderer.py
- **내용:**
- 현상: catalog.yaml을 수정해도 서버 재시작 전까지 구 매핑 유지 → _legacy 블록 로드
- 근본 원인: _CATALOG_MAP이 모듈 레벨 global로 한 번만 로드됨
- 해결: reload 옵션 (--reload 시 자동 갱신) 또는 매 요청마다 파일 mtime 확인 후 reload
- **기술:** Python pathlib stat() (내장)
- **의존성:** 없음
- **완료 기준:** catalog.yaml 수정 → 서버 재시작 없이 새 매핑 적용
### DA-16: 통합 테스트
- **파일:** tests/test_pipeline.py, tests/test_renderer.py
- **내용:** 전체 파이프라인 테스트 + 블록 렌더링 테스트
- **의존성:** BF-2, BF-3, BF-4, BF-5, BF-6, BF-7
- **완료 기준:** 테스트 전체 통과
---
---
## Phase 5: 블록 라이브러리 확장
### DA-17: Figma 에셋 추출 + 블록 템플릿 제작
- **상태:** done
- **산출물:**
- Figma 스크린샷 16장 (`docs/figma-screenshots/`)
- Figma 에셋 15개+ (`docs/figma-assets/`)
- 신규 블록 템플릿 6종 (`templates/blocks/` 카테고리별)
- 디자인 분석 보고서 (`docs/figma-analysis/DESIGN-ANALYSIS.md`)
- 블록 인덱스 (`templates/blocks/INDEX.md`)
- **완료 기준:** 신규 블록 6개 독립 렌더링 테스트 통과, Figma 톤 반영
### DA-18: 블록 라이브러리 카테고리 재편
- **상태:** done
- **내용:** 플랫 구조 → 6개 카테고리 폴더 (headers, cards, tables, visuals, emphasis, media)
- **완료 기준:** INDEX.md에 전체 구조 정리, 기존 루트 파일 정리
### DA-19: 변형 확장
- **상태:** done (46개 달성)
- **산출물:** 46개 블록 (6 카테고리), catalog.yaml 46개, BLOCK_SLOTS 46개 동기화
- **완료 기준:** ✅ 달성
---
## Phase 2: 파이프라인 고도화 (상세: docs/PHASE2-PLAN.md, PHASE2-PROCESS.md)
### P2-A: FAISS 블록 검색 인덱스
- **파일:** `src/block_search.py` (신규), `scripts/build_block_index.py` (신규), `src/design_director.py` (수정)
- **내용:** catalog 전문 → FAISS 검색으로 관련 블록 5~8개만 프롬프트에 전달
- **기술:** BAAI/bge-m3 + faiss-cpu (Kei persona와 동일 패턴)
- **의존성:** 없음
- **완료 기준:** 꼭지별 검색 → 카테고리별 최소 1개 보장 → 프롬프트 토큰 절약
### P2-B: SVG N개 자동 배치
- **파일:** `src/svg_calculator.py` (신규), `src/renderer.py` (수정), `templates/blocks/visuals/venn-diagram.html` (수정)
- **내용:** venn-diagram 3개 고정 → N개(2~7) cos/sin 자동 계산
- **기술:** Python math (내장, 추가 의존성 없음)
- **의존성:** 없음 (2-A와 병렬 가능)
- **완료 기준:** N=2~7 각각 렌더링 테스트 통과. Phase 1 fallback 유지.
### P2-C: Step A Opus+FAISS 고도화
- **파일:** `src/design_director.py` (수정)
- **내용:** 규칙 4줄 → Opus(Kei API)가 FAISS 후보에서 블록 선정 + 배치 결정
- **기술:** Kei API 호출 (Opus). anthropic 직접 호출 **절대 금지**.
- **의존성:** P2-A 완료 필수
- **완료 기준:** Opus가 콘텐츠 보고 블록 후보 선정. Kei API 실패 시 기존 방식 fallback.
### P2-D: 5단계 재검토 강화
- **파일:** `src/pipeline.py` (수정)
- **내용:** shrink/rewrite action 구현 + 재조정 루프 (MAX=2)
- **기술:** Anthropic API (Sonnet) — 기존 패턴
- **의존성:** 없음 (병렬 가능)
- **완료 기준:** expand/shrink/rewrite 3개 action 모두 동작. 루프 2회 제한.
### P2-E: 누락 기능
- **E-1 Pillow:** `src/design_director.py` — 이미지 크기 읽기 → 블록 선택 참고
- **E-2 details-block:** `src/design_director.py` + `src/pipeline.py` — detail_target → details-block 배치
- **의존성:** 없음 (병렬 가능)
- **완료 기준:** 이미지 크기 정보가 팀장에게 전달. details 접기/펼치기 동작.
### 의존 관계
```
P2-A (FAISS) ──────────────────────┐
├→ P2-C (Opus+FAISS)
P2-B (SVG N개) ── 병렬 │
P2-D (재검토) ─── 병렬 │
P2-E (누락기능) ── 병렬 │
```
### DA-21: renderer 카테고리 경로 지원
- **상태:** todo
- **내용:** `renderer.py`의 블록 로드 경로를 `blocks/{type}.html``blocks/{category}/{name}.html`로 변경
- **주의:** 기존 파이프라인과 호환성 유지
- **의존성:** DA-18
- **완료 기준:** 카테고리 경로로 블록 렌더링 정상 동작
### DA-22: catalog.yaml 경로 업데이트
- **상태:** todo
- **내용:** template 경로를 새 폴더 구조로 반영
- **의존성:** DA-21
- **완료 기준:** catalog.yaml의 모든 template 경로가 실제 파일과 일치
---
## Phase V: 콘텐츠-컨테이너 적합성 검증 + Kei 에스컬레이션 (상세: PHASE-V.md)
> 근거: Phase T' 디버깅에서 발견된 구조적 결함. 콘텐츠 분량과 무관한 컨테이너 고정 배분, 적합성 검증 부재, 판단 주체 부재.
### V-1: Stage 1.7 수정 — 꼭지별 블록 선택
- **현재:** 영역당 블록 1개 → **변경:** 꼭지당 블록 1개
- **파일:** `src/block_reference.py`, `src/pipeline.py`
- **의존성:** 없음
- **완료 기준:** 배경 꼭지2개 → 블록2개 선택
### V-2: Stage 1.8 신규 — 적합성 검증
- **파일:** `src/fit_verifier.py` (신규)
- **내용:** 꼭지별 필요 높이 계산 → 컨테이너 배분 → 들어가는지 검증
- **의존성:** V-1
- **완료 기준:** 배경 117px 부족 자동 감지
### V-3: Stage 1.8 재배분 로직
- **파일:** `src/fit_verifier.py`
- **내용:** 여유 영역 → 부족 영역으로 공간 재분배
- **의존성:** V-2
- **완료 기준:** 배경 117→151px, 본심 345→311px 자동 재배분
### V-4: Stage 1.8 Kei 에스컬레이션
- **파일:** `src/fit_verifier.py`, `src/kei_client.py`
- **내용:** 재배분으로도 안 될 때 AI가 옵션 생성 → Kei에게 결정 요청
- **의존성:** V-2, V-3
- **완료 기준:** Kei에게 옵션 전달 → 결정 수신 → 파이프라인 계속
### V-5: Stage 1.5a 리팩터
- **파일:** `src/space_allocator.py`, `src/pipeline.py`
- **내용:** weight 고정 배분 → 콘텐츠 분량 기반 동적 배분으로 교체
- **의존성:** V-2
- **완료 기준:** weight 하드코딩 제거
### V-6: 통합 검증 — ✅ 완료 (31/31 통과, 하드코딩 0개)
### V-7: 주종 관계 블록 내 종속 꼭지 처리
- **파일:** `src/fit_verifier.py`, `src/block_reference.py`
- **내용:** 종속 꼭지 분량에 따라 인라인/하위블록/보조블록 자동 판단 → Kei 확인
- **완료 기준:** 배경 꼭지2(supporting)가 꼭지1 블록 안에 인라인
### V-8: 여유 공간 콘텐츠 보충
- **파일:** `src/fit_verifier.py`
- **내용:** 재배분 후 여유 감지 → 관련 팝업 구조화 콘텐츠 → 요약 블록 추가 제안 → Kei 확인
- **완료 기준:** 본심 여유 공간에 비교표 핵심 요약 배치
### V-9: 영역 핵심 결론 강조 블록
- **파일:** `src/fit_verifier.py`, `src/block_reference.py`
- **내용:** purpose에서 핵심 결론 추출 → 강조 블록 제안 → Kei 확인
- **완료 기준:** 배경 "체계적 정립 필요"가 강조 블록으로 표시
### V-10: 텍스트 핵심 키워드 bold
- **파일:** `src/html_generator.py`
- **내용:** source_data 핵심 키워드 추출 → Stage 2 프롬프트에 전달 → Sonnet이 bold 처리
- **완료 기준:** 본심 "상위개념", "기술융합" 등 핵심 키워드 bold
---
## Phase Y: MDX 외부 컴포넌트 인라인 삽입
> 근거: MDX에서 `import ... from '*.astro'`로 불러오는 외부 컴포넌트(표, 다이어그램 등)가 파이프라인에서 누락됨. import문은 제거되고 `<DxEffect />` 같은 태그는 사라져서 콘텐츠 손실 발생.
### Y-1: import문 파싱 — 컴포넌트명:파일경로 매핑
- **파일:** `src/mdx_normalizer.py`
- **내용:** `import Foo from '../../components/foo.astro'``{"Foo": 절대경로}` 매핑 추출
- **의존성:** base_path (MDX 원본 파일 위치, pipeline.py에서 전달)
- **완료 기준:** import문에서 컴포넌트명→절대경로 dict 반환
### Y-2: .astro 파일 파싱 — HTML + CSS 추출
- **파일:** `src/mdx_normalizer.py`
- **내용:** .astro 파일에서 `---` frontmatter 제거, HTML 본문 + `<style>` 블록 추출
- **의존성:** Y-1
- **완료 기준:** dx.astro → `<div class="table-wrapper">...</div>` + `<style>...</style>` 반환
### Y-3: 셀프클로징 태그 교체 — 인라인 삽입
- **파일:** `src/mdx_normalizer.py`
- **내용:** `<DxEffect />` 태그를 Y-2에서 추출한 HTML+CSS로 교체
- **의존성:** Y-1, Y-2
- **완료 기준:** MDX 정규화 결과에 외부 컴포넌트 HTML이 인라인으로 포함
### Y-4: Astro 특수 문법 정리
- **파일:** `src/mdx_normalizer.py`
- **내용:** Astro의 멀티라인 태그(`<td class="category-cell">텍스트</td>` 줄바꿈 패턴), `style="letter-spacing: -0.9px"` 등 인라인 스타일 정리
- **의존성:** Y-2
- **완료 기준:** 추출된 HTML이 브라우저에서 정상 렌더링
---
## 의존 관계
```
Phase 1~2 (기반+블록):
DA-1 → DA-2, DA-3 → DA-4~DA-10 → DA-11(렌더러)
Phase 3 (AI 파이프라인):
DA-12(실장) → DA-13(팀장) → DA-13b(편집자) → DA-14(조립+재검토)
Phase 4 (UI):
DA-14 → DA-15(프론트엔드) → DA-16(테스트)
Phase 5 (블록 라이브러리):
DA-17(Figma추출) → DA-18(카테고리재편) → DA-19(변형확장) → DA-20(FAISS)
DA-18 → DA-21(renderer경로) → DA-22(catalog경로)
Phase V (적합성 검증):
V-1(꼭지별블록) → V-2(적합성검증) → V-3(재배분) → V-4(Kei에스컬레이션)
V-2 → V-5(1.5a리팩터)
V-1~V-5 → V-6(통합검증)
```
- Phase 1~2, 5: AI 없이 진행 가능
- Phase 3: Anthropic API 필요 (5단계 파이프라인)
- Phase 5는 Phase 3와 **병렬** 진행 가능
---
## Phase Z: 매칭 시스템 통합 (2026-04-28 ~)
> **상세 설계**: [IMPROVEMENT-REDESIGN.md](IMPROVEMENT-REDESIGN.md)
>
> 별도 검증된 매칭 시스템 (V1~V4, `tests/matching/`) 을 기존 pipeline 에 통합.
### 단계적 진행
| 단계 | 내용 | 산출물 |
|---|---|---|
| **Phase Z-1** | 통합 prototype — Stage 1.7 (블록 선택) 만 V4 로 교체 | MDX 03 회귀 통과 |
| **Phase Z-2** | 매칭 + 4 프리셋 (Type A/B/B'/B'') 통합 | MDX 03/02/01 자동 매칭 |
| **Phase Z-3** | 컨테이너 검증 + 5 차 Fallback | 안정적 자동 처리 |
| **Phase Z-4** | 전체 통합 + 회귀 검증 | 새 pipeline 완성 |
### 사전 결정 사항 (검토 완료)
- **위계** : slide → slide-base → slide-body → 레이아웃 → Zone → 프레임
- **5 단계 흐름** : MDX 분석/레이아웃 → Zone 텍스트 배치 → 프레임 매칭 → 검토 → 출력
- **매칭 분기** : 완벽 / 어정쩡 / 안 됨 → 후속 작업 차등
- **레이아웃 프리셋** : Type A / B / B' / B'' (기존 4 가지 활용)
- **절대 룰** : 텍스트 원문 무손실, 자유 디자인 금지, MDX 1 = 슬라이드 1
### 사전 작업 진행 상태
**완료** (2026-04-28)
- 32 frame Zone 적용 분류 (`zone_direct` / `zone_adapt` / `zone_extract` / `reference_only`) — [docs/architecture/FRAME-INTEGRATION-MAP.md](docs/architecture/FRAME-INTEGRATION-MAP.md)
- Frame / Style Inventory (32 frame + 18 token + 6 legacy) — [docs/architecture/PHASE-Z-FRAME-STYLE-INVENTORY.md](docs/architecture/PHASE-Z-FRAME-STYLE-INVENTORY.md)
**미진행**
- catalog / runtime 설계 prep
- slide-base 검증
⚠️ **미실행 / 의도적으로 보류** (승인 전)
- 기존 `templates/blocks/` 삭제 / 교체
- catalog / runtime 구현
- `templates/styles/frame-patterns/` 신규 파일 생성
- 새 token (`gap_candidate`) 추가
- legacy structures 6 파일 삭제
> ⚠️ **Phase Z-1 자체는 진행 중**. 위 ✅ 는 *사전 작업 중 일부* 완료 표시.
---
## 기술 스택
| 역할 | 도구 | 비고 |
|------|------|------|
| 서버 | FastAPI + uvicorn | 포트 8001 |
| 템플릿 엔진 | Jinja2 | 카테고리별 블록 조합 |
| 렌더링 | CSS Grid + 디자인 토큰 | 슬라이드 + 웹 |
| 한국어 폰트 | Pretendard Variable | word-break: keep-all |
| AI (5단계) | Anthropic API (Sonnet) | 실장→팀장→편집자→실무자→재검토 |
| 이미지 생성 | Gemini API | 복합 시각화 배경 (레이어 방식) |
| Figma | Figma REST API + Framelink MCP | 에셋 추출 |
| 변형 검색 | FAISS (향후) | 블록 40개+ 시 |
| 테스트 | pytest | 렌더링 + 파이프라인 |
File diff suppressed because one or more lines are too long
+338
View File
@@ -0,0 +1,338 @@
# Design Agent — 진행 상황
## 현재 상태 요약 (2026-04-01 기준)
| 상태 | 내용 |
|------|------|
| **완료** | Phase 1~5 기반, A~Q 개선, R(실패), S(설계), **T 전체 완료** |
| **Phase T 결과** | 11 Step 완료 (T-0~T-10). 통합 테스트 31/31 통과. 신규 5파일, 수정 4파일+yaml |
| **다음** | 실제 MDX + Kei API + Sonnet API로 end-to-end 실행. Phase ZZ는 파이프라인 안정화 이후 |
---
## ✅ 완성된 것
### 파이프라인 핵심
- 5단계 파이프라인 작동 (1A→1B→컨테이너계산→A-2→블록스펙→3→4→측정→5)
- Kei API 무한 재시도 (모든 Kei 호출. fallback 없음. 제한 없음)
- Step B(Sonnet 블록 매핑) 제거 — Kei(A-2) + 코드(Phase O)로 대체
- 죽은 코드 전면 정리 (STEP_B_PROMPT, _fallback_layout, PURPOSE_FALLBACK, DOWNGRADE_MAP, _downgrade_fallback, _apply_defaults, manual_classify)
### 블록/카탈로그
- 블록 라이브러리 38개 (6 카테고리)
- catalog.yaml 개선 완료 (when/not_for/purpose_fit)
- FAISS 인덱스 재빌드 완료 (bge-m3, 38블록)
- topic_id/id 양쪽 체크 버그 수정
### 레이아웃
- 프리셋 자동 선택 (sidebar-right, two-column, hero-detail, single-column)
- Kei 비중 시스템 (page_structure weight — 콘텐츠마다 동적)
- Phase O 컨테이너 스펙 계산 (calculate_container_specs)
- Phase O 블록 스펙 확정 (finalize_block_specs)
- 비중 기반 grid row 컨테이너 (renderer.py)
### 측정/검수
- Phase L Selenium 렌더링 측정 (scrollHeight/clientHeight)
- Phase N-4 스크린샷 캡처 (slide.screenshot_as_base64)
- Stage 5 Opus 멀티모달 검수
### 인프라
- 중간 산출물 추적 (data/runs/{timestamp}/)
- 실행 리포트 생성 (scripts/generate_run_report.py)
- SSE 스트리밍 유틸 (sse_utils.py)
- 이미지 크기 측정 + base64 삽입 (image_utils.py)
### 버그 수정 완료
- BF-1~BF-10: 전부 수정 완료 (SSE 파싱, Jinja2 변수, 한글, body 겹침, 제목, topic_id, 예산, grid, catalog 캐시)
---
## ✅ Phase P 실행 완료 + 결과 분석 (2026-03-27~28)
### 실행 결과
- **실행 데이터:** `data/runs/1774599277829/`
- **최종 슬라이드 품질:** 20/100점
### 발견된 근본 문제 5가지
| # | 근본 원인 | 증상 |
|---|----------|------|
| R1 | FAISS 텍스트 임베딩이 시각 블록을 매칭하지 못함 | "hierarchy" 관계인데 venn 대신 comparison-2col 선택 |
| R2 | Opus 추천에 catalog 검증 없음 | 존재하지 않는 블록 5개 환각 (arrow-flow, hierarchy-tree 등) |
| R3 | overflow 해소 실패 시 출력 차단 없음 | 배경 117px에 330px 콘텐츠 → 겹침 상태로 출력 |
| R4 | 블록 중복 사용 제한 없음 | 5개 topic에 3종류 블록만 사용 (38개 중 7.9%) |
| R5 | 공간 배분이 일방향 | 배경 20%에 topic 2개 강제 → card-numbered(205px)가 컨테이너(117px)에 안 맞음 |
### Phase P 접근법의 구조적 한계
- 3후보 × 5topics = **15번 렌더링 + 15번 AI 호출 → ~40분 소요**
- 15개 중 10개 폐기 (작업의 2/3 낭비)
- 업계 조사 결과, **다후보 렌더링 비교 방식은 어떤 상용/오픈소스 도구도 사용하지 않음**
- 블록 유형 선택은 **렌더링 전에 결정할 수 있는 문제** (콘텐츠 relation_type 기반)
### 업계 조사 결과 (2026-03-28)
| 접근법 | 대표 사례 | 핵심 원리 |
|--------|----------|----------|
| 제약 기반 레이아웃 엔진 | Beautiful.ai | AI는 콘텐츠만, 레이아웃은 규칙 엔진이 결정론적으로 |
| 템플릿 검색 + AI 커스터마이징 | Canva | 벡터 검색으로 템플릿 매칭, AI가 텍스트/색상만 교체 |
| NLP 관계 유형 → 시각화 매핑 | Napkin.ai | 계층/비교/프로세스 감지 → 다이어그램 유형 자동 선택 |
| 시각적 자기교정 | VASCAR (2024) | 생성→렌더링→비전 모델 평가→개선, 훈련 불필요 |
| 참조 기반 학습 | PPTAgent (EMNLP 2025) | 기존 프레젠테이션에서 디자인 패턴 귀납적 학습 |
**업계 합의:** AI가 레이아웃을 직접 결정하면 안 된다. AI는 콘텐츠만, 레이아웃은 제약 엔진이 담당.
---
## 📋 Phase Q: 제약 기반 블록 선택 + 글자수 예산 시스템 (설계 확정)
**상세:** [IMPROVEMENT-PHASE-Q.md](IMPROVEMENT-PHASE-Q.md)
**핵심 원칙:** "계산 먼저, AI 판단 나중에, 렌더링은 검증만"
### 실행 스텝
| 스텝 | 내용 | 유형 | 파일 | 의존성 | 상태 |
|------|------|------|------|--------|------|
| Q-1 | catalog.yaml 메타데이터 보강 (min_height_px, relation_types, category, min/max_items) | 데이터 | `templates/catalog.yaml` | ✅ 완료 |
| Q-2 | relation_type → 블록 카테고리 결정론적 매핑 엔진 | 신규 | `src/block_selector.py` | ✅ 완료 |
| Q-3 | 글자수 예산 계산 엔진 | 추가 | `src/space_allocator.py` | ✅ 완료 |
| Q-4 | Kei 블록 선택 프롬프트 재설계 (필터링된 2-3개만 제시) | 수정 | `src/kei_client.py` | ✅ 완료 |
| Q-5 | pipeline.py 재구성 (Phase P 15-render → Phase Q 단일 경로) | 수정 | `src/pipeline.py` | ✅ 완료 |
| Q-6 | 비전 모델 품질 게이트 (VASCAR식) | 신규 | `src/kei_client.py` | ✅ 완료 |
| Q-7 | overflow 수학적 조정 (LaTeX 글루 모델) | 추가 | `src/space_allocator.py` | ✅ 완료 |
| Q-8 | 출력 차단 정책 + P0 재시도 제한 (30회/300초) | 추가 | `src/pipeline.py` | ✅ 완료 |
### 기대 효과
| 지표 | Phase P | Phase Q 목표 |
|------|---------|-------------|
| 슬라이드 품질 | 20/100 | 70-80/100 |
| 처리 시간 | ~40분 | ~8-12분 |
| API 호출 | ~25회 | ~8회 |
| 유령 블록 | 5건 발생 | 불가능 |
| overflow 출력 | 허용 | 차단 |
---
## Phase 이력
| Phase | 내용 | 상태 | 비고 |
|-------|------|------|------|
| 1~3 | 기반 구축 + 블록 템플릿 + AI 파이프라인 | 완료 | |
| 4 | UI + 출력 | 완료 | |
| 5 | 블록 라이브러리 확장 (38개) | 완료 | |
| A~D | 슬라이드 품질 핵심 | 완료 | 일부 Phase O로 대체 |
| G | Kei API 통신 정상화 | 완료 | |
| H | 스토리라인 설계 기반 전환 | 완료 | |
| I | 전수 정합성 복구 (14건) | 완료 | |
| J | 블록 선택 권한 재정의 | 완료 | Step B 제거로 일부 무력화 |
| K | purpose 기반 시각적 위계 | 완료 | |
| K-1 | 중간 산출물 저장 | 완료 | |
| L | Selenium 렌더링 측정 | 완료 | |
| M | Kei 비중 시스템 | 완료 | Phase O로 교체 |
| N | 4대 핵심 문제 해결 | 완료 | |
| **O** | **컨테이너 기반 레이아웃** | **완료** | 코드 + 미해결 3건 해결 + Step B 제거 |
| **P** | **다후보 렌더링 비교 선택** | **완료** | 실행됨. 결과 20/100점 → Phase Q로 방향 전환 |
| **Q** | **제약 기반 블록 선택 + 글자수 예산** | **코드 완료** | Q-1~Q-8 구현 + fill_candidates 복원. 블록 선택 개선 확인 |
| **R** | **하이브리드 블록 시스템 (variant 추가)** | **실패** | 기존 블록 선택 구조 위에 패치만 추가. P=Q=R 동일 구조. |
| **R'** | **접근 C: 블록 CSS 참고 + AI 구조 결정** | **설계** | 방향만 확정. Kei API HTML 생성 실패 확인. |
| **S** | **검증 기반 확정 — Claude HTML 생성 + 검증된 프롬프트 규칙** | **설계 확정** | 영역별 검증 합격. Claude Sonnet 확정. |
| **T** | **폰트 위계 + 파이프라인 기반 정비 + 디자인 레퍼런스** | **완료** | 11 Step 완료. 통합 테스트 31/31 통과. |
---
## ❌ Phase R 실패 기록
Phase R은 접근 C로 가기로 합의했으나, 구현에서 기존 블록 선택 시스템 위에 variant 패치만 추가.
**P = Q = R: 세 개 다 "블록 선택 → 슬롯 채우기" 근본 구조가 동일.**
결과물 34점. C_reference.png(70점) 수준에 전혀 도달 못함.
근본 원인: 기존 코드(block_selector, catalog, fill_candidates)를 유지하면서 최소 변경으로 해결하려는 관성.
---
## 📋 Phase R': 접근 C — 블록 CSS 참고 + AI 구조 결정 (설계 확정)
> ⚠️ **Legacy — Phase Z 로 대체됨 (2026-04-28)**
>
> Phase R' 의 "AI 가 HTML 구조를 직접 생성" 흐름은 Phase Z 에서 다음과 같이 변경됨:
> - **HTML 구조** = `slide-base.html` + 코드 (Jinja2) 가 결정 (AI 가 생성하지 않음)
> - **AI 의 역할** = zone 안의 콘텐츠 / 텍스트 매핑 / 텍스트 다듬기 / 디자인 변형만
> - **자유 디자인 금지** — 항상 Figma 프레임 DB 참고
>
> 아래 R' 설계 내용은 히스토리 / 참고용. 실제 구현은 [`IMPROVEMENT-REDESIGN.md`](IMPROVEMENT-REDESIGN.md) 의 5 단계 흐름 따름.
**상세:** [IMPROVEMENT-PHASE-R-PRIME.md](IMPROVEMENT-PHASE-R-PRIME.md)
### 핵심 전환
```
P=Q=R (실패): 블록이 구조를 결정 → 콘텐츠를 슬롯에 채움
R' (접근 C): 콘텐츠가 구조를 결정 → 블록 CSS를 참고하여 HTML 생성
```
### 프로세스 변경
> ⚠️ **아래 표는 폐기된 Phase R' 기록이며 신규 구현 지시가 아니다.** 새 구현은 [IMPROVEMENT-REDESIGN.md](IMPROVEMENT-REDESIGN.md) 의 Phase Z 5 단계 흐름 따름.
| 단계 | 현재 (P=Q=R) | R' (접근 C) |
|------|-------------|------------|
| 1단계 Kei 분석 | 유지 | 유지 |
| 1.5단계 컨셉 구체화 | 유지 | 유지 |
| 컨테이너 계산 | 유지 | 유지 |
| 프리셋 선택 | 유지 | 유지 |
| **2단계** | block_selector → 블록 선택 | **제거** → html_generator가 AI HTML 생성 |
| **3단계** | fill_candidates → 슬롯 채우기 | **제거** → html_generator에 통합 |
| 4단계 렌더링 | render_slide (블록 템플릿) | render_slide_from_html (AI HTML 삽입) |
| 검증 | Selenium + 비전 모델 | 유지 |
### 실행 스텝
| 스텝 | 내용 | 파일 | 상태 |
|------|------|------|------|
| R'-1 | 디자인 토큰 + 블록 CSS 패턴을 프롬프트용 텍스트로 추출 | 신규 `src/design_tokens.py` | 대기 |
| R'-2 | few-shot 예시 슬라이드 정리 | `data/examples/` | 대기 |
| R'-3 | AI HTML 생성 함수 구현 | 신규 `src/html_generator.py` | 대기 |
| R'-4 | pipeline.py 2-3단계 교체 (블록 선택+채우기 → html_generator) | `src/pipeline.py` | 대기 |
| R'-5 | 렌더러에 AI HTML 삽입 함수 추가 | `src/renderer.py` | 대기 |
| R'-6 | HTML 정화 + 토큰 위반 검증 | 신규 `src/html_validator.py` | 대기 |
| R'-7 | 테스트 (2개 콘텐츠) | `scripts/test_phase_r_prime.py` | 대기 |
### 회귀 방지 — 호출하면 안 되는 함수
- `select_block_candidates()` — 블록 선택 회귀
- `fill_candidates()` / `fill_content()` — 슬롯 채우기 회귀
- `select_block_for_topics()` — 블록 선택 AI 회귀
- `finalize_block_specs()` — 블록 스펙 회귀
### 합격 기준
C_reference.png와 동일 수준의 결과를 **자동으로** 생성:
- topic 합침 가능
- 포함 관계 시각화 가능
- 핵심 메시지 별도 강조 가능
- 원본 텍스트 보존 (자유도 15-20)
- 720px overflow 없음
---
## Phase R' 이후 방향
- 디자인 참조 DB 구축 → 성공한 슬라이드를 few-shot으로 축적
- Playwright 마이그레이션 → 더 빠른 측정 + PDF 내보내기
---
## Phase Z: 매칭 시스템 통합 설계 (2026-04-28)
### 배경
별도 검증한 매칭 시스템 (V1~V4) 을 기존 design_agent pipeline 에 통합하기 위한 설계.
**매칭 시스템 (`tests/matching/`) 검증 결과**:
- V1 키워드 매칭 (Logistic Regression 가중치, TARGET 4/4 LOOCV 검증)
- V2 의미 매칭 (ko-sroberta cosine)
- V3 구조 매칭 (layout / content_affinity / structure_intent)
- V4 종합 판정 (5축 + 라벨)
- TARGET 정답률 3/4 (75%), BM25 / IDF 보다 우위
- V4 slot 축 ablation: Top-1 매칭 7/7 동일 (slot 축 frame 선별 무영향)
### 설계 결정 사항
**위계 + 용어 정리** :
```
[ slide ] 1280×720
├─ slide-title ← MDX 대목차 제목
├─ slide-divider (고정)
├─ slide-body ≈ 1200×590 ← 콘텐츠 영역
│ └─ 레이아웃 (Type A/B/B'/B'')
│ └─ Zone (top/bottom_l/bottom_r 등)
│ └─ 프레임 (Figma 디자인 단위)
└─ slide-footer ← MDX 대목차 결론
```
**5 단계 새 흐름**:
1. STAGE 1 — MDX 분석 + 레이아웃 매칭 (Type A/B/B'/B'')
2. STAGE 2 — Zone 별 텍스트 1차 배치
3. STAGE 3 — Zone 별 프레임 매칭 (완벽 / 어정쩡 / 안 됨 분기)
4. STAGE 4 — 프레임 검토 + 컨테이너 조정 (5 차 Fallback)
5. STAGE 5 — HTML 조립 + 검증 + 출력
**핵심 원칙**:
- MDX 1 파일 = 대목차 1 개 = 슬라이드 1 장
- 텍스트 원문 무손실 보존 (본문 미리보기 + 팝업 원문)
- 자유 디자인 금지 (항상 Figma 프레임 DB 참고)
- 불일치 시 레이아웃 회귀 (콘텐츠 줄이지 않고 그릇 변경)
### 산출물 (이번 세션)
| 파일 | 용도 |
|---|---|
| [`IMPROVEMENT-REDESIGN.md`](IMPROVEMENT-REDESIGN.md) | 매칭 시스템 통합 설계 문서 (전체 명세) |
| [`PROCESS_OVERVIEW.html`](PROCESS_OVERVIEW.html) | 임원 보고용 A4 2 페이지 (프로세스 + 구조도) |
| [`tests/PIPELINE.md`](tests/PIPELINE.md) | V1~V4 통합 정리 + frame 단위 명확화 |
| [`tests/pipeline/`](tests/pipeline/) | 매칭 시스템 코드 + 결과 + 보고서 (분류 복사본) |
### 다음 단계 (구현)
`IMPROVEMENT-REDESIGN.md`**단계적 진행 계획** 참조.
- **Phase Z-1**: 통합 prototype (MDX 03 회귀 통과)
- **Phase Z-2**: 매칭 + 프리셋 통합
- **Phase Z-3**: 컨테이너 검증 + Fallback
- **Phase Z-4**: 전체 통합 + 검증
### 발견된 약점 (8가지) — Phase Z 진행 시 대응
`IMPROVEMENT-REDESIGN.md` 11 장 (리스크) + `tests/PROGRESS.md` 약점 표 참조.
핵심 :
- 02-2.2 매칭 실패 (Frame 14 anchor 재라벨링 필요)
- 32 frame DB 사이즈 라벨링 부족 (zone 단위 vs 슬라이드 단위)
- slot 의미 매핑 부재
- V3 콘텐츠 성격 분류 부정확 (키워드 사전 한계)
---
## Phase Z-1 사전 작업 진행 (2026-04-28)
> **Phase Z-1 자체는 진행 중**. 본 entry 는 사전 작업 중 **Frame / Style Inventory 완료** 만 기록.
### ✅ 완료 — Frame / Style Inventory (사전 작업 일부)
| 산출 | 위치 | 내용 |
|---|---|---|
| Frame Integration Map | [`docs/architecture/FRAME-INTEGRATION-MAP.md`](docs/architecture/FRAME-INTEGRATION-MAP.md) | 32 frame Zone 적용 분류 (`zone_direct` / `zone_adapt` / `zone_extract` / `reference_only`). row 21~28 Figma ID 정정. 1171281171 부록 처리 |
| Frame Style Inventory | [`docs/architecture/PHASE-Z-FRAME-STYLE-INVENTORY.md`](docs/architecture/PHASE-Z-FRAME-STYLE-INVENTORY.md) | 32 frame (변환 14 + 미변환 18) + Token 18 행 (covered 7 / gap 5 / hierarchy 3 / hold 3) + Legacy 6 행 |
### ⬜ 다음 — Phase Z-2 본격 (catalog / runtime 설계)
- Phase Z-1 의 catalog / runtime 설계 prep 부분 (slide-base 검증 등) 은 미진행
- Phase Z-2 본격 (매칭 + 4 프리셋 통합) 도 미진행
### ⚠️ 미실행 / 의도적으로 보류
- 기존 `templates/blocks/` 삭제 / 교체 실행
- catalog / runtime 구현
- `templates/styles/frame-patterns/` 신규 파일 생성
- `templates/styles/tokens/``gap_candidate` token 추가
- legacy structures 6 파일 삭제
→ 모두 **승인 전 보류**. Frame / Style Inventory 는 추출 / 검증 단계이고, 실제 변경은 별도 승인 단계.
---
## 프로젝트 구조
| 항목 | 파일 | 상태 |
|------|------|------|
| 프로젝트 규칙 | CLAUDE.md | Phase Z 반영 (2026-04-28) |
| 개선 계획 (이전) | IMPROVEMENT.md | Phase R' 반영 |
| **개선 계획 (신규)** | **IMPROVEMENT-REDESIGN.md** | **Phase Z 매칭 시스템 통합 (2026-04-28)** |
| 임원 보고용 | PROCESS_OVERVIEW.html | Phase Z 흐름 반영 |
| 진행 추적 | PROGRESS.md | 이 파일 (2026-04-28 갱신) |
| 전체 감사 | CLEANUP-AUDIT.md | 유효/무력화 분류 완료 |
| Phase별 상세 | IMPROVEMENT-PHASE-{A~R'}.md | 각 Phase 기록 |
| Phase R 실패 기록 | IMPROVEMENT-PHASE-R.md | 블록 선택 위에 variant 패치 — 실패 |
| Phase R' 설계 | IMPROVEMENT-PHASE-R-PRIME.md | 접근 C 기반 재설계 |
| 매칭 시스템 (별도 검증) | tests/PIPELINE.md + tests/pipeline/ | V1~V4 검증 완료 (2026-04-27) |
| README | README.md | Phase Z 반영 |
+269
View File
@@ -0,0 +1,269 @@
# Design Agent / C.E.L Slide Automation
## 1. 프로젝트 개요
MDX 문서를 입력받아 1280×720 프레젠테이션 슬라이드 HTML 로 자동 변환하는 파이프라인입니다.
- **입력**: MDX 파일 (텍스트 + 표 + 불릿 + JSX 블록 + details + 이미지)
- **변환 흐름**: V4 매칭 → Phase Z 렌더 파이프라인
- **출력**: `final.html` (단일 슬라이드) + 단계별 산출물 (의사결정 추적)
- **최종 목표**: 파이프라인 + AI 보정 + DB / 카탈로그 + 프론트엔드 에디터가 연결된 *제품형* 시스템
### 핵심 용어 (처음 보는 분 위해)
| 용어 | 의미 |
|---|---|
| **MDX** | 마크다운 + JSX 컴포넌트 결합 형식. 슬라이드의 *원본 콘텐츠* |
| **Figma BEPs frame** | 디자인 원천. 32 개의 Figma 프레임을 HTML / CSS 로 변환해 `figma_to_html_agent/blocks/` 에 누적 |
| **V4** | MDX 섹션 ↔ Figma 프레임 매칭 시스템 (네 번째 버전). 콘텐츠 의미 / 구조 / 키워드 / 카디널리티 등 5 개 축으로 점수화. `tests/matching/v4_full32_result.yaml` 에 결과 저장 |
| **Phase Z** | 현재 활성 렌더 파이프라인. V4 매칭 결과를 받아 슬라이드 HTML 로 만듦 |
| **프레임 (Frame)** | Figma 디자인 단위. 1 개의 슬라이드 영역(zone) 안에 들어감 |
| **Internal Region** | zone 내부의 콘텐츠 배치 단위 (text 영역, table 영역, image 영역 등) |
| **Frame Slot** | frame 내부의 콘텐츠 자리 (예: pillar_1, quadrant_1, process_column) |
### 위계
```
Slide → Zone → Internal Region → Frame → Frame Slot → Content
```
---
## 2. 전체 실행 구조 (22 단계 파이프라인)
22 단계를 3 개 블록으로 묶어 운영합니다:
- **블록 A — 렌더 전 계획 (Step 0~12)**: 모든 의사결정. 가장 중요한 영역.
- **블록 B — 렌더 (Step 13)**: Jinja2 + 프레임 partial → final.html.
- **블록 C — 렌더 후 점검 / 예외 처리 (Step 14~22)**: 시각 검증 + 필요 시 재시도. *블록 A 가 정밀하면 거의 동작 안 함*.
```mermaid
flowchart TD
Input([MDX 입력])
subgraph BlockA["블록 A — 렌더 전 계획 (Step 0~12)"]
S0["Step 0<br/>사전 준비<br/><sub>카탈로그 / 컨트랙트 / V4 결과</sub>"]
S1["Step 1<br/>MDX 업로드"]
S2["Step 2<br/>MDX 정규화<br/><sub>frontmatter / 목차 / 푸터 분리</sub>"]
S3["Step 3<br/>콘텐츠 객체 추출<br/><sub>텍스트 / 표 / 이미지 / details</sub>"]
S4["Step 4<br/>섹션 내부 구성 계획<br/><sub>전체 / 묶기 / 분할</sub>"]
S5["Step 5<br/>V4 매칭 후보 추출<br/><sub>거절 제외 최대 6 개</sub>"]
S6["Step 6<br/>구성 계획<br/><sub>어떤 섹션 묶음 = 한 zone</sub>"]
S7["Step 7<br/>슬라이드 레이아웃 계획<br/><sub>8 개 프리셋 중 선택</sub>"]
S8["Step 8<br/>Zone / Region 비율 계획"]
S9["Step 9<br/>적용 계획<br/><sub>V4 후보를 어떻게 넣을지 번역</sub>"]
S10["Step 10<br/>프레임 컨트랙트 확인"]
S11["Step 11<br/>콘텐츠 → Region → Frame Slot 매핑"]
S12["Step 12<br/>슬롯 데이터 생성"]
end
subgraph BlockB["블록 B — 렌더 (Step 13)"]
S13["Step 13<br/>HTML 렌더<br/><sub>Jinja2 + 프레임 partial → final.html</sub>"]
end
subgraph BlockC["블록 C — 렌더 후 점검 / 예외 처리 (Step 14~22)"]
S14["Step 14<br/>시각 점검<br/><sub>Selenium 으로 실제 렌더 검사</sub>"]
S15["Step 15<br/>문제 분류<br/><sub>오버플로우 / 잘림 / 비율 어긋남</sub>"]
S16["Step 16<br/>재시도 라우터<br/><sub>어떤 조치를 할지 선택</sub>"]
S17["Step 17<br/>조치 실행<br/><sub>zone 비율 재시도 / 팝업 전환 / ...</sub>"]
S18["Step 18<br/>실패 분류"]
S19["Step 19<br/>다음 조치 제안"]
S20["Step 20<br/>슬라이드 상태 결정<br/><sub>PASS / 시각 회귀 / ...</sub>"]
S21["Step 21<br/>디버그 / 추적 기록"]
S22["Step 22<br/>사용자 확인 / 내보내기"]
end
Visual{"시각 점검 OK?"}
Repair{"수정 방식?"}
AI["AI 보정 / 재구성<br/><i>(향후 예정)</i>"]
Input --> S0 --> S1 --> S2 --> S3 --> S4 --> S5
S5 --> S6 --> S7 --> S8 --> S9 --> S10 --> S11 --> S12
S12 --> S13 --> S14 --> Visual
Visual -->|예| S20 --> S21 --> S22
Visual -->|아니오| S15 --> S16 --> S17 --> S18 --> S19 --> Repair
Repair -->|결정론적<br/>zone 재시도 / 팝업 / 레이아웃 조정| S13
Repair -->|AI 필요<br/>재구성 / 점수 낮음 / 반복 오버플로우| AI
AI --> S13
classDef plan fill:#e7f5ff,stroke:#1971c2,color:#000
classDef render fill:#fff3cd,stroke:#f59f00,color:#000
classDef check fill:#f3f0ff,stroke:#7048e8,color:#000
classDef decision fill:#ffd8a8,stroke:#d9480f,color:#000
classDef future fill:#f8f9fa,stroke:#868e96,color:#000,stroke-dasharray: 5 5
class S0,S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,S12 plan
class S13 render
class S14,S15,S16,S17,S18,S19,S20,S21,S22 check
class Visual,Repair decision
class AI future
```
각 단계의 자세한 진행 상태는 [`PHASE-Z-PIPELINE-STATUS-BOARD.md`](docs/architecture/PHASE-Z-PIPELINE-STATUS-BOARD.md) 가 단일 출처입니다 (자주 갱신됨).
---
## 3. 현재 완료 수준
### 3.1 MDX03 정상 경로 — 통과
기준 샘플 (`samples/mdx_batch/03.mdx`) 의 자동 렌더 경로가 정상으로 닫혔습니다.
```
overall : PASS
visual_check_passed : true
full_mdx_coverage : true
adapter_needed_count : 0
content_truncated_count: 0
units : 03-1 → F13 (그대로 사용 가능, 0.927)
03-2 → F29 (그대로 사용 가능, 0.920)
```
### 3.2 22 단계 진행 수준
전체 약 **65~70%**. MDX03 정상 경로는 닫혔고, 일반화 (다른 MDX / 예외 케이스 / 재시도 / UI) 는 진행 중.
상세 ✅ / ⚠ / ❌ 표는 [`PHASE-Z-PIPELINE-STATUS-BOARD.md`](docs/architecture/PHASE-Z-PIPELINE-STATUS-BOARD.md) 에서 확인.
### 3.3 검증 / 실험 저장소 성격
본 저장소는 *제품형 시스템* 까지 가는 과정에서 다음 샘플을 *검증 재료* 로 사용:
- `samples/mdx_batch/03.mdx` — 기준 샘플 (정상 경로 확인)
- `samples/mdx_batch/04.mdx` — 다음 검증 예정
- `samples/mdx/01. ...mdx` / `02. ...mdx` — 향후 검증
**샘플 MDX 는 로드맵 단계가 아니라 22 단계 파이프라인을 보완하기 위한 검증 재료입니다.**
### 3.4 결정 변경 이력
설계 변경 / 폐기된 안 / 일치 정정의 시간 순 기록은 [`PHASE-Z-CHANGE-LOG.md`](docs/architecture/PHASE-Z-CHANGE-LOG.md) 참조.
---
## 4. 향후 로드맵
```mermaid
flowchart LR
R1["1. 22 단계 파이프라인<br/>안정화<br/><sub>프레임 연결 / 시각 점검 보강 /<br/>MDX 정리 / 01·02·04 검증</sub>"]
R2["2. 옛 코드 검토<br/>및 반영<br/><sub>Phase Q 25 모듈 audit</sub>"]
R3["3. AI 보정 /<br/>재구성 단계<br/><sub>점수 낮음 / 모두 거절 /<br/>재구성 / 오버플로우 반복</sub>"]
R4["4. DB / 카탈로그<br/>정리<br/><sub>프레임 / V4 / 실행이력 / 사용자 변경</sub>"]
R5["5. 프론트엔드 연결<br/><sub>실행 목록 / 타임라인 /<br/>매칭 후보 / 적용 계획</sub>"]
R6["6. HTML 수정 기능<br/><sub>user_overrides.json</sub>"]
R7["7. 프레임 지속<br/>업데이트<br/><sub>Figma → Phase Z 어댑터 추가</sub>"]
R1 --> R2 --> R3 --> R4 --> R5 --> R6 --> R7
classDef current fill:#fff3cd,stroke:#f59f00,color:#000
classDef future fill:#f3f0ff,stroke:#7048e8,color:#000
classDef later fill:#f8f9fa,stroke:#868e96,color:#000,stroke-dasharray: 5 5
class R1 current
class R2,R3 future
class R4,R5,R6,R7 later
```
**현재 위치**: 단계 1 (22 단계 파이프라인 안정화). MDX03 정상 경로 닫힘 → 일반화 진행 중.
### 단계별 상세
**1. 22 단계 파이프라인 안정화 (현재)**
- 프레임 ↔ Phase Z 연결 구조 정리
- F14 / F11 / F18 등 Phase Z 가 아직 받지 못하는 Figma 프레임의 어댑터 추가
- *Figma 새 디자인이나 V4 새 매칭이 아니라*, 이미 두 곳 (Figma / V4) 에 있는 프레임을 Phase Z 런타임이 받아 쓸 수 있게 연결만
- 시각 점검 범위 확장 (Step 14)
- 누락 이미지 / 표 잘림 / 이미지 비율 어긋남 / 빈 공간 검사
- MDX 정규화 / 정리 방법 적용 (Step 2 / 3 / 4)
- MDX 01 / 02 / 04 검증으로 예외 케이스 발견 + 파이프라인 일반화
**2. 옛 코드 검토 및 반영**
- `src/` 안 옛 25 개 모듈 (slide_measurer, space_allocator, content_editor 등) 각각 검토
- 살릴 기능 / 폐기할 모듈 / 학습 자료로만 둘 것 분류
- 살릴 것은 Phase Z 로 이식
**3. AI 보정 / 재구성 단계**
- 점수 낮음 / 모두 거절 / 재구성 필요 / 오버플로우 반복 케이스 처리
- AI 가 MDX 원문은 보존하면서 슬롯 데이터 / Region / 팝업 / 레이아웃 제안
- 연결되는 단계: Step 9 / 12 / 17 / 19 / 21
**4. DB / 카탈로그 정리**
- 프레임 카탈로그 / 컨트랙트
- V4 결과
- 실행 이력 / 단계별 산출물
- 사용자 변경 이력 (어떤 후보를 골랐는지 등)
**5. 프론트엔드 연결**
- 실행 목록 / preview.png / final.html 보기
- 22 단계 타임라인 (각 단계 산출물 시각화)
- V4 1~6 위 후보 표시 + 사용자 선택
- 레이아웃 / Region / 적용 계획 표시
- 시각 점검 / 재시도 / 다음 조치 결과
**6. HTML 수정 기능**
- 텍스트 수정
- 이미지 크기 / 위치 조정
- 프레임 후보 변경 (V4 의 1 위 외 다른 위 선택)
- 레이아웃 / Region 조정
- `user_overrides.json` 으로 저장 (final.html 직접 수정 X — MDX 원문 보존 원칙 정합)
**7. 프레임 지속 업데이트**
- Figma → HTML 변환 추가 (`figma_to_html_agent/`)
- Phase Z 어댑터 연결 (단계 1 의 작업과 같은 방식)
- 컨트랙트 / partial / 빌더 추가
- V4 카탈로그와 런타임 동기화
---
## 5. 운영 원칙
### 5.1 절대 원칙
- **MDX 원문 무손실 보존** — AI 가 일반 경로에서 MDX 원문을 *재작성 / 삭제 / 요약하지 않음*. 원문은 본문 미리보기 또는 자세히보기 / 팝업 어딘가에 *반드시* 보존.
- **자유 디자인 금지** — Figma 프레임 DB / 카탈로그 / 컨트랙트 기반으로만 디자인 결정. AI 가 프레임 / 레이아웃 / 새 디자인 패턴을 *생성하지 않음*.
- **그릇 변경 원칙** — 콘텐츠가 안 맞을 때 *콘텐츠를 줄이지 않음*. 대신 *그릇* (레이아웃 / zone / Region / 프레임 / 표시 방식) 을 변경. 공통 CSS / padding / tolerance 임의 축소 *금지*.
- **dropped 절대 룰** — `text_block / table / image / details` 콘텐츠는 *절대 삭제하지 않음*. 장식 요소 (decorative_element) 만 공간 부족 시 dropped 가능.
### 5.2 V4 ↔ Phase Z 책임 분담
| 시스템 | 역할 |
|---|---|
| **V4** | 프레임 *선택* — 점수 + 라벨 (그대로 사용 / 가벼운 편집 / 재구성 / 거절) |
| **Step 5** | V4 후보를 거절 제외 최대 6 개로 정리 |
| **Step 6** | 구성 단위 결정 (어느 섹션 묶음 = 1 zone) — 현재는 V4 1 위를 그대로 채택 |
| **Step 9** | V4 후보를 *어떻게 적용할지* 번역 (V4 점수를 다시 계산하지 않음) |
V4 라벨 → 적용 방식 변환:
- `그대로 사용` → 바로 삽입
- `가벼운 편집` → 같은 프레임에 약간 조정
- `재구성` → 레이아웃 / Region 변경 (자동으로는 적용 안 함, 사람 확인)
- `거절` → 제외
### 5.3 렌더 정책
- 현재 렌더는 V4 의 1 위 후보 사용
- 2~6 위는 보존만 — 향후 프론트엔드에서 사용자가 선택할 수 있게
- `final.html` 을 직접 수정하지 않음 — 프론트엔드에서 변경 시 `user_overrides.json` 으로 누적 (원문 보존 원칙과 정합)
---
## 참고 문서
| 문서 | 역할 |
|---|---|
| [`CLAUDE.md`](CLAUDE.md) | 프로젝트 규칙 + Phase Z 위계 |
| [`PHASE-Z-PIPELINE-OVERVIEW.md`](docs/architecture/PHASE-Z-PIPELINE-OVERVIEW.md) | 22 단계 도면 (구조 잠금) |
| [`PHASE-Z-PIPELINE-STATUS-BOARD.md`](docs/architecture/PHASE-Z-PIPELINE-STATUS-BOARD.md) | 현재 진행 상태 (✅ / ⚠ / ❌) |
| [`PHASE-Z-CHANGE-LOG.md`](docs/architecture/PHASE-Z-CHANGE-LOG.md) | 결정 변경 이력 |
| [`PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md`](docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md) | 콘텐츠 객체 + Internal Region + Frame Slot 명세 |
| [`PHASE-Z-FIT-CLASSIFIER-ROUTER-SPEC.md`](docs/architecture/PHASE-Z-FIT-CLASSIFIER-ROUTER-SPEC.md) | Step 14~19 점검 / 라우팅 명세 |
| [`IMPROVEMENT-REDESIGN.md`](IMPROVEMENT-REDESIGN.md) | Phase Z 통합 설계 |
| [`PROCESS_OVERVIEW.html`](PROCESS_OVERVIEW.html) | 임원 보고용 A4 2 페이지 (프로세스 + 구조도) |
| [`PROGRESS.md`](PROGRESS.md) | 전체 Phase 이력 (Phase 1~T + R' + Z) |
+274
View File
@@ -0,0 +1,274 @@
"""MDX 02 최종 4안 — 처음부터 독립, CSS font-size override 금지.
글씨 크기: 블록 CSS 원래 값 그대로. 절대 변경 금지.
zone 크기: 글씨 크기에 맞게 조정 (글씨가 기준, 레이아웃이 맞춤).
안 1: 내 판단 + new/ only
상단: cards-3col-persona 하단좌: stacked-arrow-list 하단우: cards-3col-persona(3주체)
안 2: 내 판단 + new/ + 기존
상단: card-compare-3col 하단좌: card-numbered 하단우: table-simple-striped
안 3: Kei 판단 + new/ only (Kei 응답: 상단1 하단좌4 하단우2 결론6)
상단: cards-3col-persona 하단좌: split-panel-numbered 하단우: compare-vs-rows
안 4: Kei 판단 + new/ + 기존 (Kei 응답: 상단A 하단좌7 하단우H 결론6)
상단: card-compare-3col 하단좌: issues-paired-rows 하단우: compare-3col-badge
"""
import base64, re
from pathlib import Path
from jinja2 import Environment, FileSystemLoader
BLOCKS = Path("templates/blocks")
SVG = BLOCKS / "svg"
OUT = Path("data/runs/mdx02_4plans_final")
OUT.mkdir(parents=True, exist_ok=True)
env = Environment(loader=FileSystemLoader(str(BLOCKS)), autoescape=False)
def b64(f):
p = SVG / f
if not p.exists(): return ""
ext = "svg+xml" if f.endswith(".svg") else "png"
return f"data:image/{ext};base64," + base64.b64encode(p.read_bytes()).decode()
def clean(h): return re.sub(r'<!--.*?-->', '', h, flags=re.DOTALL).strip()
img_uri = open("data/runs/mdx02_v4_test/slide_image.txt").read().strip()
title = "DX의 시행 목표 및 기대효과"
ft = '고품질의 성과품, 비용 절감, 시간 단축, 의사소통에 도움이 <em>안 되면 DX가 아니다</em>'
# slide-body: 1200×590px. 블록 글씨 크기에 맞춰 zone 크기 계산.
# 컨테이너 계산 → 글자수 예산 → overflow 방지
IW = 500 # 이미지
GAP = 10
# zone 높이: 블록 필요 높이 기반 계산
# new/ 블록(15~22px): 상단 244px, 하단 336px
# 기존 블록(13~15px): 상단 204px, 하단 310px
TH_NEW = 244
BH_NEW = 336
TH_OLD = 204
BH_OLD = 310
# 원문 텍스트
TOP = [
("안전과 품질", [
"시설물의 요구 성능을 설계-시공-운영 전 과정에서 <strong>디지털로 검증</strong>하여 <strong>안전성 확보</strong>",
"Copy &amp; Paste로 하향 평준화된 성과물의 <strong>하자 최소화</strong>로 <strong>고품질 성과물 제공</strong>"]),
("생산성 향상", [
"Analogue 기반 업무를 Digital 기반 프로세스로 전환하여 <strong>업무 속도·정확성·일관성 향상</strong>",
"건설 비용 및 유지관리비 절감, 건설 기간 단축, 인력투입 최소화를 통해 <strong>부가가치 제고</strong>"]),
("소통과 신뢰", [
"성과품과 Solution을 통한 협업 강화로 <strong>의사소통 효율 및 운영·유지관리</strong>의 <strong>편리성 증진</strong>",
"3D 모델 및 데이터 기반 검증을 통한 <strong>오류 최소화 및 Claim 예방</strong>으로 <strong>신뢰성 확보</strong>"]),
]
BL = [
("생산 방식", "수작업 의존의 반복 업무에서 벗어나, <strong>SW를 활용한 체계화된 방식</strong>으로 전환"),
("인지·검토", "2D 도면 해석 중심에서 <strong>3D 모델 기반의 직관적 인지·검토 체계</strong>로 전환"),
("협업 구조", "개별 문서 중심 협업에서 <strong>데이터 통합 기반의 정보 공유·관리 협업 환경</strong>으로 전환"),
("검증·대응", "사후 대응 중심의 문제 처리에서 <strong>사전 검증 중심의 예방적 업무 방식</strong>으로 전환"),
]
BR = {
"headers": ["구분", "발주자", "시공자", "설계자"],
"rows": [
["필요 역량", "실행 의지와 합리적 판단", "기술 투자와 운영 역량", "SW개발 투자 역량"],
["SW 기반 체계화", "행정 자동화로 생산성 향상", "체계적 공정관리로 신뢰성 확보", "설계 프로세스 체계화"],
["3D 기반 전환", "직관적 시각화로 품질 향상", "안전성 제고 및 관리 편의", "3D 검증으로 설계 오류 방지"],
["데이터 통합 협업", "원활한 의사소통으로 오류 감소", "협업 효율 및 서류 감소", "설계 신뢰도로 상호신뢰 증진"],
["사전 검증 관리", "민원·소송 등 사전 예방", "설계·시공 오류 예방", "설계 책임 리스크 감소"],
],
}
def wrap_slide(body_html, fname):
sb = clean((BLOCKS / "slide-base.html").read_text(encoding="utf-8"))
r = sb.replace('{{ title|default("슬라이드") }}', title)
r = r.replace('{{ title|default("슬라이드 제목") }}', title)
r = r.replace('{% block body %}{% endblock %}', body_html)
pill = b64("pill_scroll.png")
r = r.replace('{% if footer_text %}', '').replace('{% if footer_pill_bg %}', '')
r = r.replace('{{ footer_pill_bg }}', pill).replace('{% else %}', '')
r = r.replace('<div class="slide-footer-bg slide-footer--css"></div>', '')
li = r.rfind('{% endif %}')
if li > 0: r = r[:li] + r[li + len('{% endif %}'):]
r = r.replace('{% endif %}', '').replace('{{ footer_text|safe }}', ft)
r = r.replace('src="svg/bg_slide_texture.png"', f'src="{b64("bg_slide_texture.png")}"')
r = r.replace('src="svg/line_divider.svg"', f'src="{b64("line_divider.svg")}"')
out = OUT / fname
out.write_text(r, encoding="utf-8")
return out
def make_body(top_html, bl_html, br_html, th, bh):
"""slide-body 안에 배치. zone 높이는 블록 글씨 크기 기반 계산값."""
return f"""
<div style="height:{th}px;margin-bottom:{GAP}px;overflow:hidden;">
<div style="font-weight:700;font-size:13px;color:#1a365d;margin-bottom:4px;">DX의 궁극적 목표</div>
<div style="display:flex;gap:8px;height:{th-20}px;">
<div style="flex:1;overflow:hidden;">{top_html}</div>
<div style="width:{IW}px;flex-shrink:0;display:flex;flex-direction:column;justify-content:center;">
<img src="{img_uri}" style="width:100%;border-radius:8px;object-fit:contain;">
<div style="font-size:10px;color:#94a3b8;text-align:center;margin-top:2px;">DX의 궁극적 목표</div>
</div>
</div>
</div>
<div style="height:{bh}px;overflow:hidden;">
<div style="font-weight:700;font-size:13px;color:#1a365d;padding-bottom:4px;border-bottom:1px solid #e2e8f0;margin-bottom:4px;">DX 기반 Process 혁신에 따른 주체별 기대효과</div>
<div style="display:flex;gap:12px;height:{bh-28}px;">
<div style="flex:1;overflow:hidden;">
<div style="font-weight:700;font-size:12px;color:#1a365d;margin-bottom:4px;">업무 수행 과정(Process)의 변화</div>
{bl_html}
</div>
<div style="width:1px;background:#cbd5e1;flex-shrink:0;"></div>
<div style="flex:1;overflow:hidden;">
<div style="font-weight:700;font-size:12px;color:#1a365d;margin-bottom:4px;">DX 시행 주체별 기대효과</div>
{br_html}
</div>
</div>
</div>"""
# Jinja2 .items() 충돌 방지용 클래스
class _Cat:
def __init__(self, name, color, items): self.name=name; self.color=color; self.items=items
# ══════════════════════════════════════════
# 안 1: 내 판단 + new/ only — 글씨 크기 그대로
# ══════════════════════════════════════════
print("=== 안 1 ===")
t1 = clean(env.get_template("new/cards-3col-persona.html").render(personas=[
{"overlay_color":c,"label_line1":t,"label_color":"#1a365d","bullets":[{"text":b} for b in bs]}
for (t,bs),c in zip(TOP,["#dce8d4","#d4dce8","#e8dcd4"])
]))
# 뱃지/사진만 숨김 — 글씨 크기는 원래 값(15px body, 20px label)
t1 += "<style>.c3p-badge{display:none}.c3p-photo{display:none}.c3p-badge-label{position:relative;z-index:2;margin-bottom:4px}</style>"
b1l = clean(env.get_template("new/stacked-arrow-list.html").render(items=[
{"text":f"<strong>{k}</strong>: {v}","border_color":c}
for (k,v),c in zip(BL,["#fb5915","#e79000","#919f00","#0d6361"])
]))
# 헤더/장식만 숨김 — 글씨 크기(22px)는 원래 값
b1l += "<style>.sal-header{display:none}.sal-deco{display:none}</style>"
b1r = clean(env.get_template("new/cards-3col-persona.html").render(personas=[
{"overlay_color":c,"label_line1":h,"label_color":"#1a365d",
"bullets":[{"text":BR["rows"][ri][ci+1]} for ri in range(5)]}
for ci,(h,c) in enumerate([("발주자","#c8d8e8"),("시공자","#d8e8c8"),("설계자","#e8d8c8")])
]))
b1r = b1r.replace('block-c3p','block-c3p2').replace('c3p-','c3p2-')
b1r += "<style>.c3p2-badge{display:none}.c3p2-photo{display:none}.c3p2-badge-label{position:relative;z-index:2;margin-bottom:4px}</style>"
p1 = wrap_slide(make_body(t1, b1l, b1r, TH_NEW, BH_NEW), "plan1_new_only.html")
print(f" {p1.stat().st_size:,} bytes")
# ══════════════════════════════════════════
# 안 2: 내 판단 + mixed — 글씨 크기 그대로
# ══════════════════════════════════════════
print("=== 안 2 ===")
t2 = clean(env.get_template("cards/card-compare-3col.html").render(cards=[
{"title":t,"color":c,"bullets":bs}
for (t,bs),c in zip(TOP,["#1a365d","#15803d","#b45309"])
]))
b2l = clean(env.get_template("cards/card-numbered.html").render(items=[
{"title":k,"description":v,"color":c}
for (k,v),c in zip(BL,["#2563eb","#16a34a","#d97706","#7c3aed"])
]))
b2r = clean(env.get_template("tables/table-simple-striped.html").render(**BR))
p2 = wrap_slide(make_body(t2, b2l, b2r, TH_OLD, BH_OLD), "plan2_mixed.html")
print(f" {p2.stat().st_size:,} bytes")
# ══════════════════════════════════════════
# 안 3: Kei 판단 + new/ only (1,4,2,6)
# ══════════════════════════════════════════
print("=== 안 3 (Kei: 1,4,2,6) ===")
# 상단: 1. cards-3col-persona (안 1과 동일 블록, 동일 데이터)
t3 = clean(env.get_template("new/cards-3col-persona.html").render(personas=[
{"overlay_color":c,"label_line1":t,"label_color":"#1a365d","bullets":[{"text":b} for b in bs]}
for (t,bs),c in zip(TOP,["#dce8d4","#d4dce8","#e8dcd4"])
]))
t3 += "<style>.c3p-badge{display:none}.c3p-photo{display:none}.c3p-badge-label{position:relative;z-index:2;margin-bottom:4px}</style>"
# 하단좌: 4. split-panel-numbered (Kei 선택)
b3l = clean(env.get_template("new/split-panel-numbered.html").render(
categories=[_Cat(k,c,[v]) for (k,v),c in zip(BL,["#417d38","#008e52","#008970","#2563eb"])],
right_items=[],
))
b3l += "<style>.spn-header{display:none}.spn-right{display:none}.spn-mid{display:none}.spn-left{flex:1}</style>"
# 하단우: 2. compare-vs-rows (Kei 선택) — 3주체를 좌/우로
b3r = clean(env.get_template("new/compare-vs-rows.html").render(
main_labels={"left":"발주자","center":"구분","right":"시공자·설계자"},
rows=[{"category":r[0],"left_text":r[1],"right_text":f"{r[2]} / {r[3]}"} for r in BR["rows"]],
))
b3r += "<style>.cvr-header{display:none}.cvr-conclusion{display:none}</style>"
p3 = wrap_slide(make_body(t3, b3l, b3r, TH_NEW, BH_NEW), "plan3_kei_new.html")
print(f" {p3.stat().st_size:,} bytes")
# ══════════════════════════════════════════
# 안 4: Kei 판단 + mixed (A,7,H,6)
# ══════════════════════════════════════════
print("=== 안 4 (Kei: A,7,H,6) ===")
# 상단: A. card-compare-3col (안 2와 동일 블록)
t4 = clean(env.get_template("cards/card-compare-3col.html").render(cards=[
{"title":t,"color":c,"bullets":bs}
for (t,bs),c in zip(TOP,["#1a365d","#15803d","#b45309"])
]))
# 하단좌: 7. issues-paired-rows (Kei 선택)
b4l = clean(env.get_template("new/issues-paired-rows.html").render(
pill_bg=b64("pill_scroll.png"),
rows=[
{"left":{"label":BL[0][0],"text":BL[0][1]},"right":{"label":BL[1][0],"text":BL[1][1]}},
{"left":{"label":BL[2][0],"text":BL[2][1]},"right":{"label":BL[3][0],"text":BL[3][1]},"pills_bottom":True},
],
))
b4l += "<style>.ipr-header{display:none}</style>"
# 하단우: H. compare-3col-badge (Kei 선택)
b4r = clean(env.get_template("tables/compare-3col-badge.html").render(**BR))
p4 = wrap_slide(make_body(t4, b4l, b4r, TH_OLD, BH_OLD), "plan4_kei_mixed.html")
print(f" {p4.stat().st_size:,} bytes")
# ══════════════════════════════════════════
# Selenium 검증
# ══════════════════════════════════════════
print("\n=== Selenium 검증 ===")
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
options = Options()
options.add_argument('--headless')
options.add_argument('--window-size=1400,900')
options.add_argument('--force-device-scale-factor=2')
driver = webdriver.Chrome(options=options)
for fname in ["plan1_new_only.html","plan2_mixed.html","plan3_kei_new.html","plan4_kei_mixed.html"]:
path = OUT / fname
driver.get(f"file:///{path.resolve()}")
time.sleep(2)
driver.save_screenshot(str(path).replace(".html",".png"))
html = path.read_text(encoding="utf-8")
c = re.sub(r'data:image/[^;]+;base64,[A-Za-z0-9+/=]+','I',html)
# font-size override 확인 — !important가 있으면 위반
overrides = re.findall(r'font-size.*?!important', c)
j = re.findall(r'\{[%{].*?[%}]\}',c)
ts = ['안전','품질','생산','향상','소통','신뢰','생산 방식','인지','협업','검증',
'발주자','시공자','설계자','안 되면 DX가 아니다','DX의 궁극적 목표','Process 혁신','업무 수행']
m = [t for t in ts if t not in c]
print(f" [{fname}]")
print(f" Jinja:{len(j)} 텍스트:{len(ts)-len(m)}/{len(ts)} font-size override:{len(overrides)}")
if m: print(f" MISSING: {m}")
if overrides: print(f" OVERRIDE 위반: {overrides[:3]}")
driver.quit()
print("\n완료!")
+306
View File
@@ -0,0 +1,306 @@
"""MDX 03: slide-base + prerequisites-3col(상단) + process-product-2col(하단) + pill(결론).
블록 CSS 글씨 크기 그대로. font-size override 금지.
텍스트 원문 그대로. 요약/추론 금지.
"""
import base64, re
from pathlib import Path
from jinja2 import Environment, FileSystemLoader
BLOCKS = Path("templates/blocks")
SVG = BLOCKS / "svg"
OUT = Path("data/runs/mdx03_final")
OUT.mkdir(parents=True, exist_ok=True)
env = Environment(loader=FileSystemLoader(str(BLOCKS)), autoescape=False)
def b64(f):
p = SVG / f
if not p.exists(): return ""
ext = "svg+xml" if f.endswith(".svg") else "png"
return f"data:image/{ext};base64," + base64.b64encode(p.read_bytes()).decode()
def clean(h): return re.sub(r'<!--.*?-->', '', h, flags=re.DOTALL).strip()
# ══════════════════════════════════════════
# 상단: prerequisites-3col — MDX 원문 그대로
# ══════════════════════════════════════════
class _Item:
def __init__(self, heading, desc): self.heading = heading; self.desc = desc
class _Col:
def __init__(self, **kw):
for k, v in kw.items(): setattr(self, k, v)
# 블록 CSS만 가져오고, HTML은 콘텐츠 items 수에 맞게 동적 생성
# prerequisites-3col의 CSS를 추출
_p3c_raw = (BLOCKS / "new" / "prerequisites-3col.html").read_text(encoding="utf-8")
_p3c_css = re.search(r'<style>(.*?)</style>', _p3c_raw, re.DOTALL).group(0)
# MDX 원문 그대로 — 각 열의 항목 수가 다름
cols_data = [
{
"name": "기술", "sub": "디지털",
"bar": "linear-gradient(180deg, #0D78D0 0%, #023056 100%)",
"hgrad": "linear-gradient(180deg, #0D78D0 0%, #134D7F 100%)",
"items": [
("Digital 기술(S/W, H/W)과 업무 Process의 통합", [
"기존 업무 프로세스에 다양한 디지털 기술을 접목하여 업무 수행",
"프로젝트 전반에 걸친 업무 프로세스의 연결 및 조율",
]),
("분야별 전문 지식(설계, 시공, 유지관리 등) 보유", [
"건설 전 단계에 대한 근본적인 이해와 지식 및 경험",
"최신 토목 기술 트랜드 및 표준 기준 등에 대한 높은 지식",
]),
],
},
{
"name": "사람", "sub": "역량",
"bar": "linear-gradient(180deg, #FF9A23 0%, #CC5200 100%)",
"hgrad": "linear-gradient(180deg, #CC5200 0%, #883700 100%)",
"items": [
("혁신적 사고방식과 창의적 문제 해결 능력", [
"기존 수행 방식과 관습적 사고 등에 의한 접근 방식 탈피",
"디지털 기술을 활용한 창의적, 혁신적인 솔루션 제시",
]),
("사용자 중심 사고와 DX 수행 경험", [
"사용자의 요구와 기대를 충족시키는 설계 및 구현",
"시행착오를 포함한 수행 경험과 사용자 경험(UX)을 반영한 해결 방안 제시",
]),
],
},
{
"name": "자연", "sub": "여건",
"bar": "linear-gradient(180deg, #39BE49 0%, #23742C 100%)",
"hgrad": "linear-gradient(180deg, #39BE49 0%, #1E6328 100%)",
"items": [
("지속적인 투자 및 실행 의지", [
"기술 도입 초기 단계에 필요한 인력·기간·비용 등의 대규모 투자",
"기술 고도화를 위한 지속적인 개선 및 투자 체계 구축",
"변화와 혁신을 통해 부가가치를 창출하려는 실행 의지와 추진력",
]),
],
},
]
# 동적 HTML 생성 — 블록 CSS 클래스 사용, items 수 동적
cols_html = ""
for col in cols_data:
items_html = ""
n = len(col["items"])
for i, (heading, bullets) in enumerate(col["items"]):
pct_h = int(95 / n)
pct_top = int(3 + i * (95 / n))
bul = "".join(f'<div class="bul">• {b}</div>' for b in bullets)
items_html += f"""
<div class="p3c-section" style="position:absolute;left:60px;right:6px;top:{pct_top}%;height:{pct_h}%;">
<div class="p3c-heading" style="background-image:{col['hgrad']}">{heading}</div>
<div class="p3c-desc">{bul}</div>
</div>"""
if i < n - 1:
line_top = pct_top + pct_h
items_html += f'<div class="p3c-mid-line" style="position:absolute;left:56px;right:0;top:{line_top}%;border-top:1.2px dashed #000;"></div>'
cols_html += f"""
<div class="p3c-col" style="flex:1;position:relative;height:100%;border-top:1.2px solid #000;border-bottom:1.2px solid #000;">
<div class="p3c-bar" style="background:{col['bar']};position:absolute;left:0;top:0;width:56px;height:100%;"></div>
<div class="p3c-vlabel-area" style="position:absolute;left:0;top:0;width:56px;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;z-index:3;">
<div class="p3c-vlabel">{col['name']}</div>
<div class="p3c-vlabel-sub">{col['sub']}</div>
</div>
{items_html}
</div>"""
top = f'<div class="block-p3c" style="display:flex;gap:12px;width:100%;height:100%;">{cols_html}</div>\n{_p3c_css}'
# ══════════════════════════════════════════
# 하단: process-product-2col — MDX 원문 그대로
# ══════════════════════════════════════════
# process-product-2col: 블록 CSS 사용 + HTML은 좌우 소제목이 같은 행에 오도록 Grid 재구성
_pp2_raw = (BLOCKS / "BEPs" / "process-product-2col.html").read_text(encoding="utf-8")
_pp2_css = re.search(r'<style>(.*?)</style>', _pp2_raw, re.DOTALL).group(0)
arrow_uri = b64("arrow_asis_tobe.png")
# 좌우 소제목을 행 단위로 대응시킴
# 행1: Analogue 기반 업무의 Digital화 (As-is→To-be) | Copy & Paste로 인해... 품질 향상
# 행2: GIS + BIM의 연계 | Analogue 기반 도서 외 Digital 기반 정보물 추가
# 행3: 사용자 중심의 Solution 제공 | Solution을 활용한 업무 효율화
# 2열 grid + ::before로 열 배경 gradient → 행 높이 동기화 + gradient 유지
bottom = f"""
<div class="pp2-grid-wrap" style="position:relative;width:100%;height:100%;">
<!-- 좌측 배경 gradient (::before 대신 absolute div) -->
<div style="position:absolute;left:0;top:0;width:50%;height:100%;background:linear-gradient(180deg,#ffffff 46%,#39311e 100%);z-index:0;"></div>
<!-- 우측 배경 gradient -->
<div style="position:absolute;left:50%;top:0;width:50%;height:100%;background:linear-gradient(0deg,#296b55 0%,#ffffff 56%);z-index:0;"></div>
<!-- 2열 grid — 행 높이 동기화 -->
<div style="position:relative;z-index:1;display:grid;grid-template-columns:1fr 1fr;width:100%;height:100%;">
<!-- 헤더 행 -->
<div class="pp2-header-bar pp2-header-bar--left" style="background:linear-gradient(270deg,#a4a096 0%,#39311e 100%);border-radius:0 24px 24px 0;display:flex;align-items:center;justify-content:center;height:30px;margin-top:4px;">
<span class="pp2-header-text pp2-header-text--left" style="font-size:13px;font-weight:900;color:#3e3523;">과정(Process)의 혁신</span>
</div>
<div class="pp2-header-bar pp2-header-bar--right" style="background:linear-gradient(90deg,#296b55 0%,#022017 100%);border-radius:24px 0 0 24px;display:flex;align-items:center;padding-left:20px;height:30px;margin-top:4px;">
<span class="pp2-header-text pp2-header-text--right" style="font-size:13px;font-weight:900;color:#ffffff;">결과(Product)의 변화</span>
</div>
<!-- 행1: Analogue Digital화 | 품질 향상 -->
<div style="padding:3px 16px;">
<div class="pp2-mid-title pp2-mid-title--left">Analogue 기반 업무의 Digital화</div>
<div style="display:flex;align-items:center;gap:4px;">
<div style="flex:1;">
<div class="pp2-body-text">• <strong>개념·문서·행정 절차 중심</strong></div>
<div class="pp2-body-text">• <strong>2D 도면, 전문가, 규정</strong></div>
<div class="pp2-body-text">• <strong>업무 구분(단절), 책임</strong></div>
</div>
<div style="flex-shrink:0;width:30px;text-align:center;"><img src="{arrow_uri}" style="width:30px;height:16px;object-fit:contain;" alt=""></div>
<div style="flex:1;">
<div class="pp2-body-text">• <strong>시각화된 목적물, 소통, 투명성 중심</strong></div>
<div class="pp2-body-text">• <strong>3D 모델, 참여자, 실체</strong></div>
<div class="pp2-body-text">• <strong>협업(융·복합), 창의성</strong></div>
</div>
</div>
</div>
<div style="padding:3px 16px;">
<div class="pp2-mid-title pp2-mid-title--right">Copy &amp; Paste로 인해 하향 평준화된 기존 성과물의 품질 향상</div>
<div class="pp2-body-text">• 과거 수작업으로 시행하면서 발생하던 오류 등의 최소화</div>
<div class="pp2-body-text">• 정확한 Data에 기반한 계획으로 고품질 성과물 도출</div>
</div>
<!-- 행2: GIS+BIM | Digital 정보물 -->
<div style="padding:2px 16px;">
<div class="pp2-mid-title pp2-mid-title--left">GIS + BIM의 연계</div>
<div class="pp2-body-text">• 지리·지형·지반 등 위치정보(GIS)와 3D모델(형상, 속성정보) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신</div>
</div>
<div style="padding:2px 16px;">
<div class="pp2-mid-title pp2-mid-title--right">Analogue 기반 도서 외 Digital 기반 정보물 추가</div>
<div class="pp2-body-text">• 기존 성과물(도면, 수량, 계산서, 시방서 등)에 3D 모델, Simulation 등의 Digital 기반 정보물 추가</div>
</div>
<!-- 행3: Solution -->
<div style="padding:2px 16px;">
<div class="pp2-mid-title pp2-mid-title--left">사용자 중심의 Solution 제공</div>
<div class="pp2-body-text">• 서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계할 수 있는 설계·시공 Solution 제공</div>
</div>
<div style="padding:2px 16px;">
<div class="pp2-mid-title pp2-mid-title--right">Solution을 활용한 업무 효율화</div>
<div class="pp2-body-text">• Engn. Solution을 통해 성과물에 관한 이슈를 함께 검토·논의하는 협업 환경 조성</div>
<div class="pp2-body-text">• 건설 단계별 정보를 디지털 데이터로 축적하여, 건설 전 과정을 통합관리</div>
</div>
</div>
</div>
{_pp2_css}
"""
# ══════════════════════════════════════════
# slide-base 조립
# ══════════════════════════════════════════
title = "DX 실행 체계 구축 방안"
ft = 'DX는 필요한 요건과 체계를 갖춘 후 시행해야만 그 효과를 <em>기대할 수 있다</em>'
# font_hierarchy: key_msg=14, core=12, bg=12, sidebar=11
# zone제목=13px, 블록 heading=12px, 블록 desc=11px
font_override = """<style>
/* prerequisites-3col: font_hierarchy 적용 + 높이 채움 */
.p3c-heading { font-size: 12px !important; line-height: 1.5 !important; }
.p3c-desc { font-size: 11px !important; line-height: 1.6 !important; }
.p3c-desc .bul { padding-left: 12px; text-indent: -12px; }
.p3c-vlabel { font-size: 14px !important; }
.p3c-vlabel-sub { font-size: 12px !important; }
.p3c-kanji { font-size: 16px !important; }
.p3c-col { min-height: 0 !important; height: 100% !important; }
.block-p3c { height: 100% !important; }
/* 한자 숨김 — MDX 원문에 없음 */
.p3c-kanji { display: none !important; }
/* 색상바 내 라벨 영역을 바 전체로 */
.p3c-vlabel-area { width: 56px !important; }
/* section을 바 바로 옆으로 — 들여쓰기 2단 효과 */
.p3c-section { left: 60px !important; right: 6px !important; }
.p3c-mid-line { left: 56px !important; }
/* 자연(3번째 열): heading 1개이므로 하단 숨김 */
.p3c-col:nth-child(3) .p3c-section--top { height: 90% !important; }
.p3c-col:nth-child(3) .p3c-section--bottom { display: none !important; }
.p3c-col:nth-child(3) .p3c-mid-line { display: none !important; }
/* process-product-2col: font_hierarchy 적용 + 높이 채움 */
.pp2-header-text { font-size: 13px !important; letter-spacing: 0.8px !important; }
.pp2-mid-title { font-size: 12px !important; line-height: 1.5 !important; margin-top: 6px !important; }
.pp2-mid-title:first-child { margin-top: 0 !important; }
.pp2-body-text { font-size: 11px !important; line-height: 1.6 !important; padding-left: 12px !important; text-indent: -12px !important; }
.pp2-col { min-height: 0 !important; }
.pp2-header-bar { height: 30px !important; margin-top: 4px !important; }
.pp2-body { padding: 6px 16px !important; }
.block-pp2 { height: 100% !important; }
/* 우측 헤더 텍스트: 배경 gradient와 겹쳐서 안 보임 → 흰색 */
.pp2-header-text--right { color: #ffffff !important; }
/* 좌우 본문 영역 높이 맞춤 */
.pp2-body { display: flex !important; flex-direction: column !important; }
</style>"""
body = f"""
{font_override}
<div style="height:38%;margin-bottom:1%;padding-top:8px;">
<div style="font-weight:700;font-size:13px;color:#1a365d;margin-bottom:8px;">DX 시행을 위한 필수 요건</div>
<div style="height:calc(100% - 28px);padding:0 12px 0 24px;">{top}</div>
</div>
<div style="height:60%;margin-top:12px;">
<div style="font-weight:700;font-size:13px;color:#1a365d;margin-bottom:8px;">Process의 혁신과 Product의 변화</div>
<div style="height:calc(100% - 28px);padding:0 12px 0 24px;">{bottom}</div>
</div>
"""
sb = clean((BLOCKS / "slide-base.html").read_text(encoding="utf-8"))
r = sb.replace('{{ title|default("슬라이드") }}', title)
r = r.replace('{{ title|default("슬라이드 제목") }}', title)
r = r.replace('{% block body %}{% endblock %}', body)
pill = b64("pill_scroll.png")
r = r.replace('{% if footer_text %}', '').replace('{% if footer_pill_bg %}', '')
r = r.replace('{{ footer_pill_bg }}', pill).replace('{% else %}', '')
r = r.replace('<div class="slide-footer-bg slide-footer--css"></div>', '')
li = r.rfind('{% endif %}')
if li > 0: r = r[:li] + r[li + len('{% endif %}'):]
r = r.replace('{% endif %}', '').replace('{{ footer_text|safe }}', ft)
r = r.replace('src="svg/bg_slide_texture.png"', f'src="{b64("bg_slide_texture.png")}"')
r = r.replace('src="svg/line_divider.svg"', f'src="{b64("line_divider.svg")}"')
out = OUT / "final.html"
out.write_text(r, encoding="utf-8")
print(f"저장: {out} ({out.stat().st_size:,} bytes)")
# ══════════════════════════════════════════
# Selenium 검증
# ══════════════════════════════════════════
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
options = Options()
options.add_argument('--headless')
options.add_argument('--window-size=1400,900')
options.add_argument('--force-device-scale-factor=2')
driver = webdriver.Chrome(options=options)
driver.get(f"file:///{out.resolve()}")
time.sleep(2)
driver.save_screenshot(str(out).replace(".html", ".png"))
driver.quit()
# 텍스트 검증
c = re.sub(r'data:image/[^;]+;base64,[A-Za-z0-9+/=]+', 'I', r)
overrides = re.findall(r'font-size.*?!important', c)
j = re.findall(r'\{[%{].*?[%}]\}', c)
ts = ['기술','사람','자연','디지털','역량','여건',
'Digital 기술','혁신적 사고방식','지속적인 투자',
'Process의 혁신','Product의 변화',
'Analogue','Digital','GIS','BIM','Solution',
'기대할 수 있다']
m = [t for t in ts if t not in c]
print(f"Jinja:{len(j)} font-override:{len(overrides)} 텍스트:{len(ts)-len(m)}/{len(ts)}")
if m: print(f" MISSING: {m}")
else: print(" ALL OK")
File diff suppressed because it is too large Load Diff
+1054
View File
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
{
"name": "design_agent",
"version": "1.0.0",
"description": "콘텐츠를 시각적으로 구조화된 슬라이드 HTML로 변환하는 독립 에이전트.",
"main": "index.js",
"directories": {
"doc": "docs",
"test": "tests"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/keimin86/design_agent.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"bugs": {
"url": "https://github.com/keimin86/design_agent/issues"
},
"homepage": "https://github.com/keimin86/design_agent#readme",
"dependencies": {
"@antv/infographic": "^0.2.16",
"infographic-cli": "^0.5.1"
}
}
+36
View File
@@ -0,0 +1,36 @@
[project]
name = "design-agent"
version = "0.1.0"
description = "콘텐츠 시각 구조화 슬라이드 생성 에이전트"
requires-python = ">=3.10"
dependencies = [
"fastapi>=0.115",
"uvicorn>=0.30",
"jinja2>=3.1",
"pydantic>=2.0",
"pydantic-settings>=2.0",
"anthropic>=0.40",
"httpx>=0.27",
"python-multipart>=0.0.9",
"sse-starlette>=2.0",
"pyyaml>=6.0",
"Pillow>=10.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"pytest-asyncio>=0.24",
"ruff>=0.8",
]
[tool.ruff]
line-length = 100
target-version = "py310"
[tool.pytest.ini_options]
asyncio_mode = "auto"
markers = [
"integration: end-to-end pipeline integration tests (heavy; invoke Selenium)",
]
+75
View File
@@ -0,0 +1,75 @@
"""MDX 03을 기존 파이프라인 (Phase Q) 또는 Phase Z-2 MVP-1 로 실행.
기본 (no flag) : 기존 Phase Q 파이프라인 — async, Kei API 사용
- Stage 0: mdx_normalizer
- Stage 1A/1B: kei_client (분류 + 정제)
- Stage 1.5a: space_allocator
- Stage 1.7: block_reference
- 출력 : data/runs/{run_id}/final.html
`--phase-z2` flag : Phase Z-2 MVP-1 — sync, AI 미사용, 결정론적
- matched_zone only (V4 use_as_is) — 그 외 abort + error.json
- 출력 : data/runs/{run_id}/phase_z2/final.html
- 상세 : src/phase_z2_pipeline.py + docs/architecture/PHASE-Z-CATALOG-RUNTIME-DESIGN.md § 16
"""
import argparse
import asyncio
import sys
import time
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
DEFAULT_MDX = Path("samples/mdx/03. DX 시행을 위한 필수 요건 및 혁신 방안.mdx")
async def run_phase_q(mdx_path: Path):
"""기존 Phase Q 파이프라인 실행."""
from src.pipeline import generate_slide
content = mdx_path.read_text(encoding="utf-8")
print(f"[Phase Q] MDX: {mdx_path.name}")
print(f" 내용 길이: {len(content)}\n")
start = time.time()
async for event in generate_slide(content, base_path=str(mdx_path.parent)):
ev_type = event.get("event", "")
data = event.get("data", "")
if ev_type == "progress":
print(f" {data}")
elif ev_type == "result":
elapsed = time.time() - start
print(f"\n완료! ({elapsed:.1f}초)")
if isinstance(data, dict):
run_id = data.get("run_id", "")
print(f" run_id: {run_id}")
print(f" 결과: data/runs/{run_id}/")
elif ev_type == "error":
print(f" 에러: {data}", file=sys.stderr)
def run_phase_z2(mdx_path: Path, run_id: str = None):
"""Phase Z-2 MVP-1 파이프라인 실행 (sync, AI 미사용)."""
from src.phase_z2_pipeline import run_phase_z2_mvp1
run_phase_z2_mvp1(mdx_path, run_id)
def main():
parser = argparse.ArgumentParser(description="MDX 03 pipeline runner.")
parser.add_argument("--phase-z2", action="store_true",
help="Phase Z-2 MVP-1 (sync, AI 미사용, matched_zone only).")
parser.add_argument("--mdx", type=Path, default=DEFAULT_MDX,
help=f"MDX 파일 경로 (default: {DEFAULT_MDX}).")
parser.add_argument("--run-id", type=str, default=None,
help="run_id 오버라이드 (default: timestamp).")
args = parser.parse_args()
if args.phase_z2:
run_phase_z2(args.mdx, args.run_id)
else:
asyncio.run(run_phase_q(args.mdx))
if __name__ == "__main__":
main()
Binary file not shown.

After

Width:  |  Height:  |  Size: 894 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

@@ -0,0 +1,120 @@
---
title: 건설산업 DX의 올바른 이해
sidebar:
order: 00
---
* **용어의 혼용**
* 건설산업의 디지털 전환 논의에서 DX(Digital Transformation)와 BIM(Building Information Modeling)이 개념적으로 명확히 정립되지 않은채 혼용되어 사용되고 있음
* 이로인해 BIM기술의 도입을 DX의 완성으로 오인하거나, DX를 BIM 기술 도입 수준으로 한정하는 인식 확산
<details>
<summary style={{cursor: 'pointer', fontWeight: 'bold', color: '#555'}}>혼용 대표 사례</summary>
<div style={{marginTop: '10px', paddingLeft: '15px', borderLeft: '3px solid #ddd', fontSize: '0.9rem', color: '#666'}}>
* **[스마트 건설 활성화 방안(2022.07)]**
* 추진과제 : 건설산업 디지털화
* 실행과제 : BIM 전면 도입, BIM 전문인력 양성
* **[제7차 건설기술진흥 기본계획(2023.12)]**
* 추진방향 : 디지털 전환을 통한 스마트 건설 확산
* 추진과제 : BIM 도입으로 건설산업 디지털화
</div>
</details>
* 건설산업의 DX를 올바르게 이해하기 위해 각 용어의 정의, 역할, 상호관계에 대한 체계적 정립 필요
<br/>
---
## 1. 용어 정의
<br/>
* **건설산업**
* 다양한 시설물을 각 산업마다의 광범위한 기술을 통합 및 융합하여 만들어내는 종합산업
* 목적 시설물의 품질 욕구를 충족시키면서 최단기간내에 최소 비용으로 편리하고 안전하며 우수한 성능의 시설물 완성을 목표로 함
<br/>
* **BIM(Building Information Modeling) : 디지털 전환을 위한 핵심 기술**
* 시설물의 생애주기동안 발생한 모든 정보를 3차원 모델 기반으로 통합·관리하는 정보 관리 도구
* 건설 정보와 절차를 표준화된 방식으로 연계하고 디지털 협업이 가능하도록 하는 핵심 인프라 기술
<div style={{
fontSize: '0.8rem',
color: '#999',
marginTop: '5px',
lineHeight: '1.4',
paddingLeft: '0px' }}>
*건설산업 BIM 기본지침, 국토교통부, 2020*
</div>
<br/>
* **DX(Digital Transformation) : 산업 패러다임의 변화**
* 디지털 기술을 기반으로 산업 전반의 업무방식과 가치 창출 구조를 전환하는 과정 및 결과
* 단순한 기술 도입이 아닌, 고객 가치와 의사결정 방식의 근본적인 변화로 산업의 새로운 방향을 정립하는 것을 의미함
<div style={{
fontSize: '0.8rem',
color: '#999',
marginTop: '5px',
lineHeight: '1.4',
paddingLeft: '0px' }}>
*Digital Transformation, IBM Institute for Business Value, 2011 / What is Digital Transformation?, Agile Elephant, 2015*
</div>
---
<br/>
## 2. 용어간 상호관계
* DX는 BIM과 같은 디지털기술을 기반으로 산업 전반의 프로세스를 혁신하는 상위개념
* 건설산업의 DX는 GIS(공간정보), BIM, 디지털 트윈(가상환경)의 기술융합을 통해서만 실현 또는 구현 가능
* GIS의 역할 : 지리적 데이터를 공간 분석하여 시각적으로 표현, 위치기반 정보 제공
* BIM의 역할 : 형상정보와 내용정보가 포함된 3D모델로, 건설 정보 기반의 Process와 Product를 제공
![DX와 핵심기술간 상호관계](/assets/images/DX1.png)
<div style={{
fontSize: '0.8rem',
color: '#999',
marginTop: '5px',
lineHeight: '1.4',
paddingLeft: '0px' }}>
*[그림 1] DX와 핵심기술간 상호관계*
</div>
<br/>
<br/>
<details>
<summary style={{cursor: 'pointer', fontWeight: 'bold', color: '#555'}}>DX와 BIM의 구분</summary>
<div style={{marginTop: '10px', paddingLeft: '15px', borderLeft: '3px solid #ddd', fontSize: '0.9rem', color: '#666'}}>
| DX | 구분 | BIM |
| :--- | :---: | ---: |
| **BIM &lt;&lt; DX**<br/>(Engineering + Management 통합) | **범위** | **Only 3D**<br/>(형상 구현 중심) |
| **제작 및 운영**(상용 + 전용 40~80개)<br/>[Rhino, Sketchup, Blender..] + [EG-BIM 등] | **S/W** | **모델 제작용 상용 SW**<br/>[Revit, Civil 3D, Navisworks, Autocad] |
| **근본적 문제의식을 통한 개선** | **프로세스** | **기존 2D 설계 방식 유지** |
| **공학 정보 및 콘텐츠 연계에 집중**<br/>**도면, 수량, 시공계획 등 일식** | **성과품** | **3D 모델 중심**<br/>**기존 성과품 유지** |
| **설계/시공 생산성 혁신**(개념의 재정립) | **활용** | **3D 모델에 의한 일반적 이해 향상** |
| **전 생애주기 활용 시스템** | **확장성** | **(설계/시공/운영) 분야별 단절** |
| **구체화(복잡) - 적극적/구체적 실현 방안** | **수행 개념** | **단순화(오류) - 수동적/집단적 동질화** |
| **적극적, 주체적인 기술 접목/융합** | **CIVIL + IT** | **소극적, 상용 기술에 의존** |
| **자체 수행 능력 - 지속가능성 확보** | **주체** | **S/W 제작사 판매 정책에 의존** |
| **차별화 및 경쟁력 확보, 해외 진출** | **발주처** | **평준화, 국내 중심** |
| **IT + CIVIL ENG 220명 운영 + 기술 개발** | **설계사** | **소규모 BIM팀 운영 + 단순교육에 집중** |
| **분야 확장 모델 및 시스템** | **시공사** | **국내 토목 소극적/해외 토목증가** |
</div>
</details>
<br/>
---
:::note[핵심 요약]
* BIM은 건설산업의 디지털전환(DX)을 수행하는 과정에서 **가장 기초가 되는 일부분**이다
:::
@@ -0,0 +1,42 @@
---
title: DX의 시행 목표 및 기대효과
sidebar:
order: 1
---
import DxEffect from '../../../../components/dx.astro';
## 1. DX의 궁극적 목표
- **안전과 품질**
- 시설물의 요구 성능을 설계-시공-운영 전 과정에서 **디지털로 검증**하여 **안전성 확보**
- Copy & Paste로 하향 평준화된 성과물의 **하자 최소화**로 **고품질 성과물 제공**
<br/>
- **생산성 향상**
- Analogue 기반 업무를 Digital 기반 프로세스로 전환하여 **업무 속도·정확성·일관성 향상**
- 건설 비용 및 유지관리비 절감, 건설 기간 단축, 인력투입 최소화를 통해 **부가가치 제고**
<br/>
- **소통과 신뢰**
- 성과품과 Solution을 통한 협업 강화로 **의사소통 효율 및 운영·유지관리**의 **편리성 증진**
- 3D 모델 및 데이터 기반 검증을 통한 **오류 최소화 및 Claim 예방**으로 **신뢰성 확보**
![DX의 궁극적 목표](/assets/images/궁극적목표.png)
<br/>
## 2. DX 기반 Process 혁신에 따른 주체별 기대효과
<br/>
### 2.1 업무 수행 과정(Process)의 변화
- **생산 방식**: 수작업 의존의 반복 업무에서 벗어나, **SW를 활용한 체계화된 방식**으로 전환
- **인지·검토**: 2D 도면 해석 중심에서 **3D 모델 기반의 직관적 인지·검토 체계**로 전환
- **협업 구조**: 개별 문서 중심 협업에서 **데이터 통합 기반의 정보 공유·관리 협업 환경**으로 전환
- **검증·대응**: 사후 대응 중심의 문제 처리에서 **사전 검증 중심의 예방적 업무 방식**으로 전환
<br/>
### 2.2 DX 시행 주체별 기대효과
<DxEffect />
<br/>
<br/>
:::note[핵심 요약]
* 고품질의 성과품, 비용 절감, 시간 단축, 의사소통에 도움이 안 되면 DX가 아니다.
:::
<br/>
@@ -0,0 +1,89 @@
---
title: DX 실행 체계 구축 방안
sidebar:
order: 02
---
## 1. DX 시행을 위한 필수 요건
<br/>
* **기술(디지털)**
* **Digital 기술(S/W, H/W)과 업무 Process의 통합**
* 기존 업무 프로세스에 다양한 디지털 기술을 접목하여 업무 수행
* 프로젝트 전반에 걸친 업무 프로세스의 연결 및 조율
* **분야별 전문 지식(설계, 시공, 유지관리 등) 보유**
* 건설 전 단계에 대한 근본적인 이해와 지식 및 경험
* 최신 토목 기술 트랜드 및 표준 기준 등에 대한 높은 지식
<br/>
* **사람(역량)**
* **혁신적 사고방식과 창의적 문제 해결 능력**
* 기존 수행 방식과 관습적 사고 등에 의한 접근 방식 탈피
* 디지털 기술을 활용한 창의적, 혁신적인 솔루션 제시
* **사용자 중심 사고와 DX 수행 경험**
* 사용자의 요구와 기대를 충족시키는 설계 및 구현
* 시행착오를 포함한 수행 경험과 사용자 경험(UX)을 반영한 해결 방안 제시
<br/>
* **자연(여건)**
* **지속적인 투자 및 실행 의지**
* 기술 도입 초기 단계에 필요한 인력·기간·비용 등의 대규모 투자
* 기술 고도화를 위한 지속적인 개선 및 투자 체계 구축
* 변화와 혁신을 통해 부가가치를 창출하려는 실행 의지와 추진력
<br/>
---
## 2. Process의 혁신과 Product의 변화
<br/>
### 2.1 과정(Process)의 혁신
* **Analogue 기반 업무의 Digital화**
| As-is [Analogue] | 구분 | To-be [Digital] |
| :--- | :---: | :--- |
| **개념·문서·행정 절차 중심** | ➠ | **시각화된 목적물, 소통, 투명성 중심** |
| **2D 도면, 전문가, 규정** | ➠ | **3D 모델, 참여자, 실체** |
| **업무 구분(단절), 책임** | ➠ | **협업(융·복합), 창의성** |
<br/>
* **GIS + BIM의 연계**
* 지리·지형·지반 등 위치정보(GIS)와 3D모델(형상, 속성정보) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신
<br/>
* **사용자 중심의 Solution 제공**
* 서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계할 수 있는 설계·시공 Solution 제공
<br/>
<br/>
### 2.2 결과(Product)의 변화
* **Copy & Paste로 인해 하향 평준화된 기존 성과물의 품질 향상**
* 과거 수작업으로 시행하면서 발생하던 오류 등의 최소화
* 정확한 Data에 기반한 계획으로 고품질 성과물 도출
<br/>
* **Analogue 기반 도서 외 Digital 기반 정보물 추가**
* 기존 성과물(도면, 수량, 계산서, 시방서 등)에 3D 모델, Simulation 등의 Digital 기반 정보물 추가
<br/>
* **Solution을 활용한 업무 효율화**
* Engn. Solution을 통해 성과물에 관한 이슈를 함께 검토·논의하는 협업 환경 조성
* 건설 단계별 정보를 디지털 데이터로 축적하여, 건설 전 과정을 통합관리
<br/>
---
:::note[핵심 요약]
* **DX는 필요한 요건과 체계를 갖춘 후 시행해야만 그 효과를 기대할 수 있다.**
:::

Some files were not shown because too many files have changed in this diff Show More