멀티턴은 그만, 싱글턴으로 끝내는 랜딩페이지 실험(Google AI Studio · Lovable · Bolt 활용)

소개

전주 사례로 n8n 자동화를 Claude Code를 활용한 AI 주도 개발 방식으로 진행하고자 했다.
Claude Code 공식 문서를 살펴보면 전체 흐름은 explore → plan → code → commit 단계로 구성되어 있으며, 이를 AI 주도 개발에 맞게 정리하면 export(데이터 수집) → plan(기획·PRD 생성·ROADMAP 생성) → code(shrimp manager) → commit 단계로 이어진다. 이 구조를 스터디원들과 공유하고 싶었으나, 작업 일정 상 충분한 시간이 확보되지 않아 방향을 급히 전환하게 되었다.

또한 전주에 고도화를 진행하겠다고 발표한 만큼, 단순 구현이 아닌 기존 흐름의 고도화에 초점을 맞추기로 했다. 이에 따라 랜딩페이지에서 구글폼으로 단순 연결되던 구조를 개선하여, 랜딩페이지에서 n8n 웹훅을 직접 호출하고 ‘교육 신청 접수 자동화’가 즉시 실행되는 플로우로 발전시키는 방향으로 설계하였다.

해당 과정을 진행하면서 프롬프트 기법 중 싱글턴(single-turn)과 멀티턴(multi-turn)을 비교 검토하였다. 최근 LLM의 컨텍스트 처리 용량이 크게 확장됨에 따라, 복잡한 흐름에서도 싱글턴 방식이 매우 효율적이라는 판단 하에 싱글턴 프롬프트 기반으로 실험을 진행하였다.

또한 이번 작업은 랜딩페이지 구현이 목적이었기 때문에, 무거운 개발 환경인 Claude Code까지 사용할 필요는 없다고 판단하였다. 이에 따라 Google AI Studio, Lovable, Bolt를 활용하여 보다 빠르고 유연한 방식으로 개발을 진행하였다.

진행 방법

1. Single Turn 프롬프트 설계

전주에 Google AI Studio에서 작성한 프롬프트를 면밀히 검토한 결과, [신청 양식] 영역의 설계가 적절하지 않았다는 점을 확인할 수 있었다.

기존 프롬프트 : 신청 양식 부분

[신청 양식]

이름: _______________
회사명: _______________
직급/부서: _______________
이메일: _______________
휴대폰: _______________

회사 소재지:
( ) 서울/경기/인천 (수도권)
( ) 그 외 지역 (비수도권)

우선지원대상기업 해당 여부:
( ) 예
( ) 아니오
( ) 잘 모르겠음

가장 관심있는 분야: (복수선택 가능)
□ ChatGPT 문서 작성
□ 엑셀 자동화
□ 카드뉴스 제작
□ 랜딩페이지 제작
□ 전체 과정

[무료 상담 신청하기] 👉

변경 프롬프트 : 신청 양식 부분

해당 프롬프트는 구글폼에 있는 형식을 그대로 준수하여 프롬프트를 작성하였다.

# 교육 신청 정보 

제출 시 즉시 안내 메일이 발송됩니다.
* 표시는 필수 입력 항목입니다.

1. 성함을 알려주세요* : _______________
2. 소속 회사명을 알려주세요* : _______________
3. 직급/부서를 알려주세요* : _______________
4. 이메일 주소를 입력해주세요* : _______________
5. 연락 가능한 휴대폰 번호를 알려주세요(예:010-0000-0000)* : _______________
6. 회사 소재지는 어디인가요?
 - 서울/경기/인천 (수도권)
 - 그 외 지역 (비수도권)
7. 귀사는 우선지원대상기업*에 해당하시나요?
* 중소기업 중 업종별 상시근로자 수 기준 충족 기업
 - 예
 - 아니요
 - 잘 모르겠음 (확인 필요)
8. 이 교육을 어떻게 알게 되셨나요?
 - LinkedIn
 - 블로그/검색
 - 지인 추천
 - 기타
9. 가장 관심있는 주제는 무엇인가요? (복수선택)
 - ChatGPT 문서작성 자동화
 - 엑셀 데이터 자동화
 - 카드뉴스/콘텐츠 제작
 - 랜딩페이지 제작
 - 전체 과정
10. 추가로 전달하고 싶은 내용이 있으신가요? 

[무료 상담 신청하기] 👉
n8n 웹훅 호출 URL : https://junsan12edu002.app.n8n.cloud/webhook-test/training-signup

또한 보다 풍부한 Context 정보를 제공하기 위해, 다음 프롬프트를 추가하였다.

신청폼 추가 내용

"무료 상담 신청하기" 버튼 클릭 시 n8n 웹훅 호출 URL
https://junsan12edu002.app.n8n.cloud/webhook-test/training-signup

구글폼에서 n8n 웹훅 호출 시 json 데이터 내용. 폼의 키값은 아래를 참고해서 구현이 되어야됨.
{
  "headers": {
    "x-forwarded-host": "junsan12edu002.app.n8n.cloud",
    "x-forwarded-port": "443",
    "x-forwarded-proto": "https",
    "x-forwarded-server": "traefik-prod-users-gwc-102-67995f758b-pzz5r",
    "x-is-trusted": "yes",
    "x-real-ip": "34.116.22.106"
  },
  "params": {},
  "query": {},
  "body": {
    "formTitle": "",
    "timestamp": "2026-01-28T07:15:19.970Z",
    "email": "",
    "1. 성함을 알려주세요": "좌성훈",
    "2. 소속 회사명을 알려주세요": "신시웨이",
    "3. 직급/부서를 알려주세요": "인재교육팀",
    "4. 이메일 주소를 입력해주세요": "[email protected]",
    "5. 연락 가능한 휴대폰 번호를 알려주세요": "010-7400-3791",
    "6. 회사 소재지는 어디인가요?": "서울/경기/인천 (수도권)",
    "7. 귀사는 우선지원대상기업*에 해당하시나요?": "예",
    "8. 이 교육을 어떻게 알게 되셨나요?": "LinkedIn",
    "9. 가장 관심있는 주제는 무엇인가요? (복수선택)": [
      "ChatGPT 문서작성 자동화",
      "카드뉴스/콘텐츠 제작"
    ],
    "10. 추가로 전달하고 싶은 내용이 있으신가요?": "없음"
  },
  "webhookUrl": "https://junsan12edu002.app.n8n.cloud/webhook-test/training-signup",
  "executionMode": "test"
}

2. 완성된 싱글턴 프롬프트 구조

기존 프롬프트 앞부분
변경 프롬프트 : 신청 양식 부분
신청폼 추가 내용
기존 프롬프트 뒷부분

3. Google AI Studio 실행

싱글턴 프롬프트 실행

1차 시도에서는 웹훅 호출 자체는 정상적으로 이루어졌으나, 전달되어야 할 다른 값들이 모두 undefined로 출력되었다.

원인을 정확히 파악하기 위해 프롬프트를 다시 실행했으며, 이때 웹훅으로 수신된 JSON 데이터code node 소스를 함께 포함하여 보다 상세하게 점검하도록 구성하였다.

"무료 상당 신청하기" 버튼 클릭하면 웹훅은 잘 되. 하지만 n8n code node에서 잘 분석하지 못하는 것 같아. 왜 그런지 분석해줘.
n8n 웹훅으로 들어온 json 데이터
[
{
"headers": {
"host": "junsan12edu002.app.n8n.cloud",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
"content-length": "829",
"accept": "/",
"accept-encoding": "gzip, br",
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
"cdn-loop": "cloudflare; loops=1; subreqs=1",
"cf-connecting-ip": "218.236.21.147",
"cf-ew-via": "15",
"cf-ipcountry": "KR",
"cf-ray": "9c4ec661f097184c-NRT",
"cf-visitor": "{"scheme":"https"}",
"cf-worker": "n8n.cloud",
"content-type": "application/json",
"origin": "https://4v2v6rsmlbyluxnzetd108o6kzd3kow5yskphrl1mhcs7vev7u-h858592233.scf.usercontent.goog",
"priority": "u=1, i",
"sec-ch-ua": ""Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": ""Windows"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "cross-site",
"x-forwarded-for": "218.236.21.147, 162.159.110.137",
"x-forwarded-host": "junsan12edu002.app.n8n.cloud",
"x-forwarded-port": "443",
"x-forwarded-proto": "https",
"x-forwarded-server": "traefik-prod-users-gwc-102-67995f758b-pptkp",
"x-is-trusted": "yes",
"x-real-ip": "218.236.21.147"
},
"params": {},
"query": {},
"body": {
"body": {
"formTitle": "AI Business Training Signup",
"timestamp": "2026-01-28T07:28:45.365Z",
"email": "[email protected]",
"1. 성함을 알려주세요": "김갑동",
"2. 소속 회사명을 알려주세요": "에이아이컴퍼니",
"3. 직급/부서를 알려주세요": "인재교육팀",
"4. 이메일 주소를 입력해주세요": "[email protected]",
"5. 연락 가능한 휴대폰 번호를 알려주세요": "010-74003791",
"6. 회사 소재지는 어디인가요?": "서울/경기/인천 (수도권)",
"7. 귀사는 우선지원대상기업*에 해당하시나요?": "예",
"8. 이 교육을 어떻게 알게 되셨나요?": "LinkedIn",
"9. 가장 관심있는 주제는 무엇인가요? (복수선택)": [
"ChatGPT 문서작성 자동화",
"랜딩페이지 제작"
],
"10. 추가로 전달하고 싶은 내용이 있으신가요?": "없음"
}
},
"webhookUrl": "https://junsan12edu002.app.n8n.cloud/webhook-test/training-signup",
"executionMode": "test"
}
]
code node 소스
// 1. 데이터 소스 정의 (body 항목에 접근)
const data = $input.item.json.body;
// 2. 질문 답변 추출 (질문 문구와 정확히 일치해야 함)
const region = data["6. 회사 소재지는 어디인가요?"] || '';
const isPriority = data["7. 귀사는 우선지원대상기업*에 해당하시나요?"] || '확인필요';
const rawInterests = data["9. 가장 관심있는 주제는 무엇인가요? (복수선택)"] || [];
const referral = data["8. 이 교육을 어떻게 알게 되셨나요?"] || '';
const extraMsg = data["10. 추가로 전달하고 싶은 내용이 있으신가요?"] || '';
// 3. 지역에 따른 환급률 계산
const isCapital = region.includes('수도권') || region.includes('서울') || region.includes('경기') || region.includes('인천');
const refundRate = isCapital ? 0.9 : 0.95;
// 4. 예상 수익 계산 (훈련비 50만원 기준)
const trainingFee = 500000;
const expectedRevenue = Math.floor(trainingFee * refundRate * 0.8);
// 5. 훈련기관 자동 배정 및 상태 확인
const trainingOrg = isCapital ? '기관A' : '기관B';
const needsCheck = isPriority === '아니오' || isPriority === '잘 모르겠음' || isPriority === '확인필요';
// 6. 현재 날짜/시간 (한국 시간 기준)
const now = new Date();
const timestamp = now.toLocaleString('ko-KR', { timeZone: 'Asia/Seoul' });
// 7. 결과 반환
return {
신청일시: data.timestamp || timestamp,
이름: data["1. 성함을 알려주세요"] || '',
회사명: data["2. 소속 회사명을 알려주세요"] || '',
직급_부서: data["3. 직급/부서를 알려주세요"] || '',
이메일: data["4. 이메일 주소를 입력해주세요"] || '',
전화번호: data["5. 연락 가능한 휴대폰 번호를 알려주세요"] || '',
지역: region,
우선지원대상: isPriority,
유입경로: referral,
관심분야: Array.isArray(rawInterests) ? rawInterests.join(', ') : rawInterests,
추가메시지: extraMsg,
상태: needsCheck ? '확인필요' : '신규',
담당훈련기관: trainingOrg,
예상환급률: ${Math.round(refundRate * 100)}%,
예상수익: expectedRevenue,
기업배분_20: Math.floor(expectedRevenue * 0.2),
강사배분_80: Math.floor(expectedRevenue * 0.8),
최종업데이트: timestamp,
메모: needsCheck ? '우선지원대상 확인 필요' : '',
수도권여부: isCapital,
환급액: Math.floor(trainingFee * refundRate),
자부담액: trainingFee - Math.floor(trainingFee * refundRate)
};

결과 : 정상적으로 동작

한국어 지원서 스크린샷

4. Lovable 실행(정상동작)

싱글턴 프롬프트 실행

5. Bolt 실행(정상동작)

싱글턴 프롬프트 실행
한국어로 된 웹사이트의 홈페이지

사용 도구

  • Google AI Studio

  • Lovable

  • Bolt

결과와 배운 점

싱글턴 프롬프트를 활용하여 랜딩페이지를 직접 구현해보았다. 이번 실험을 진행하면서 LLM의 전반적인 성능이 확실히 향상되었음을 체감할 수 있었다.

최근 Vibe Coding 환경에서는 프롬프트 설계가 잘못된 경우를 흔히 ‘프롬프트 버그(prompt bug)’라고 표현한다. 이러한 프롬프트 버그가 포함된 상태로 개발을 진행하면, 결과적으로 코드 구조가 점점 복잡해지며 스파게티 코드로 이어질 가능성이 매우 높다. 심한 경우 프로젝트를 처음부터 다시 시작해야 하는 상황까지 발생할 수 있다.

이번 사례를 통해 , 프롬프트의 중요성을 다시 한 번 실감하게 되었고, 단순한 문장 작성이 아닌 프롬프트 자체에 대한 기획과 구조 설계가 얼마나 중요한지 깨닫는 계기가 되었다.

뉴스레터 무료 구독

👉 이 게시글도 읽어보세요