feishu-card (schema 2.0)
핵심 규칙
- 모든 카드는 schema 2.0 사용, 요소는
body.elements[]에 배치 (최상위elements[]아님) - 카드 발송은 반드시
--as bot,--msg-type interactive,--content에 JSON 문자열 전달 - 카드 내 @멘션은
<at id="ou_xxx">이름</at>사용 (<at user_id>아님) - JSON 2.0 버튼에는
action컨테이너가 없음, button을body.elements에 직접 배치, 상호작용은behaviors배열 사용 - 먼저 "생각 중" 카드를 발송하여
message_id획득, Claude가 응답한 후 PATCH로 원본 업데이트 (도배 방지) note태그는 schema 2.0에서 지원 중단됨 (오류 200861 발생), 비고는div + lark_md사용 (<font color=grey>비고 텍스트</font>)- 카드 JSON 구축은 반드시 Python heredoc 또는 파일 쓰기 사용,
$(python3 -c "...")금지 — 내용에 백틱이나 특수 문자가 있을 경우 bash 구문 오류 발생
최상위 구조 전체 필드
{
"schema": "2.0",
"config": {
"streaming_mode": false,
"enable_forward": true,
"update_multi": true,
"width_mode": "default"
},
"card_link": {
"url": "https://...",
"pc_url": "https://...",
"ios_url": "https://...",
"android_url": "https://..."
},
"header": { "...": "..." },
"body": {
"direction": "vertical",
"padding": "0px",
"elements": []
}
}
config 필드
| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
streaming_mode | bool | false | 스트리밍 업데이트 상태 (생각 중 자리 표시용) |
enable_forward | bool | true | 카드 전달 허용 |
update_multi | bool | false | JSON 2.0 공유 카드 모드 (여러 사용자 동기 업데이트 필요 시 true) |
width_mode | string | default (600px) | compact (400px) / fill (전폭 반응) / default |
Header 필드
{
"header": {
"title": {"tag": "plain_text", "content": "제목"},
"subtitle": {"tag": "plain_text", "content": "부제목 (선택사항)"},
"template": "blue",
"icon": {
"tag": "standard_icon",
"token": "robot-outlined",
"color": "blue"
},
"text_tag_list": [
{"tag": "text_tag", "text": {"tag": "plain_text", "content": "New"}, "color": "blue"}
]
}
}
template 색상: blue / wathet / turquoise / green / yellow / orange / red / carmine / violet / purple / indigo / grey
Feishu 색상 열거형 빠른 참조
색상 열거형을 지원하는 모든 필드 (background_color, text_color, icon color 등)는 다음 형식을 사용해야 하며, 기본 색상명만 사용하면 안 됨 (예: "blue"를 단독으로 사용하면 일부 컴포넌트에서 오류 발생), 계층 접미사가 필요:
| 색상 계열 | 밝음 (배경 권장) | 중간색 | 어두움 (텍스트 권장) |
|---|---|---|---|
| 블루 blue | blue-50 blue-100 blue-200 | blue-300~blue-500 | blue-600~blue-900 |
| 워터블루 wathet | wathet-50 wathet-100 wathet-200 | wathet-300~wathet-500 | wathet-600~wathet-900 |
| 청록 turquoise | turquoise-50 turquoise-100 | turquoise-300~turquoise-500 | turquoise-600~turquoise-900 |
| 그린 green | green-50 green-100 green-200 | green-300~green-500 | green-600~green-900 |
| 라임 lime | lime-50 lime-100 | lime-300~lime-500 | lime-600~lime-900 |
| 옐로우 yellow | yellow-50 yellow-100 | yellow-300~yellow-500 | yellow-600~yellow-900 |
| 오렌지 orange | orange-50 orange-100 | orange-300~orange-500 | orange-600~orange-900 |
| 레드 red | red-50 red-100 | red-300~red-500 | red-600~red-900 |
| 카민 carmine | carmine-50 carmine-100 | carmine-300~carmine-500 | carmine-600~carmine-900 |
| 퍼플 purple | purple-50 purple-100 | purple-300~purple-500 | purple-600~purple-900 |
| 바이올렛 violet | violet-50 violet-100 | violet-300~violet-500 | violet-600~violet-900 |
| 인디고 indigo | indigo-50 indigo-100 | indigo-300~indigo-500 | indigo-600~indigo-900 |
| 그레이 grey | grey-00 grey-50 grey-100 | grey-300~grey-500 | grey-600~grey-1000 |
| 화이트 | white bg-white | — | — |
자주 사용되는 밝은 배경색 권장 (collapsible_panel, column 배경 등):
blue-100 wathet-100 green-100 yellow-100
orange-100 red-100 purple-100 carmine-100
turquoise-100 violet-100 indigo-100 lime-100
컴포넌트 빠른 참조표
| tag | 타입 | 설명 |
|---|---|---|
div | 내용 | 텍스트 블록 (plain_text / lark_md), 아이콘 접두사 지원 |
markdown | 내용 | 순수 Markdown 텍스트 (@멘션 미지원, @는 div+lark_md 사용) |
img | 내용 | 이미지 |
table | 내용 | 데이터 테이블 (카드당 최대 5개, 중첩 불가) |
hr | 레이아웃 | 구분선 |
note | 레이아웃 | ❌ schema 2.0에서 폐기됨, div + lark_md + <font color=grey>로 대체 |
column_set | 컨테이너 | 다중 열 레이아웃 |
collapsible_panel | 컨테이너 | 접이식 패널 |
button | 상호작용 | 버튼 (JSON 2.0은 elements에 직접 배치, action 컨테이너 불필요) |
input | 상호작용 | 텍스트 입력 상자 (form 내에서 사용해야 함) |
select_static | 상호작용 | 정적 드롭다운 선택기 |
div (텍스트 블록)
{
"tag": "div",
"text": {
"tag": "lark_md",
"content": "**굵게** _기울임_ `코드`",
"text_size": "normal",
"text_color": "default",
"text_align": "left",
"lines": 3
},
"icon": {"tag": "standard_icon", "token": "robot-outlined", "color": "blue"}
}
text.tag: plain_text (순수 텍스트) 또는 lark_md (Markdown + @멘션)
text_size: heading-0 / heading / normal (기본값) / notation / x-small
text_align: left / center / right
img (이미지)
{
"tag": "img",
"img_key": "img_xxx",
"alt": {"tag": "plain_text", "content": "호버 설명"},
"title": {"tag": "plain_text", "content": "이미지 제목"},
"scale_type": "crop_center",
"size": "medium",
"corner_radius": "4px",
"preview": true
}
scale_type: crop_center / crop_top / fit_horizontal
size: stretch (전폭) / large / medium / small / tiny / "300px 200px" (사용자 정의)
JSON 2.0은
stretch_without_padding을 지원하지 않음, 전폭 효과는 음수 margin 사용
column_set (다중 열 레이아웃)
{
"tag": "column_set",
"flex_mode": "bisect",
"horizontal_spacing": "medium",
"background_style": "default",
"columns": [
{
"tag": "column",
"width": "weighted",
"weight": 1,
"vertical_align": "top",
"elements": [{"tag": "div", "text": {"tag": "plain_text", "content": "왼쪽 열"}}]
},
{
"tag": "column",
"width": "weighted",
"weight": 1,
"elements": [{"tag": "div", "text": {"tag": "plain_text", "content": "오른쪽 열"}}]
}
]
}
flex_mode: none (비율에 따라 압축) / stretch (좁은 화면에서 세로 배치) / flow (자동 줄바꿈) / bisect (동일 폭 두 열) / trisect (동일 폭 세 열)
horizontal_spacing: small(4px) / medium(8px) / large(12px) / extra_large(16px)
column.width: auto / weighted (weight 1-5와 함께 사용) / "200px"
최대 중첩 5단계, 열 내에는 form 컨테이너와 table을 배치할 수 없음
collapsible_panel (접이식 패널)
{
"tag": "collapsible_panel",
"expanded": false,
"background_color": "default",
"header": {
"title": {"tag": "plain_text", "content": "클릭하여 펼치기"},
"background_color": "grey",
"icon": {"tag": "standard_icon", "token": "arrow-down-outlined"},
"icon_expanded_angle": -180
},
"elements": [
{"tag": "div", "text": {"tag": "plain_text", "content": "접힌 내용"}}
]
}
table (데이터 테이블)
{
"tag": "table",
"page_size": 5,
"row_height": "low",
"freeze_first_column": false,
"header_style": {
"text_align": "left",
"text_size": "normal",
"background_style": "grey",
"bold": true
},
"columns": [
{"name": "name", "display_name": "이름", "data_type": "text", "width": "auto"},
{"name": "status", "display_name": "상태", "data_type": "options", "width": "120px"},
{"name": "count", "display_name": "수량", "data_type": "number",
"format": {"precision": 0, "separator": true}},
{"name": "ts", "display_name": "시간", "data_type": "date",
"format": "YYYY/MM/DD HH:mm"}
],
"rows": [
{"name": "홍길동", "status": [{"name": "진행 중", "color": "blue"}], "count": 42, "ts": 1700000000000}
]
}
data_type: text / lark_md / markdown / options / number / persons / date
row_height: low / middle / high / auto / "48px" (32-124px)
각 카드에는 최대 5개의 table만 가능, 중첩 불가
button (JSON 2.0)
{
"tag": "button",
"text": {"tag": "plain_text", "content": "확인"},
"type": "primary",
"size": "medium",
"width": "default",
"disabled": false,
"behaviors": [
{
"type": "callback",
"value": {"action": "confirm", "data": "payload"}
}
],
"confirm": {
"title": {"tag": "plain_text", "content": "재확인"},
"text": {"tag": "plain_text", "content": "이 작업을 실행하시겠습니까?"}
}
}
type: default (회색) / primary (파란색) / danger (빨간색) / text / primary_text / danger_text / primary_filled / danger_filled / laser
size: tiny / small / medium / large
behaviors[].type: callback (이벤트 트리거) / open_url (링크 이동)
JSON 2.0 변경 사항:
action컨테이너가 더 이상 없음, button을body.elements또는column.elements에 직접 배치; 상호작용은 이전value대신behaviors사용
input (텍스트 입력)
{
"tag": "input",
"name": "field_name",
"placeholder": {"tag": "plain_text", "content": "입력하세요..."},
"default_value": "",
"input_type": "text",
"max_length": 200,
"required": false,
"disabled": false,
"label": {"tag": "plain_text", "content": "레이블"},
"label_position": "top",
"width": "fill"
}
input_type: text / multiline_text / password
사용자 제출 시 card.action.trigger 이벤트 발생, 이벤트에 input_value 포함
@멘션 구문
| 메시지 유형 | @멘션 구문 | @전체 |
|---|---|---|
카드 interactive lark_md | <at id="ou_xxx">이름</at> | <at id="all">모든 사용자</at> |
텍스트 text / post | <at user_id="ou_xxx">이름</at> | <at user_id="all"></at> |
카드 내 @멘션 검증된 요소 구조 (div + lark_md 사용, markdown 태그 사용 금지):
{
"tag": "div",
"text": {
"tag": "lark_md",
"content": "<at id=\\