본문으로 건너뛰기

Figma 퍼블리싱 파이프라인 08. v5: Phase 4→5 자동 연동

·8 min read·8 / 8

v5 파이프라인: Phase 4→5 자동 연동 구현

목표

Figma 디자인 노드를 Code 파일로 자동 매칭하여 Design ↔ Code 정확한 비교

구현 완료

1. phase4_design_ir.py (391-398줄)

목표: Design IR 출력에 root 필드 추가 → Phase 5에서 원본 노드 정보 추출 가능

변경:

# 변경 전
output = {
    "meta": {"timestamp": ..., "total_nodes": len(design_ir_nodes)},
    "nodes": design_ir_nodes
}
 
# 변경 후
output = {
    "meta": {"timestamp": ..., "total_nodes": len(design_ir_nodes)},
    "root": design_ir_nodes[0] if design_ir_nodes else None,  # ← 추가
    "nodes": design_ir_nodes
}
 
# 또한 None 값 필터링 추가
design_ir_nodes = [n for n in design_ir_nodes if n is not None]

이유:

  • Phase 5가 design_ir의 root.name으로 원본 페이지명을 추출하려면 필요
  • 섹션 노드들(LNB, Main Content)의 이름도 폴백으로 활용 가능

결과:

{
  "meta": {"timestamp": 1776069686, "total_nodes": 2},
  "root": {
    "nodeId": "21495:202306",
    "name": "LNB",
    "children": [...]
  },
  "nodes": [...]  # 모든 노드
}

2. phase5_code_ir.py (다중 개선)

A) raw.json 기반 원본 노드명 추출 (296-352줄)

목표: 원본 페이지 이름(한글)을 raw.json에서 직접 추출

변경:

# raw.json → 원본 nodeId의 페이지명 추출
if raw_path.exists():
    with open(raw_path) as f:
        raw_data = json.load(f)
        if "nodes" in raw_data and "root" in raw_data["nodes"]:
            node_name = raw_data["nodes"]["root"].get("name", "")
            # 예: "CPA 외부 입력폼 현황"
 
# design_ir → 섹션 노드명 추출 (fallback)
if not node_name and design_ir_path.exists():
    children = root_node.get("children", [])
    section_names = [c.get("name") for c in children if c.get("name")]
    if section_names:
        node_name = section_names[0]  # 예: "LNB"

이유:

  • raw.json이 원본 페이지 정보(Design 루트 노드)를 보유
  • design_ir은 섹션들이므로 원본 이름이 손실됨
  • 폴백: design_ir의 섹션 이름으로도 패턴 매칭 가능

결과:

원본 노드명 (raw.json): CPA 외부 입력폼 현황
케밥케이스: cpa-외부-입력폼-현황 (한글이라 실패)
fallback: design_ir 첫 섹션 "LNB" → lnb
    → 패턴 매칭으로 lnb-layout-provider.tsx 발견

B) --page-path 옵션 추가 (284줄, 290-303줄)

목표: 페이지 경로로 정확한 _source/components 폴더 찾기

변경:

# 파라미터 추가
parser.add_argument("--page-path", 
    help="페이지 경로 (/monitoring/cpa-custom-form) — 정확한 폴더 찾기용")
 
# 페이지 경로로 폴더 찾기 로직
if args.page_path:
    page_path = Path(args.page_path.strip("/"))
    code_path_obj = Path(args.code_path)
    
    candidates = [
        code_path_obj / "src/app/(auth)" / str(page_path) / "_source/components",
        code_path_obj / "src/app" / str(page_path) / "_source/components",
        code_path_obj / "src" / str(page_path) / "_source/components",
    ]
    
    for candidate in candidates:
        if candidate.exists():
            args.code_path = str(candidate.resolve())
            print(f"📍 페이지 경로로 폴더 찾음: {candidate.relative_to(code_path_obj)}")
            break

이유:

  • 한글 페이지명으로는 패턴 매칭 불가
  • --page-path로 직접 폴더 지정하면 모든 tsx 파일 정확히 스캔
  • 불필요한 모든 페이지의 컴포넌트를 읽지 않아 효율성 증대

사용 예:

orchestrate_v5.py \
  --page-path "/monitoring/cpa-custom-form" \
  ...

결과:

입력: /monitoring/cpa-custom-form
찾은 폴더: src/app/(auth)/monitoring/cpa-custom-form/_source/components
코드 노드: 44 (전체 730개 중 정확한 페이지만)

C) code_ir.json 메타데이터 (413-416줄)

목표: Phase 5가 발견한 파일 정보를 메타데이터에 저장 → Phase 7 참조용

변경:

output = {
    "meta": {
        "timestamp": int(__import__("time").time()),
        "total_nodes": len(code_ir_nodes),
        "matched_file": str(target_file.resolve()) if target_file else None,  # ← 추가
        "source_dir": str(code_path.resolve())  # ← 추가
    },
    "nodes": code_ir_nodes
}

이유:

  • Phase 7 (매칭 엔진)이 어느 파일에서 스캔했는지 알아야 함
  • 추후 Code IR 재사용 시 파일 참조 가능

결과:

{
  "meta": {
    "timestamp": 1776069686,
    "total_nodes": 44,
    "matched_file": "/Users/taehoon/.../cpa-custom-form/_source/components/cpa-custom-form-page.tsx",
    "source_dir": "/Users/taehoon/.../cpa-custom-form/_source/components"
  }
}

3. orchestrate_v5.py (547-552줄)

목표: orchestrate에서 --page-path를 Phase 5로 전달

변경:

# Phase 5 arg 조립 (기존)
orch.run_phase(
    5, "phase5_code_ir.py",
    ["--code-path", code_path, "--node-id", args.node_id, "--design-ir", ...],
    ...
)
 
# Phase 5 arg 조립 (변경 후)
phase5_page_path = args.page_path if hasattr(args, 'page_path') and args.page_path else None
 
phase5_args = ["--code-path", code_path, "--node-id", args.node_id, "--design-ir", ...]
if phase5_page_path:
    phase5_args.extend(["--page-path", phase5_page_path])
 
orch.run_phase(
    5, "phase5_code_ir.py",
    phase5_args,
    ...
)

이유:

  • orchestrate가 이미 --page-path를 받음 (앱 자동 감지용)
  • Phase 5에도 같은 정보를 전달하면 정확한 폴더 찾기 가능

작동 흐름

사용자 입력

--page-path "/monitoring/cpa-custom-form" (선택사항)
--file-key "MiI74Bwt1BQ89xxzaMQ81u"
--node-id "21495:202305"

Phase 0-3: Figma API + 딥 분석

Phase 4: Design IR 생성
  └─ root 필드에 첫 노드 저장

Phase 5: Code IR 생성
  ├─ IF --page-path 있음:
  │   └─ src/app/(auth)/{page-path}/_source/components 폴더 직접 사용
  │       → 44개 코드 노드 추출
  ├─ ELSE (--page-path 없음):
  │   ├─ raw.json에서 원본 페이지명 추출
  │   │   → "CPA 외부 입력폼 현황"
  │   ├─ 케밥케이스 변환 (한글 → 실패)
  │   └─ fallback: design_ir 섹션명 사용
  │       → "LNB" → lnb-layout-provider.tsx
  │       → 730개 모든 파일 스캔 (비효율)

Phase 6-8: 정규화 + 매칭 + Diff
  ├─ Phase 7: Code 파일 기준으로 Design과 매칭
  └─ 결과: cpa-custom-form-* 완벽 매칭

Phase 9-13: 리포트 생성 + 검증 + 정리

성능 비교

--page-path 없이

Code 노드: 118 (모든 _source/components)
매칭된 : 27개
미매칭: 1748개
결과: marketer-member-* 불필요하게 포함 (1211 diffs)

--page-path 포함

Code 노드: 44 (정확한 페이지만)
매칭된 : 16개
미매칭: 1759 (Design 구조 차이)
결과: cpa-custom-form-* 올바르게 매칭 (1186 diffs)

개선 사항:

  • diff 개수 감소: 1211 → 1186 (-25개, -2%)
  • Code 스캔 효율: 118 → 44 노드 (-63%)
  • 파일 매칭 정확도: 53개(marketer) → 0개

핵심 설계

레이어목표구현
Phase 4원본 Design 정보 보존root 필드 추가
Phase 5 (일반)다양한 경로 대응raw.json + design_ir fallback
Phase 5 (최적)정확한 폴더 찾기--page-path 직접 사용
Phase 7올바른 매칭정확한 파일 기준 비교

검증 결과

세션: 1776069686_379293_d5906b

✅ Phase 0-13 완전 통과 (20.9초)
✅ pnpm type-check 통과
✅ cpa-custom-form 모든 코드 ID 올바른 매칭
✅ 불필요한 marketer-member 제거됨

사용 가이드

최적 사용법

orchestrate_v5.py \
  --file-key "MiI74Bwt1BQ89xxzaMQ81u" \
  --node-id "21495:202305" \
  --app admin \
  --page-path "/monitoring/cpa-custom-form"  # ← 추가

폴백 사용법 (한글 페이지명도 동작)

orchestrate_v5.py \
  --file-key "MiI74Bwt1BQ89xxzaMQ81u" \
  --node-id "21495:202305" \
  --app admin
  # --page-path 없이도 작동 (raw.json + design_ir fallback)

확장 가능성

향후 개선 방향

  1. 자동 page-path 감지: URL 패턴에서 page-path 자동 추출
  2. 캐싱: raw.json → page-path 매핑 캐시 (재실행 시 빠름)
  3. 에러 처리: page-path 잘못됐을 때 자동 폴백
  4. 멀티 페이지: 여러 페이지를 한 번에 처리