# B+D 이미지 템플릿 시스템 설계서

**작성일:** 2026-03-29
**작성자:** 오딘 (dev2-team 팀장)
**근거:** task-1251.1 에이전트 미팅 3사이클 합의

---

## 1. 개요

### 방법 B+D란 무엇인가

방법 B+D는 두 가지 역할의 결합이다.

- **D (제이회장님)**: Canva에서 핵심 레이아웃 기본틀을 직접 제작하는 역할. 배경 비주얼, 구도, 색상 팔레트, 전체적인 디자인 톤앤매너를 결정한다. 최종 PNG로 export할 때는 텍스트 레이어를 제외한 순수 배경 이미지만 출력한다.
- **B (에이전트)**: 기본틀을 입력받아 텍스트와 색상만 교체하는 템플릿 시스템. 배경 PNG 위에 HTML/CSS로 텍스트를 오버레이하고 Playwright로 렌더링한다.

결과적으로 디자인 퀄리티는 D(제이회장님)가 Canva에서 보증하고, 대량 변형 생산은 B(에이전트)가 담당하는 역할 분리 구조다.

### 기존 방법(HTML/CSS → Playwright) 대비 장점

| 구분 | 기존 방법 | B+D 방법 |
|------|----------|---------|
| 레이아웃 품질 | 코드로 디자인 재현 — 폰트·자간·여백이 Canva와 달라짐 | Canva 원본 PNG를 배경으로 사용 — 디자인 품질 그대로 보존 |
| 재현성 | 브라우저 버전·환경에 따라 렌더링 결과가 달라짐 | 배경은 고정 PNG, 텍스트만 HTML로 제어 — 환경 의존성 최소화 |
| 폰트 문제 | Canva 유료 폰트가 HTML에서 깨짐 (v4 실패 사례) | 공용 폰트 4종으로 통일 — Canva·HTML 양쪽에서 동일하게 렌더링 |
| 생산 속도 | 새 컨셉마다 전체 HTML/CSS를 다시 작성 | Zone 명세서(JSON)만 교체하면 동일 배경에서 무제한 변형 생산 가능 |
| QC 결합 | 렌더링 오류를 사후 발견 | overflow_policy: reject — 오버플로우 발생 즉시 렌더링 자체를 중단 |

---

## 2. 전체 워크플로우

### 2.1 제이회장님 Canva 작업 단계

1. **마스터 템플릿 제작**: Canva에서 캠페인 컨셉에 맞는 배경 레이아웃을 제작한다. 이 단계에서 색상 팔레트, 이미지 요소 배치, 전체 구도가 결정된다.
2. **텍스트를 플레이스홀더로 배치**: Canva 내부에서 텍스트 레이어는 최종 위치와 크기를 가이드 목적으로만 배치한다. 실제 텍스트 내용은 에이전트가 교체할 것이므로 플레이스홀더로 취급한다.
3. **배경 PNG로 export**: 텍스트 레이어를 **제외한** 순수 배경 이미지만 PNG로 export한다. 이 파일이 에이전트의 렌더링 기반이 된다.
4. **텍스트 존 좌표를 JSON 명세서로 문서화**: 텍스트가 들어갈 영역(Zone)의 좌표(x, y, width, height), 최대 글자 수, 폰트 크기 범위, 정렬 방향 등을 JSON 명세서로 작성한다. 이 명세서가 에이전트의 렌더링 설계도가 된다.
5. **명세서 등록 및 검증**: 아마테라스가 명세서를 작성하면 마아트가 더미 텍스트(max_chars 길이)로 자동 테스트 렌더링을 실행하여 명세서 자체의 오류를 검증한다. 승인 후 생산에 투입된다.

### 2.2 에이전트 변형 생산 단계

1. **JSON 명세서 로드**: 템플릿 ID로 해당 Zone 명세서를 로드한다.
2. **배경 PNG 위에 HTML/CSS로 텍스트 오버레이**: 배경 PNG를 CSS background로 설정하고, 각 Zone 좌표에 HTML 텍스트 요소를 절대 위치(position: absolute)로 배치한다.
3. **overflow_policy: "reject"**: 텍스트가 Zone을 벗어나면 렌더링을 즉시 중단하고 오류를 반환한다. "덜 나쁜 결과물"을 만들지 않는다.
4. **auto_fit: shrink_font**: Zone 안에 텍스트가 들어가지 않을 때 폰트를 자동으로 축소한다. 단, min_font_before_reject 값 미만으로는 축소하지 않으며, 해당 임계값에 도달하면 reject로 처리한다.
5. **Playwright 렌더링**: HTML을 Playwright로 캡처하여 최종 PNG를 생성한다.

### 2.3 QC 통합 (파이프라인 잠금)

생산 결과물은 파이프라인 잠금 장치(완료 토큰 시스템)와 통합된다. 각 QC 단계의 토큰이 발급되지 않으면 다음 단계로 진행할 수 없다.

- **자동 QC 8종**: 렌더링 직후 코드로 즉시 실행. A1~A3은 B+D 템플릿 시스템 전용 신규 항목.
- **수동 QC 5종**: 역할 분산 구조 — 아프로디테(B1~B2), 아마테라스(B3), 마아트(B4~B5).

---

## 3. 텍스트 존(Zone) 명세서 스펙

### 3.1 JSON 스키마 v1.0

Cycle 2에서 아마테라스가 작성하고 전원 만장일치로 확정된 표준 스키마 (DR-13).

```json
{
  "$schema": "text-zone-spec-v1",
  "template_id": "tmpl_20260329_001",
  "template_name": "보험_상담유도_1080x1080",
  "canvas_size": {
    "width": 1080,
    "height": 1080,
    "unit": "px",
    "export_dpi": 72
  },
  "background": {
    "type": "canva_png_export",
    "file": "bg_tmpl_001.png",
    "source_canva_id": "CANVA_DESIGN_ID_HERE"
  },
  "font_config": {
    "primary_font": "Noto Sans KR",
    "fallback_font": "Pretendard",
    "source": "google_fonts",
    "canva_font_override": "동일 폰트 사용 필수"
  },
  "zones": [
    {
      "zone_id": "headline",
      "label": "메인 헤드라인",
      "anchor": {
        "x": 80,
        "y": 200,
        "width": 920,
        "height": 180
      },
      "text_constraints": {
        "max_chars": 20,
        "min_chars": 5,
        "max_lines": 2,
        "overflow_policy": "reject"
      },
      "typography": {
        "font_size_range": { "min": 42, "max": 60 },
        "font_weight": "700",
        "line_height": 1.3,
        "letter_spacing": "-0.02em",
        "text_align": "left",
        "color": "#1A1A1A",
        "bg_contrast_min": 4.5
      },
      "auto_fit": {
        "enabled": true,
        "strategy": "shrink_font",
        "min_font_before_reject": 38
      }
    },
    {
      "zone_id": "sub_copy",
      "label": "서브카피",
      "anchor": {
        "x": 80,
        "y": 400,
        "width": 780,
        "height": 120
      },
      "text_constraints": {
        "max_chars": 40,
        "min_chars": 10,
        "max_lines": 2,
        "overflow_policy": "reject"
      },
      "typography": {
        "font_size_range": { "min": 22, "max": 30 },
        "font_weight": "400",
        "line_height": 1.5,
        "letter_spacing": "0",
        "text_align": "left",
        "color": "#444444",
        "bg_contrast_min": 4.5
      },
      "auto_fit": {
        "enabled": true,
        "strategy": "shrink_font",
        "min_font_before_reject": 18
      }
    },
    {
      "zone_id": "cta_button",
      "label": "CTA 버튼 텍스트",
      "anchor": {
        "x": 80,
        "y": 920,
        "width": 360,
        "height": 80
      },
      "text_constraints": {
        "max_chars": 12,
        "min_chars": 4,
        "max_lines": 1,
        "overflow_policy": "reject"
      },
      "typography": {
        "font_size_range": { "min": 20, "max": 26 },
        "font_weight": "600",
        "line_height": 1.0,
        "letter_spacing": "0.02em",
        "text_align": "center",
        "color": "#FFFFFF",
        "bg_contrast_min": 4.5
      },
      "auto_fit": {
        "enabled": false
      }
    }
  ],
  "qc_hooks": {
    "pre_render": ["text_length_validation", "font_availability_check"],
    "post_render": ["overflow_detection", "contrast_ratio_check", "resolution_check"],
    "pilot_required": true,
    "pilot_selection_strategy": "extreme_case_auto"
  },
  "version": "1.0.0",
  "created_by": "아마테라스",
  "created_at": "2026-03-29"
}
```

### 3.2 Zone 속성 설명

| 속성 | 설명 |
|------|------|
| `zone_id` | Zone의 고유 식별자. 에이전트가 텍스트를 어떤 Zone에 배치할지 참조하는 키. |
| `anchor.x / anchor.y` | Zone의 좌상단 좌표 (px 단위, 캔버스 원점 기준). |
| `anchor.width / anchor.height` | Zone의 너비와 높이. 텍스트는 이 영역 안에 들어와야 한다. |
| `text_constraints.max_chars` | Zone에 허용되는 최대 글자 수. 이 값을 초과하는 텍스트는 overflow_policy에 따라 처리된다. |
| `text_constraints.min_chars` | 최소 글자 수. 너무 짧은 텍스트로 인한 시각적 공백을 방지한다. |
| `text_constraints.max_lines` | 최대 줄 수. 줄 바꿈 처리 기준. |
| `text_constraints.overflow_policy` | `"reject"` — 오버플로우 발생 시 렌더링 중단. 현재 이 값만 허용한다. |
| `typography.font_size_range` | 폰트 크기의 최솟값과 최댓값. auto_fit이 활성화된 경우 이 범위 안에서 자동 조정된다. |
| `typography.bg_contrast_min` | 배경 대비율 최솟값 (WCAG AA 기준 4.5). 자동 QC A2가 이 값을 기준으로 검증한다. |
| `auto_fit.enabled` | 텍스트 오버플로우 시 폰트 자동 축소 활성화 여부. |
| `auto_fit.strategy` | `"shrink_font"` — 폰트 크기를 줄여서 Zone에 맞추는 전략. |
| `auto_fit.min_font_before_reject` | 이 값 미만으로 폰트가 축소되어야 하는 상황이 오면 reject 처리. |
| `qc_hooks.pre_render` | 렌더링 전 실행되는 검증 목록. 텍스트 길이 검증, 폰트 가용성 확인. |
| `qc_hooks.post_render` | 렌더링 후 실행되는 검증 목록. 오버플로우 탐지, 대비율 확인, 해상도 확인. |

### 3.3 명세서 유효성 검증

명세서 자체도 QC 대상이다. 명세서가 잘못 작성되면 자동 QC가 잘못된 기준으로 작동하기 때문이다(Cycle 2, 로키 공격 반영).

1. **등록 시 더미 텍스트 자동 테스트 렌더링**: 명세서 최초 등록 시 각 Zone에 `max_chars` 길이의 더미 텍스트를 자동으로 배치하여 렌더링한다. 시각적으로 이상 없을 때만 명세서를 "승인" 상태로 전환한다.
2. **마아트 명세서 QC 승인**: 자동 테스트 결과물을 마아트가 육안으로 확인하고 최종 승인한다. 승인 전까지 해당 템플릿은 생산에 사용할 수 없다.
3. **bbox 시각화 첨부 권고(RR-02 반영)**: 명세서 등록 시 Zone bbox와 이미지 요소 bbox를 화면에 오버레이한 시각화 결과물을 명세서와 함께 제출하는 것을 권고한다. 좌표 착오를 사전에 방지한다.

---

## 4. 폰트 통일 정책

### 4.1 폰트 정책: 자유 선택 (DR-13 폐기, 제이회장님 지시 2026-03-29)

**"폰트도 디자인이다. 다양해야 한다."** — 제이회장님

폰트 종류 제한 없음. 디자인 컨셉에 맞는 폰트를 자유롭게 선택한다.

**유일한 제약: Canva 유료 독점 폰트(HTML 렌더링 불가) 제외**
- Canva 유료 독점 폰트(예: Canva Sans)는 HTML에서 동일 렌더링이 불가능하므로 제외
- Google Fonts, 오픈소스(SIL OFL) 폰트는 자유 사용 가능
- 위반 기준: Canva 유료 독점 폰트 사용 시에만 마아트가 템플릿 등록 거부

---

## 5. 파일럿 생산 게이트

배치 생산 전 반드시 파일럿 3개를 생산하고 QC를 통과해야 한다. "컨셉이 좋으면 생산도 잘 될 것"이라는 가정이 실패의 근본 원인이었다(Cycle 1 3 Whys 분석).

### 5.1 극단 케이스 자동 선정 알고리즘

파일럿이 대표성을 갖지 못하면 파일럿 자체가 무의미하다(로키 공격). 극단 케이스 3종을 자동으로 선정하여 가장 어려운 케이스를 먼저 검증한다.

```
입력: 배치 생산 대상 이미지 목록 (N개)
출력: 파일럿 후보 3개

선정 기준 (각 Zone별 계산):

1. [텍스트 밀도 극단값]
   = 각 이미지의 (헤드라인 글자 수 / max_chars) 가장 높은 것
   → 텍스트가 Zone을 가득 채우는 최악의 오버플로우 시나리오

2. [Zone 겹침 극단값]
   = 각 이미지에서 이미지 요소(로고, 일러스트 등) bbox와
     텍스트 Zone bbox의 IoU(교차면적/합집합면적) 가장 높은 것
   → 텍스트가 이미지 요소와 가장 많이 겹치는 시나리오

3. [폰트 크기 최소값]
   = 예상 font_size_range.min이 가장 작은 것
   → 폰트가 가장 작아서 가독성 위협이 가장 큰 시나리오

→ 3가지 기준에서 각 1개씩 선정 (중복 시 다음 순위로 대체)
```

IoU 계산에 필요한 이미지 요소 bbox는 Zone 명세서에 `image_elements` 필드로 디자이너가 기입한다. 에이전트는 이 값을 읽어 자동으로 계산한다.

### 5.2 파일럿 → 배치 전환 조건

| 조건 | 결과 |
|------|------|
| 파일럿 3개 모두 통과 + 아마테라스 OK 사인 | 배치 생산 승인 (Phase 2.5 통과) |
| 파일럿 1개라도 실패 | 전체 배치 중단 + 원인 수정 + 재파일럿 |

---

## 6. 컨셉 퀄리티 보존 검증 방법

### 6.1 근본 원인 (50컨셉 → 15선 → 생산 망가짐)

Cycle 1 3 Whys 분석에서 도출된 근본 원인은 두 가지다.

1. **컨셉 품질과 생산 품질의 개념 혼동**: 컨셉 단계에서 "좋아 보이는 이미지"는 디자이너가 수동으로 만든 것이다. 코드로 재현하면 다른 결과가 나온다. 컨셉 QC를 통과했다고 생산 품질이 보장되지 않는다.
2. **생산 방법의 재현성 부재**: HTML/CSS 렌더링은 브라우저 버전, 폰트 설치 여부, 해상도에 따라 결과가 달라진다. QC가 OK한 결과물과 실제 배포 결과물이 다를 수 있다.
3. **파일럿 없이 배치 생산**: 15개를 선택하고 바로 배치 생산에 들어갔다. 생산 방법의 문제를 미리 검증하는 단계가 없었다.

### 6.2 검증 체계

각 Phase에서 어떤 품질 차원을 검증하는지 역할이 명확히 나뉜다.

| Phase | 검증 내용 | 담당 |
|-------|----------|------|
| Phase 0.5 | 브리프 단계에서 기획 방향 사전 검증 (10점 기준) | 마아트 |
| Phase 1.5 | 카피 기획의 방향성·실현 가능성 검증 (14점 기준, 사이클별 임계값 적용) | 마아트 + 아마테라스 |
| Phase 2.5 | 파일럿 극단 케이스 3종 — 생산 방법의 기술적 문제 검증 | 아마테라스 + 마아트 |
| Phase 3 (자동 QC 8종) | 렌더링 결과의 기술적 완성도 검증 | 시스템 자동 |
| Phase 4 (수동 QC 5종) | 마케팅 효과성 + 시각 밸런스 + 프로 수준 검증 | 아프로디테·아마테라스·마아트 |
| 사후 검증 | 배포 후 2주 내 실제 CTR 데이터로 컨셉 효과 검증 | 시스템 자동 플래그 (P2 구현) |

### 6.3 전환 트리거

단기 방법(옵션 1: Canva PNG + HTML 오버레이)으로 시작하되, 관성에 의한 현상 유지를 막기 위해 명시적 전환 조건을 사전에 합의했다(DR-15).

- **전환 트리거**: 옵션 1로 렌더링 오류가 **월 5건 이상** 발생하면 Figma 전환 검토 착수
- **트리거 발동 전**: Canva API 재조사 불필요
- **트리거 발동 후**: Figma API 활용 방안(텍스트 노드 직접 수정 + PNG export) 기술 검토 착수

---

## 7. 파이프라인 잠금 장치 (완료 토큰 시스템)

소프트 잠금(알림만)이 아니라 하드 잠금(진행 물리적 차단)으로 설계되었다(DR-17). QC 스킵 관행이 납기 압박 시에도 발생하지 않도록 하는 구조다.

### 7.1 토큰 발급 주체

| 토큰명 | 발급 주체 | 발급 조건 |
|--------|----------|----------|
| `BRIEF_QC_OK` | 마아트 | Phase 0.5 브리프 QC 점수 기록 + 8점 이상 |
| `COPY_DRAFT_OK` | 시스템 자동 | Phase 1 완료 + Phase 0.5 토큰 보유 필수 |
| `PLAN_QC_OK` | 마아트 | Phase 1.5 기획 QC 점수 기록 + 사이클별 임계값 이상 |
| `PILOT_OK` | 아마테라스 + 마아트 | Phase 2.5 파일럿 3개 모두 통과 + 공동 서명 |
| `AUTO_QC_OK` | 시스템 자동 | 자동 QC A1~A8 전 항목 통과 |
| `MANUAL_QC_OK` | 3인 서명 (아프로디테, 아마테라스, 마아트) | 수동 QC B1~B5 전 항목 서명 완료 |

배포 실행 조건: `AUTO_QC_OK` + `MANUAL_QC_OK` 두 토큰 모두 보유 시에만 가능.

### 7.2 바이패스 조건

긴급 상황에서 바이패스를 완전히 차단하면 실무에서 운용이 불가능해진다. 대신 바이패스 자체를 기록하여 자기 보정 구조를 만든다.

- **바이패스 실행 조건**: 사장 계정 승인 + 사유 로그 (삭제 불가)
- **바이패스 제한**: 월 2회 이상 → 다음 월 QC 회의 의무 안건으로 상정
- **긴급 등급 조건(Phase 0.5/1.5 우선 처리)**: 캠페인 런칭 D-3일 이내 AND 임원 승인 — 두 조건 모두 충족 시에만 적용

### 7.3 상태 저장

각 태스크별 상태는 `pipeline_state.json`에 저장된다.

```json
{
  "task_id": "task-1251",
  "tokens": {
    "BRIEF_QC_OK": {
      "issued_by": "마아트",
      "score": 9,
      "issued_at": "2026-03-29T10:00:00"
    },
    "COPY_DRAFT_OK": {
      "issued_by": "system",
      "issued_at": "2026-03-29T11:30:00"
    },
    "PLAN_QC_OK": null,
    "PILOT_OK": null,
    "AUTO_QC_OK": null,
    "MANUAL_QC_OK": null
  },
  "current_phase": "Phase 1.5",
  "blocked": false
}
```

**저장 경로**: `/tasks/{task_id}/pipeline_state.json`

**바이패스 방지 원칙**:
- 토큰 파일은 에이전트 런타임이 읽기 전용으로 마운트
- 토큰 발급은 별도 QC 서비스(마아트 계정 인증)를 통해서만 가능
- 자동 QC 실패 시 오류 보고서 없이 재실행 불가 (오류 인정 로그 강제)

---

## 8. 구현 로드맵

### P0 — 즉시 구현 (이번 주, 다음 캠페인 착수 전 필수)

| # | 과제 | 담당 | 완료 기준 |
|---|------|------|----------|
| P0-1 | **qc-master-checklist-v1.json 파일 작성** | 마아트 + 아마테라스 | `/tasks/qc-master-checklist-v1.json` 파일 생성 완료. Phase 0.5 5항목 + Phase 1.5 7항목 + 자동 QC 8항목 + 수동 QC 5항목 전체 기입. |
| P0-2 | **파이프라인 잠금 장치 MVP 구현** | 에이전트/개발팀 | 토큰 파일 읽기 + 미보유 시 예외 발생 최소 기능 구현. 테스트 태스크에서 토큰 없이 다음 Phase 진입 시 예외 발생 확인. |
| P0-3 | **자동 QC A1 (텍스트 오버플로우) 코드 구현** | 에이전트/개발팀 | 기존 Playwright 파이프라인에 `scrollWidth > clientWidth` 체크 통합. 단위 테스트 통과. |
| P0-4 | **Zone 명세서 파일럿 1개 실행** | 아마테라스 주도 | Canva 템플릿 1개 선택 → Zone 명세서 JSON 작성 → 더미 텍스트 자동 테스트 렌더링. 결과물 시각 확인 완료, 명세서 포맷 이상 없음 확인. |

### P1 — 2주 내 구현

| # | 과제 | 담당 | 완료 기준 |
|---|------|------|----------|
| P1-1 | **자동 QC A2 (대비율 worst-case) + A3 (폰트 크기) 코드 구현** | 에이전트/개발팀 | A2: Pillow/sharp 기반 worst-case pixel 대비율 계산 단위 테스트 통과. A3: computed CSS font-size 추출 단위 테스트 통과. |
| P1-2 | **마케팅 효과성 복수 평가 운영 방법론 문서화** | 아프로디테 | 평가자 풀 구성, 평가 실행 절차, 척도 앵커 예시, 집계 방법 1페이지 운영 가이드 완성. |
| P1-3 | **Zone 명세서 현보유 Canva 템플릿 전수 등록** | 아마테라스 | 현재 보유 모든 템플릿에 대해 Zone 명세서 JSON 작성 완료 + 마아트 명세서 QC 통과. |
| P1-4 | **반복 사이클 1회 전체 실행 + 소요시간 측정** | 전원 참여 | Phase 0~4 전 단계 실제 통과 기록 + 단계별 소요시간 측정표 작성. |
| P1-5 | **D-5일 규칙 예외 조건 사전 정의 (최우선)** | 아프로디테 + 마아트 | 허용 예외 사유 목록 + 각 예외별 처리 절차 1페이지 문서화. P1 중 최우선 착수. |

### P2 — 1개월 내 구현

| # | 과제 | 담당 | 완료 기준 |
|---|------|------|----------|
| P2-1 | **파이프라인 잠금 장치 완전 구현** | 에이전트/개발팀 | P0-2 MVP에서 완전한 서비스로 업그레이드. 마아트 계정 인증 연동. 바이패스 로그 삭제 불가 구현. |
| P2-2 | **CTR 사후 검증 자동 플래그 생성 연동** | 에이전트/개발팀 | 배포 2주 후 CTR 데이터 자동 수집 + 기준 미달 시 기획 재검토 플래그 자동 생성. |
| P2-3 | **전환 트리거 모니터링 대시보드** | 에이전트/개발팀 | 렌더링 오류 자동 집계 + 월 5건 트리거 임박 시 알림 발송 구현. |
| P2-4 | **마아트 백업 체제 공식 문서화** | 마아트 주도 | 대행 조건(아마테라스/아프로디테/외부 컨설턴트), 적용 범위(긴급 조건 한정), 로그 기록 의무 포함 1페이지 문서. 피크 시즌 수요 예측 포함(RR-01). |
| P2-5 | **월간 품질 회고 회의 구조 문서화 + 1회차 실시** | 전원 | 4개 의무 안건 포함 회고 템플릿 작성 + 첫 번째 월간 회고 실시 및 회의록 저장. 회고 결과 개선 결정 사항 이행 추적 섹션 포함(RR-05). |

---

## 부록: 참고 문서

- 미팅 기록:
  - `meetings/task-1251.1-meeting-cycle1.md` — 문제 정의 및 초안 제안
  - `meetings/task-1251.1-meeting-cycle2.md` — JSON 스키마 확정, 파이프라인 잠금 장치 설계
  - `meetings/task-1251.1-meeting-cycle3.md` — 전원 만장일치 확정, DR-10~DR-22, 구현 우선순위
- 워크플로우 계획서: `specs/image-workflow-v2-plan.md` (v2.2 — B+D 합의사항 반영 완료)
- QC 노하우: `specs/design-qc-knowhow.md`
