본문 바로가기

(부록) 구글로 데이터까지 연결하기

1. HTML 한 장으로는 부족한 순간

지금까지 만든 건 화면입니다. 보기에는 멀쩡한데, 한 가지 못 하는 게 있습니다. 기억입니다. 설문 폼을 예쁘게 만들어도 누가 뭘 적었는지 어디에도 남지 않고, 일정을 입력해도 새로고침 한 번이면 사라집니다. HTML은 화면을 그릴 뿐, 입력한 내용을 어딘가에 쌓아 두지는 못합니다.

값을 저장하고 다시 꺼내 보려면 보통 서버라는 게 필요합니다. 데이터를 받아 두는 창고이자, 그 창고를 여닫는 직원 같은 존재입니다. 그런데 서버를 직접 마련하는 건 이 책의 범위를 한참 넘습니다. 다행히 우리가 매일 쓰는 구글 안에 그 창고가 이미 들어 있습니다. 두 가지를 쓸 겁니다.

구글 폼구글 시트 + 앱스 스크립트
난이도코드 한 줄 없음짧은 코드 복사
화면구글이 만들어 준 폼내가 만든 HTML
잘 맞는 일설문, 신청, 접수일정·재고처럼 직접 관리하는 화면

쉬운 쪽인 구글 폼부터 보겠습니다.

같은 브라우저 내에는 데이터를 쌓을 수 있습니다. localStorage와 같은 기능이 있습니다. 다만 이러한 저장공간은 브라우저마다, 심지어 브라우저의 다른 탭과도 공유되지 않습니다. 그래서 내가 만든 화면에서 입력한 내용을 다른 탭이나 다른 사람과 공유하려면, 구글 폼이나 시트 같은 외부 창고가 필요합니다.

2. 구글 폼으로 설문 서비스 만들기

구글 폼은 코드가 전혀 필요 없습니다. 질문을 클릭으로 만들면 응답을 받는 주소가 생기고, 그 주소를 사람들에게 보내면 끝입니다. 받은 답은 자동으로 표에 쌓입니다.

2.1 폼 만들기

  1. forms.google.com에 접속해 빈 양식을 엽니다.

  2. 맨 위 제목 칸에 설문 이름을 적습니다. 예를 들어 "신메뉴 만족도 조사"처럼요.

  3. 질문을 추가합니다. 질문 글을 쓰고, 오른쪽에서 답변 형태를 고릅니다. 객관식, 체크박스, 단답형, 별점(선형 배율) 등이 있습니다.

  4. 질문을 더 넣으려면 오른쪽 도구 막대의 + 버튼을 누릅니다.

  5. 꼭 받아야 하는 질문은 아래쪽 필수 스위치를 켭니다. 그러면 답을 안 하면 제출이 안 됩니다.

  6. 오른쪽 위 보내기를 누르고, 링크 아이콘을 골라 주소를 복사합니다. 이 주소를 받은 사람은 누구나 응답할 수 있습니다.

여기까지면 이미 설문 서비스가 돌아갑니다. 서버도, HTML도 필요 없었습니다.

2.2 응답을 표로 모으기

응답이 들어오면 폼 안에서도 그래프로 볼 수 있지만, 표로 쌓아 두면 다루기 훨씬 편합니다.

  1. 폼 위쪽의 응답 탭으로 갑니다.

  2. 초록색 시트 아이콘(스프레드시트에 연결)을 누릅니다.

  3. 새 구글 시트를 만들면, 이제부터 응답이 한 줄씩 그 시트에 자동으로 쌓입니다.

누가 언제 무엇을 답했는지 시간까지 함께 기록됩니다. 이 시트가 잠시 뒤 3절에서 다룰 구글 시트와 같은 것입니다.

2.3 폼으로 더 할 수 있는 것

폼은 단순한 설문 그 이상입니다. 설정에서 스위치 몇 개만 켜면 제법 똑똑해집니다.

  • 이메일 주소 수집: 설정에서 켜면 응답자의 이메일이 함께 기록됩니다. 누가 냈는지 알아야 하는 신청서에 좋습니다.
  • 1인 1회 응답: 한 사람이 여러 번 내는 걸 막습니다. 구글 로그인이 필요해집니다.
  • 퀴즈 모드: 설정에서 퀴즈로 바꾸면 정답과 배점을 정할 수 있고, 제출하면 점수가 자동으로 매겨집니다. 간단한 시험이나 이벤트 퀴즈를 그대로 만들 수 있습니다.
  • 섹션과 분기: 질문을 여러 페이지(섹션)로 나누고, "예를 고르면 3페이지로" 같은 식으로 답에 따라 다른 질문으로 보낼 수 있습니다. 응답자마다 다른 길을 걷는 설문이 됩니다.
  • 파일 업로드: 답변으로 사진이나 문서를 받을 수 있습니다. 받은 파일은 내 구글 드라이브에 모입니다.
  • 응답 알림: 응답 탭의 점 세 개 메뉴에서 새 응답 이메일 알림을 켜면, 누가 답할 때마다 메일이 옵니다.
  • 응답 받기 마감: 응답 탭의 스위치를 끄면 더 이상 받지 않습니다. 신청 마감에 씁니다.

AI에게 물어볼 때: 폼 자체는 클릭으로 만들지만, 막힐 때 "구글 폼에서 답에 따라 다음 질문을 다르게 보여주려면 어떻게 설정해?"처럼 물으면 어디를 눌러야 하는지 단계로 알려줍니다.

2.4 내가 만든 페이지에 폼 끼워 넣기

폼 링크만 보내도 되지만, 앞에서 만든 내 HTML 페이지 안에 폼을 그대로 넣을 수도 있습니다. 간단한 설문 페이지를 만들어 AI에게 아래와 같이 요청해보세요.

내 HTML 페이지에 구글 폼 링크 "여기에_폼_링크_붙여넣기"를 넣어줘.

이렇게 폼이 들어가는 방식은 2가지입니다.

  1. 링크로 보내기: 폼 링크를 버튼이나 글자에 걸어서, 누르면 폼 페이지로 이동합니다. 가장 간단합니다.
  2. 페이지 안에 끼워 넣기: 내 페이지 안에 폼이 그대로 보입니다. 폼 링크를 AI에게 주면서 "내 페이지 안에 이 폼이 보이도록 만들어 줘"라고 부탁하면 됩니다.

3. 구글 시트로 일정 관리 앱 만들기

폼은 받기만 했습니다. 이번엔 한 걸음 더 갑니다. 내가 만든 화면에서 일정을 추가하고, 그동안 넣은 일정을 불러와 보여주는 작은 앱입니다. 데이터 창고는 구글 시트가 맡고, 그 창고를 여닫는 직원 역할을 앱스 스크립트가 합니다.

3.1 큰 그림

내 HTML은 구글 시트를 직접 만지지 못합니다. 사이에 앱스 스크립트로 만든 웹앱이라는 작은 창구를 하나 둡니다. HTML은 이 창구에 "일정 추가해 줘", "목록 줘"라고 부탁하고, 창구가 시트를 대신 읽고 씁니다.

순서대로 시트를 만들고, 창구를 만들고, 화면을 만들겠습니다.

3.2 시트 준비

  1. sheets.google.com에서 새 시트를 하나 만듭니다.

  2. 빈 스프레드 시트를 클릭해주세요.

  3. 첫 줄에 제목을 적습니다. app이라고 적겠습니다. A1 칸에 날짜, B1 칸에 내용이라고 넣습니다. 이 첫 줄은 표의 머리글이고, 실제 일정은 둘째 줄부터 쌓입니다.

3.3 창구 만들기

이제 시트를 여닫을 직원을 코드로 적습니다. 어렵게 느껴져도 괜찮습니다. 통째로 붙여 넣으면 됩니다.

  1. 시트 상단 메뉴에서 확장 프로그램 → Apps Script를 누릅니다. 코드 편집기가 새 탭으로 열립니다.

  2. 원래 있던 내용을 지우고 아래 코드를 그대로 붙여 넣은 뒤, 디스크 모양 버튼으로 저장합니다.

// 시트의 첫 번째 탭을 가져옵니다
const getSheet = () =>
  SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];

// 목록을 달라는 요청(GET)을 처리합니다
function doGet() {
  const rows = getSheet().getDataRange().getDisplayValues();
  // 첫 줄(머리글)은 빼고, 나머지를 날짜·내용으로 정리합니다
  const data = rows.slice(1).map((r) => ({ date: r[0], content: r[1] }));
  return ContentService
    .createTextOutput(JSON.stringify(data))
    .setMimeType(ContentService.MimeType.JSON);
}

// 추가해 달라는 요청(POST)을 처리합니다
function doPost(e) {
  const body = JSON.parse(e.postData.contents);
  getSheet().appendRow([body.date, body.content]); // 맨 아래에 한 줄 추가
  return ContentService
    .createTextOutput(JSON.stringify({ result: "ok" }))
    .setMimeType(ContentService.MimeType.JSON);
}

doGet은 "목록 줘"라는 요청에, doPost는 "이거 추가해 줘"라는 요청에 답하는 직원입니다. 이름이 정해져 있어서 그대로 써야 합니다. 안에서 무슨 일이 벌어지는지는 주석으로 충분하고, 손볼 필요는 없습니다.

3.4 창구를 인터넷에 열기

코드를 적었으니, 바깥에서 부를 수 있게 주소를 가진 웹앱으로 내보냅니다.

  1. 앱스 스크립트 오른쪽 위 배포 → 새 배포를 누릅니다.

  2. 톱니바퀴(유형 선택)에서 웹 앱을 고릅니다.

  3. 다음 사용자로 실행은 나, 액세스 권한은 모든 사용자로 둡니다. 이래야 내 화면에서 누구든 부를 수 있습니다.

  4. 배포를 누르면 엑세스 승인 버튼이 나옵니다. 눌러보면 경고창이 뜹니다. 괜찮습니다. 내 시트를 대신 만지도록 허락하는 절차입니다. 고급(Advanced) → (내 프로젝트 이름)(으)로 이동(Go to (Project Name)) → 계속(Continue)을 차례로 눌러 권한을 허락합니다.

"This app is blocked" 화면이 뜨며 막히는 경우

승인 과정에서 고급 링크가 없는 "This app is blocked. This app tried to access sensitive info in your Google Account."라는 화면이 뜨면서 더 진행할 수 없는 경우가 있습니다. 코드에 SpreadsheetApp이 있으면 앱스 스크립트가 "내 모든 스프레드시트를 읽고 쓰는" 넓은 권한을 자동으로 요청하는데, 이런 민감한 권한은 구글의 검증을 받지 않은 앱에서 차단되기 때문입니다. 요청 권한을 "지금 이 시트 하나"로 좁혀 주면 해결됩니다.

  1. 앱스 스크립트 편집기 왼쪽 톱니바퀴(프로젝트 설정)에서 "'appsscript.json' 매니페스트 파일을 편집기에 표시"를 체크합니다. 다시 코드 편집기로 돌아오면 왼쪽 파일 목록에 appsscript.json이 나타납니다.

  1. appsscript.json을 열어 아래처럼 수정하고 저장합니다.

{
  "timeZone": "Asia/Seoul",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "oauthScopes": [
    "https://www.googleapis.com/auth/spreadsheets.currentonly"
  ]
}
  1. 저장한 뒤 다시 배포하면 승인이 정상적으로 진행됩니다.
  1. 나타나는 웹 앱 URL을 복사합니다. 이게 우리 창구의 주소입니다.

3.5 화면 만들기

이제 진짜 우리 영역입니다. 일정을 입력하는 폼과 목록을 보여주는 HTML을 만듭니다. 아래 코드를 일정.html 같은 파일로 저장합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8" />
  <title>나의 일정</title>
</head>
<body>
  <h1>나의 일정</h1>

  <form id="form">
    <input type="date" id="date" required />
    <input type="text" id="content" placeholder="할 일" required />
    <button type="submit">추가</button>
  </form>

  <ul id="list"></ul>

  <script>
    // 3.4에서 복사한 웹 앱 주소를 붙여 넣습니다
    const URL = "여기에_웹앱_주소_붙여넣기";

    // 시트에서 일정 목록을 불러와 화면에 그립니다
    async function load() {
      const res = await fetch(URL);
      const data = await res.json();
      const list = document.getElementById("list");
      list.innerHTML = "";
      data.forEach((item) => {
        const li = document.createElement("li");
        li.textContent = item.date + " · " + item.content;
        list.appendChild(li);
      });
    }

    // 추가 버튼을 누르면 시트에 한 줄 보내고, 다시 목록을 새로 그립니다
    document.getElementById("form").addEventListener("submit", async (e) => {
      e.preventDefault();
      const date = document.getElementById("date").value;
      const content = document.getElementById("content").value;
      await fetch(URL, {
        method: "POST",
        body: JSON.stringify({ date, content }),
      });
      e.target.reset();
      load();
    });

    // 페이지를 열면 곧바로 목록을 불러옵니다
    load();
  </script>
</body>
</html>

const URL = "..." 줄의 따옴표 안을, 3.4에서 복사한 웹 앱 주소로 바꾸는 것만 잊지 마세요. 나머지는 그대로 두면 됩니다. fetch가 창구에 부탁을 보내는 부분이고, 받은 답으로 목록을 다시 그립니다.

3.6 동작 확인과 흔한 문제

파일을 브라우저로 열어 날짜와 할 일을 넣고 추가를 눌러 봅니다. 잠깐 뒤 아래 목록에 새 줄이 생기고, 구글 시트를 열어 보면 같은 내용이 한 줄 쌓여 있을 겁니다. 화면과 시트가 연결된 것입니다.

생각대로 안 된다면 대개 다음 중 하나입니다.

  • 목록이 안 뜬다: URL 값을 진짜 웹 앱 주소로 바꿨는지, 따옴표 안에 제대로 넣었는지 확인합니다.
  • 코드를 고쳤는데 그대로다: 앱스 스크립트는 고친 뒤 다시 배포해야 반영됩니다. 배포 → 배포 관리에서 연필(수정)을 누르고 버전을 새로 만들면 됩니다.
  • 권한 오류가 난다: 배포할 때 액세스 권한이 모든 사용자인지 다시 봅니다.

여기서 더 키우려면: 지금은 추가와 목록만 됩니다. AI에게 "이 일정 앱에 완료 체크와 삭제 기능을 넣어 줘. 앱스 스크립트와 HTML 양쪽을 고쳐 줘"처럼 부탁하면, 같은 구조 위에 기능을 얹어 줍니다. 큰 틀(HTML이 창구에 부탁하고, 창구가 시트를 만진다)은 그대로입니다.

4. Apps Script로 할 수 있는 것

우리가 쓴 건 앱스 스크립트가 할 수 있는 일의 아주 일부입니다. 시트에 줄 하나 더하는 정도였지만, 앱스 스크립트는 사실 구글 도구 전체를 코드로 부리는 만능 직원에 가깝습니다. 시트뿐 아니라 메일, 캘린더, 드라이브, 문서까지 손이 닿습니다.

google form에서 직접 Apps Script를 연결하거나, 구글 시트로 연동하여 Apps Script 연결 가능합니다.

이 중에서도 입문자가 가장 요긴하게 쓰는 게 메일 보내기입니다. 앞에서 만든 일정 앱을 살짝 고치면, 새 일정이 들어올 때마다 내 메일로 알림이 오게 할 수 있습니다. doPost에 한 줄만 더하면 됩니다.

function doPost(e) {
  const body = JSON.parse(e.postData.contents);
  getSheet().appendRow([body.date, body.content]);

  // 일정이 추가되면 내 메일로 알림을 보냅니다
  MailApp.sendEmail("내메일@gmail.com", "새 일정 등록", body.date + " " + body.content);

  return ContentService
    .createTextOutput(JSON.stringify({ result: "ok" }))
    .setMimeType(ContentService.MimeType.JSON);
}

MailApp.sendEmail(받는사람, 제목, 내용) 한 줄이면 메일이 나갑니다. 주문이 들어오면 사장에게 알리거나, 신청자에게 확인 메일을 보내는 일이 전부 이 한 줄에서 출발합니다.

여기에 정해진 때 자동 실행(트리거)을 더하면 사람이 손대지 않아도 돌아가는 시스템이 됩니다. 예를 들어 "매일 아침 9시에 오늘 일정을 정리해 메일로 보내라"처럼 시간을 정해 두면, 내가 자는 동안에도 앱스 스크립트가 알아서 일합니다.

위와 같이 디자인을 입혀 실제 google calendar에 일정을 등록하는 것처럼 보이게도 할 수 있습니다. 이렇게 등록된 일정이 실제 google calendar에 등록되도록도 할 수 있습니다.

이러한 데이터는 '삭제' 기능이 민감한 데이터일 수 있습니다. 이러한 민감한 데이터의 경우 '비밀번호'를 설정하여 삭제 기능을 사용할 때마다 비밀번호를 입력하도록 하는 방법도 있습니다. AI에게 "삭제할 때마다 비밀번호를 물어보도록 고쳐 줘"처럼 부탁하면 됩니다. 보안상 허점은 없는지 "보안 취약점이 있는지 확인해줘."처럼 물어보는 것도 좋습니다.

AI에게 부탁할 때: 코드를 직접 외울 필요는 없습니다. "일정이 추가되면 내 메일(내메일@gmail.com)로 알림을 보내도록 앱스 스크립트를 고쳐 줘"처럼 부탁하면 됩니다. 메일, 캘린더 등록, 시간 트리거 모두 같은 식으로 부탁할 수 있습니다.

5. 실습

당신은 감귤을 판매하는 농장 사장입니다. 주문을 받는 웹사이트를 만들고 싶습니다. HTML과 구글 시트와 앱스 스크립트를 이용해서 주문이 들어오면 시트에 쌓이는 시스템을 만들어 주세요. 주문을 받으면 계좌 이체를 안내하는 간단한 페이지면 됩니다. 주문 양식과, 주문이 들어오면 시트에 쌓이는 시스템까지 만들어 주세요.

(부록) 구글로 데이터까지 연결하기 - 딱 필요한 만큼: 바이브 코딩을 위한 HTML | 위니버시티