# Listicle 템플릿 가이드 ## 1. 소개 번호가 주인공인 목록형 카드뉴스. "알아두면 좋은 5가지" 처럼 항목을 하나씩 넘기며 읽는 구조라 저장률이 높다. ## 2. 톤 가이드 항목 제목은 **명사형으로 짧게** 쓴다("커밋을 자주 한다" ✗ / "잦은 커밋" ✓). 설명은 "왜 그런지"를 한두 문장으로. 근거 없는 단정과 느낌표 반복을 피한다. 표지의 숫자와 항목 수는 반드시 일치시킨다 — 5가지라고 써놓고 4장만 넣지 않는다. ## 3. 슬라이드 흐름 권장 `cover → item(1~10장) → cta` 순서를 지킨다. - `cover` 의 `count` 에는 **숫자만** 넣는다(예: `"5"`). "가지"는 템플릿이 붙인다. - `item` 의 `index` 는 표지 숫자와 맞춰 `"01"`, `"02"` … 처럼 넣는다. - 항목이 7장을 넘으면 저장률이 떨어진다. 5~7장을 권장한다. ## 4. 슬롯별 작성 요령 아래 슬롯 한계는 등록 시 manifest에서 자동 생성했다. design_max는 디자인 권장 상한이며 초과해도 렌더는 성공하지만 `design_max_exceeded` 경고가 발생한다. max_chars는 실측 하드 상한이며 초과하면 422 `max_chars_exceeded`가 발생한다. 다만 max_chars는 레이아웃 안전을 보장하는 값이 아니라, 같은 글자 수라도 글자 폭이나 줄바꿈에 따라 max_chars 이내에서 렌더 영역을 넘을 수 있다. 이 경우 렌더는 성공하고 결과 이미지와 함께 `text_overflow` 등의 warning을 반환하므로, 경고가 발생한 슬롯의 문구를 더 줄여 다시 렌더한다. 이 수치는 손으로 쓴 것이 아니라 manifest가 원본이다 — 본 가이드와 manifest는 영구히 일치한다. - 요청 크기: `POST /v1/renders`의 전체 JSON 요청 본문 상한은 1,048,576바이트(1MB)다. 초과하면 HTTP 413 `payload_too_large`가 발생한다. - 글쓰기 원칙: 한 슬라이드에 한 주장. 좋은 예: `API 문서를 자동으로 검증하는 법`. 나쁜 예: `정말 놀랍고 엄청난 API 문서 자동화에 관하여 알아볼까요?`. - 브랜딩: `brand_logo_url`은 프로젝트 브랜드 자산(`logo_horizontal`)으로 렌더 시 자동 공급된다. 슬롯 값으로 데이터 URI를 직접 넣지 않는다. - 색상: `accent_color`는 manifest 테마 또는 `brand.colors.accent`의 `#RRGGBB`로 자동 공급된다. - 이미지: `image` 타입 슬롯은 공개 HTTPS URL과 `data:image/;base64,...` 데이터 URI를 모두 허용한다. 실사진은 본문 상한을 피하도록 원격 HTTPS URL을 사용하고, 데이터 URI는 로고·아이콘 같은 작은 자산에만 사용한다. 슬라이드 타입별로 아래 소절을 확인한다. 슬롯 이름·필수 여부·한계값은 manifest에서 생성되며, 타입별 작성 요령은 manifest의 `slide_types[].guidance`가 원본이다. ### `cover` (min 1, max 1) 표지는 '몇 가지인지'가 한눈에 보여야 한다. count 에 숫자만 넣고(예: 5), headline 은 그 숫자가 무엇의 개수인지 한 문장으로. | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `count` | 예 | 텍스트 | | `headline` | 예 | 텍스트 | | `subheadline` | 아니오 | 텍스트 | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `account_name` | 아니오 | 텍스트 | ### `item` (min 1, max 10) 항목 한 장에 하나씩. index 는 표지의 순서와 맞춘다. title 은 명사형으로 짧게, body 는 왜 그런지 한두 문장. | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `index` | 예 | 텍스트 | | `title` | 예 | 텍스트 | | `body` | 예 | 텍스트 | | `note` | 아니오 | 텍스트 | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `account_name` | 아니오 | 텍스트 | ### `cta` (min 1, max 1) 마무리는 행동 하나만 요청한다. 저장·공유·팔로우 중 하나. | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `headline` | 예 | 텍스트 | | `body` | 아니오 | 텍스트 | | `cta_text` | 예 | 텍스트 | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `account_name` | 아니오 | 텍스트 | ## 5. 완성된 slides.json 예시 이미지 슬롯은 **공개 HTTPS URL 과 data URI 를 모두** 받는다. 실사진은 URL 을 쓴다 — 전체 JSON 요청 본문 상한이 1,048,576바이트(1MB)라 실사진을 base64 로 넣으면 두 장에서 넘어간다 (초과 시 HTTP 413 `payload_too_large`). ```json { "template": "listicle", "format": "instagram", "slides": [ { "type": "cover", "slots": { "count": "5", "headline": "깃을 쓰기 전에 알았으면 좋았을 것", "subheadline": "3년 차가 되어서야 알게 된 것들", "account_name": "@lightsoft_dev" } }, { "type": "item", "slots": { "index": "01", "title": "잦은 커밋", "body": "작게 자주 남기면 되돌릴 지점이 촘촘해진다. 하루치를 한 번에 남기면 어디로 돌아갈지 고를 수가 없다." } }, { "type": "item", "slots": { "index": "02", "title": "브랜치는 싸다", "body": "실험은 브랜치에서 한다. 아니다 싶으면 버리면 되고, 버려도 아무 일도 일어나지 않는다.", "note": "main 에서 직접 고치는 습관이 사고의 대부분을 만든다." } }, { "type": "cta", "slots": { "headline": "나중에 또 찾게 될 내용", "body": "저장해두면 필요할 때 바로 꺼내 볼 수 있습니다.", "cta_text": "저장하기", "account_name": "@lightsoft_dev" } } ] } ``` ## 6. curl 호출 예시 ```bash curl -X POST 'https://api.cardnews.example/v1/renders' \ -H 'Authorization: Bearer $CARDNEWS_API_KEY' \ -H 'Content-Type: application/json' \ --data-binary @slides.json ``` ## 7. 검증·경고 대응 가이드 - `max_chars_exceeded`: 해당 슬롯의 글자수를 줄인다. `max_chars` 는 넘기면 확실히 거부되는 상한이지 안전 보장이 아니다 — 글자가 넓으면(전각·이모지) 상한 안에서도 넘칠 수 있다. - `text_overflow` / `out_of_bounds`: 렌더는 성공하고 이미지와 함께 경고가 온다. 글자를 줄이고 다시 렌더한다. - `low_resolution`: 더 큰 원본 이미지를 쓴다. - `unknown_slot` / `missing_required_slot`: 4절의 슬롯 목록과 대조한다.