사용 설명서 > 개발자 문서 > SDK(FC) 레퍼런스
예제 번들
아래 예제는 모두 실제 검증기를 통과하는 번들입니다. LLM에 "이 형식을 따라 줘" 하고 함께 주면 결과가 안정적입니다.
가장 작은 앱(이벤트 하나 보내기)
{
"format_version": 1,
"manifest": {
"name": "클릭 카운터",
"sdk_version": "1",
"permissions": [
"events.emit"
],
"screens": [
{
"key": "main",
"label": "메인"
}
],
"events": [
{
"name": "example.clicked",
"fields": {
"count": {
"type": "number",
"required": true
}
}
}
],
"variables": [
{
"name": "title",
"type": "text",
"default": "클릭 카운터"
}
]
},
"settings": {
"title": "클릭 카운터"
},
"client": {
"html": "<main class=\"app\">\n <h2 data-title>클릭 카운터</h2>\n <p data-count>0</p>\n <button type=\"button\" data-action=\"add\">누르기</button>\n</main>\n",
"css": ".app{font-family:Arial,sans-serif;max-width:480px;margin:auto;padding:24px}\nbutton{padding:10px 16px;border:0;border-radius:8px;background:#4A3094;color:#fff;cursor:pointer}\n",
"js": "(() => {\n let count = 0;\n document.querySelector(\"[data-title]\").textContent = FC.settings.title;\n document.querySelector(\"[data-action=add]\").addEventListener(\"click\", () => {\n count += 1;\n document.querySelector(\"[data-count]\").textContent = String(count);\n FC.event.emit(\"example.clicked\", { count });\n });\n})();\n"
}
}
이메일을 받아 연락처로 저장하기
{
"format_version": 1,
"manifest": {
"name": "소식 받기",
"sdk_version": "1",
"permissions": [
"contacts.write"
],
"screens": [
{
"key": "form",
"label": "입력"
},
{
"key": "done",
"label": "완료"
}
],
"events": [],
"variables": [
{
"name": "title",
"type": "text",
"default": "소식 받기"
}
]
},
"settings": {
"title": "소식 받기"
},
"client": {
"html": "<main class=\"app\">\n <section data-screen=\"form\">\n <h2 data-title>소식 받기</h2>\n <label>이메일 <input name=\"email\" type=\"email\" required maxlength=\"320\"></label>\n <p data-error role=\"alert\"></p>\n <button type=\"button\" data-action=\"submit\">신청하기</button>\n </section>\n <section data-screen=\"done\" hidden><p>신청해 주셔서 감사합니다.</p></section>\n</main>\n",
"css": ".app{font-family:Arial,sans-serif;max-width:480px;margin:auto;padding:24px}\ninput{display:block;width:100%;padding:10px;margin:8px 0}\n",
"js": "(() => {\n const screen = (key) => document.querySelector(\"[data-screen=\" + key + \"]\");\n document.querySelector(\"[data-action=submit]\").addEventListener(\"click\", async () => {\n const email = document.querySelector(\"input[name=email]\").value.trim();\n const error = document.querySelector(\"[data-error]\");\n if (!email) { error.textContent = \"이메일을 입력해 주세요.\"; return; }\n try {\n await FC.contact.create({ email });\n screen(\"form\").hidden = true;\n screen(\"done\").hidden = false;\n } catch (e) {\n error.textContent = \"잠시 후 다시 시도해 주세요.\";\n }\n });\n})();\n"
}
}
방문자 글을 AI가 요약하기(AI Action)
{
"format_version": 1,
"manifest": {
"name": "글 요약기",
"sdk_version": "1",
"permissions": [
"ai.generate"
],
"screens": [
{
"key": "main",
"label": "메인"
}
],
"events": [],
"variables": [
{
"name": "title",
"type": "text",
"default": "글 요약기"
}
],
"actions": [
{
"key": "summarize",
"kind": "ai.generate",
"connection": {
"mode": "managed"
},
"instruction": "입력된 글을 한국어로 세 문장 이내로 요약한다. 없는 내용은 만들지 않는다.",
"output": "text"
}
]
},
"settings": {
"title": "글 요약기"
},
"client": {
"html": "<main class=\"app\">\n <h2 data-title>글 요약기</h2>\n <textarea name=\"body\" rows=\"6\" maxlength=\"4000\"></textarea>\n <button type=\"button\" data-action=\"run\">요약하기</button>\n <p data-status role=\"status\"></p>\n <div data-result></div>\n</main>\n",
"css": ".app{font-family:Arial,sans-serif;max-width:560px;margin:auto;padding:24px}\ntextarea{width:100%;padding:10px;box-sizing:border-box}\n",
"js": "(() => {\n const button = document.querySelector(\"[data-action=run]\");\n const status = document.querySelector(\"[data-status]\");\n const result = document.querySelector(\"[data-result]\");\n button.addEventListener(\"click\", async () => {\n const input = document.querySelector(\"textarea[name=body]\").value.trim().slice(0, 4000);\n if (!input) { status.textContent = \"글을 입력해 주세요.\"; return; }\n button.disabled = true;\n status.textContent = \"요약 중입니다…\";\n result.textContent = \"\";\n try {\n const answer = await FC.ai.generate(input, { action: \"summarize\" });\n result.textContent = answer.text;\n status.textContent = \"\";\n } catch (e) {\n status.textContent = (e && e.message) || \"요약하지 못했습니다.\";\n } finally {\n button.disabled = false;\n }\n });\n})();\n"
}
}