---
title: 작업보고 — 스튜디오 빌더 프레임 리빌딩(operation JSON 직접 발행·미리보기=실앱)
category: workreport
document_type: 작업보고
source_status: published
knowledge_group: 03_history
priority: Normal
purpose: 스튜디오 구조변경 마크다운→operation JSON 직접발행으로 전환 — 미리보기=실앱 달성
read_when: 스튜디오 빌더·operation JSON·구조변경 발행·studioRuntime 관련 작업 시
updated: 2026-06-22
work_timestamp: 20260622_103901
source_of_truth: dallog-tools
---

# 작업보고 — 스튜디오 빌더 프레임 리빌딩 (operation JSON 직접 발행)

## 한 줄 요약
스튜디오 빌더가 구조 변경을 "마크다운 초안 → CC가 해석해 코드 반영"으로 우회하던 구조를, **사용자가 미리보기에서 만진 결과(operation JSON)를 실앱이 똑같은 코드로 그대로 적용**하는 구조로 갈아엎었다(미리보기=실앱, 사람·AI 해석 0). 비개발자 사장님이 화면을 보며 직접 UI를 조정·발행할 수 있게 하는 것이 목표.

## 배경 — 왜 뼈대를 다시 세웠나
- 기존 B(구조변경)는 iframe DOM 비파괴 프리뷰 + **마크다운 초안**을 만들어 CC에게 넘기는 방식이었다. 실제 코드 반영은 CC가 마크다운을 "해석"해서 했다.
- 사장님 지적(정당): "목업 HTML을 주고 코드 100% 그대로 이식하라는, 해석 여지가 거의 없는 지시조차 임의로 바꿔 못 지켰는데, 그보다 해석 여지가 훨씬 큰 마크다운을 어떻게 믿느냐." → 마크다운 전달은 또 다른 해석 레이어라 100% 실행 보장 불가.
- 또한 "코드로 내가(CC) 고치면 2일 밤새워 만든 스튜디오 의미가 없다 — 핵심은 사장님이 프리뷰 보며 직접 고치는 것"(매번 CC에게 더듬어 설명·CC가 추측하는 방식의 제거).
- 결론: SoT(source of truth)는 마크다운(사람용 설명)이 아니라 **사용자가 프리뷰에서 확정한 operation JSON/patch**여야 한다. 그게 이미 `StudioDoc.structureOps`로 존재했는데도 "마크다운 초안용"으로만 쓰고 발행 파이프라인에 안 태운 게 설계 실수였다.

## 진행 (구현 내역)
- **런타임 적용기 `src/lib/studioRuntime.ts` 신설**: 발행물(studio-overrides.css)의 `@studio-doc`(doc 전체 base64 임베드) 안 structureOps를 읽어, 미리보기(MiniBrowser)가 쓰는 **것과 똑같은 `applyAllOps`/`applyLiveOp`**로 실앱 DOM에 적용. 같은 코드+같은 데이터 → 정의상 미리보기=실앱, 해석 0. 발행된 op 없으면 완전 no-op(서비스 영향 0). MutationObserver로 React 리렌더 후 재적용(disconnect→적용→reconnect 무한루프 방지), popstate 재적용.
- **잡으면 끌리기**: onDown이 "선택된 요소"에만 드래그 허용하던 의존 제거 → 선택 없이 잡은 요소를 바로 끈다(피그마식). computeDrop·onDrop이 '잡은 요소(srcEl)' 기준.
- **덩어리 잡기(liftDragTarget)**: 작은 글자·아이콘을 잡아도 card/metric/tile/item 등 의미 단위(카드·버튼)까지 끌어올림. "카드 옮기려는데 안쪽 숫자가 잡히는" 문제 해소.
- **같은 영역 순서 바꾸기(computeDrop (0) 형제 우선)**: 끄는 요소와 같은 부모를 만나면 그 형제 옆(앞/뒤)에 놓음 — 카드를 옆 카드 위에 놓을 때 그 카드 '안'으로 빨려들던 문제 해소. 그리드는 2D(위/아래 칸) 판정.
- **없는 요소 새로 만들기**: insert op을 자리표시 placeholder가 아니라 `createNewElement`(버튼/글자/박스, 프리뷰·실앱 공용)로 실제 생성. StructurePanel에 종류 선택 + 글자 입력 UI. studioRuntime이 insert/remove(숨김)/clone(복제)을 라이브 적용(op.id 마커로 중복 방지=idempotent).
- **데스크탑 프리뷰 16:9**(1920×1080 비율) — 실제 데스크탑 화면비. 모바일은 세로 프레임 유지(모바일까지 16:9로 만들지 않음).
- **편집 속성 전수 보강 + 전 한글화**: 글자(기울임·밑줄·대소문자·줄바꿈·단어끊기·긴글자·말줄임)·크기(최소/최대)·여백(상하좌우 개별·줄/칸 간격)·배치(display·align-self)·위치(position·top/right/bottom/left·z-index)·모양색(border-style·overflow·커서) 약 54속성. 라벨·값 모두 한글(예: 글자 줄바꿈 → 자동 줄바꿈/한 줄로 고정), CSS 원문은 tooltip 보조. **"그 밖의 속성 직접 입력" 칸** = 목록에 없는 CSS도 즉석 적용하는 안전망("없는 속성" 상황 자체 제거).

## 핵심 의사결정
- **SoT = operation JSON, 마크다운은 곁다리(사람 검토용)**. 실행은 op 데이터, 미리보기와 실앱이 같은 적용 코드.
- **CC가 코드로 대신 고치지 않는다** — 시각/구조는 사장님이 빌더로 직접. 코드가 꼭 필요한 건 새 데이터 연결·계산뿐.
- **땜질 금지·전수 보강**: 속성 하나(white-space) 지적 → 그것만 추가하는 방식 폐기. "비개발자가 화면 보며 당연히 조정해야 하는가" 기준으로 전수 점검 후 일괄 보강 + 자유 입력 안전망.
- **한글 표시명이 사용성의 핵심**(개발자용 CSS 패널 아님). 복잡값(grid-template·transform·aspect-ratio)은 자유 입력 칸으로.

## 검증 (demo 실측 — "구현했다" 아님)
- **라이브 증명**: demo 스튜디오에서 카드를 옆으로 옮김 → 발행 → 진짜 대시보드(/dashboard)에서 카드가 그대로 옮겨져 있음 확인. 새 버튼 추가 op 발행 → 진짜 앱에 `<button>` 실제 생성(`data-studio-live-insert` 마커=런타임 생성) 확인. 미리보기=실앱, 내 손·해석 0.
- 합성 클릭 타이밍으로 op이 미리보기와 어긋나 보인 적 있으나, 제대로 재현하니 실제 드래그는 정상(버그 아님)임을 확인 — 발행 전 보류로 잘못된 발행 차단(빌더의 "발행 전 눈 확인" 가치 입증).
- 빌드·테스트(vitest 94) green 유지.

## Codex 검수 반영
- 프리플라이트 미수행 시 '통과' 오판 차단, 0매칭 등급 error→warn 하향(다른 페이지 전용 룰 오탐 방지), 룰 라벨 별칭 우선, 경고색 토큰화 — 즉시 반영·재검증.
- (격리 관련) 본버전 격리 이중가드는 별도 본버전 패치 작업보고 참조.

## 미해결 / 다음
- B초안(마크다운) → operation data 기록 전환은 토대 완료, 표시·정제 후속.
- 링크 연결(새 버튼에 페이지 이동)·기존 요소 텍스트 수정은 구조 작업(▣)으로 후속.
- CF Pages 자동배포가 연속 push에 자주 누락 → 빈 커밋 재트리거로 대응(Deploy Hook 등 안정화 후속).
