[태그:] 구글 시트

  • 스프레드시트 자동화, 이 설정 놓치면 데이터 망가집니다

    스프레드시트 자동화, 이 설정 놓치면 데이터 망가집니다

    매일 복붙하는 그 작업, 시트가 알아서 합니다

    구글 스프레드시트 자동화를 검색하는 순간 대부분은 이런 상황일 겁니다. 아침마다 폼 응답을 열어 복사해서 정리하고, 다른 시트에서 숫자를 받아다 집계표를 갱신하고, 그걸 보고서 양식에 붙여 넣는다. 코딩을 배울 시간은 없고, 그렇다고 이 반복을 계속할 수도 없다. 그 사이 어딘가에 있을 겁니다.

    나는 혼자서 콘텐츠 생성과 발행을 무인으로 돌리는 입장이라 시트뿐 아니라 서버의 예약 작업까지 cron 63개를 직접 관리한다. 그래서 아는 것이다. 자동화는 어렵지 않은데, ‘망가졌을 때 조용히 망가진다’는 게 진짜 문제라는 걸. 이 글은 함수 나열이 아니라 실패했을 때 어떻게 붙잡는지까지 쓴다.

    개발을 못 해도 시작할 수 있을까?

    된다. 스프레드시트 자동화란 반복되는 데이터 입력·정리·집계를 사람 대신 시트 함수와 예약 실행이 처리하도록 만드는 작업이다. 구글 시트는 함수만으로도 상당 부분 자동화되고, 거기서 한 발 더 가면 ‘매크로 녹화’가 있고, 그다음이 Apps Script라는 코드다. 이 순서대로 가면 코드를 직접 짜는 순간은 생각보다 늦게 온다. 나도 처음엔 녹화 매크로에서 시작했다.

    오늘부터 자동화 가능한 작업 vs 아닌 작업 구분법

    구분 기준은 하나다. “입력이 정해진 형태로 들어오고, 출력 규칙이 사람이 문장으로 설명할 수 있는가?” 예컨대 ‘폼 응답이 쌓이면 미결제 건만 뽑아 별도 탭으로 옮긴다’는 규칙이라 자동화된다. 반면 ‘이번 주 분위기에 맞게 홍보 문구를 손봐라’처럼 판단이 매번 달라지는 일은 사람 몫으로 남긴다. 경계선 애매하면 일주일 치 작업을 수기로 하면서 내 판단을 문장으로 적어보라. 문장이 안 나오는 작업은 아직 자동화 대상이 아니다.

    시작 전 5분 점검: 이 설정 놓치면 데이터가 망가집니다

    자동화 사고의 대부분은 화려한 기술 실패가 아니라 설정 누락에서 나온다. 실제로 나는 무인 배치가 권한 만료로 조용히 멈춘 걸 한참 뒤에야 알았다. 에러도 없다. 그냥 안 돌았을 뿐. 그 뒤로는 뭘 만들든 아래 다섯 가지를 먼저 확인하고 시작한다.

    1. 큰 배치를 돌리기 전에 파일 > 사본 만들기로 백업본을 떠 둔다.
    2. 원본 데이터 시트와 자동화 결과 시트를 파일 단위로, 최소 탭 단위로 분리한다.
    3. 자동화 계정의 접근 권한이 ‘편집자’ 이상인지, 만료일이 없는지 확인한다.
    4. 자동화가 결과를 ‘덮어쓰는지’, ‘행을 추가하는지’를 정해 두고 기록해 둔다.
    5. 시트 파일 설정의 시간대를 한국 표준시로 맞춘다.

    자동화 전 반드시 백업해 두기

    구글 시트는 버전 기록이 기본 켜져 있지만, Apps Script나 외부 도구가 대량 수정을 하면 최근 상태 위에 계속 덮인다. 복구 지점이 필요하면 큰 배치를 돌리기 직전에 파일을 복제해 두는 습관이 가장 확실하다. 나는 원본을 읽기 전용으로 두고, 자동화는 사본에만 쓰게 만든다. 이 구조로 가면 스크립트가 아무리 잘못돼도 원본은 남는다.

    원본 시트와 자동화 시트를 분리하는 구조 설계

    흔한 사고가 ‘사람이 보는 집계표’와 ‘기계가 쓰는 원천 데이터’가 같은 탭에 섞이는 거다. 정렬 한 번 잘못 누르면 함수가 참조하던 행이 전부 어긋난다. 구조는 단순하게. 데이터가 쌓이는 탭(사람 손 금지), 함수가 읽어 정리하는 탭, 사람이 보는 리포트 탭. 이렇게 세 겹으로 나누면 중간이 망가져도 원천은 살아 있다.

    권한·공유 설정에서 자주 터지는 함정

    Apps Script가 다른 스프레드시트를 읽게 하면 권한 승인 팝업이 뜨는데, 이걸 브라우저에서 한 번 승인했다고 끝이 아니다. 계정 비밀번호를 바꾸거나, 소유자가 문서를 이동하거나, 승인 토큰이 만료되면 조용히 끊긴다. 워크스페이스 관리자가 앱 권한을 정리하는 바람에 끊기는 경우도 봤다. 그래서 나는 권한을 링크가 아니라 특정 계정 기준으로 부여하고, 스크립트 소유 계정을 자동화 전용 하나로 고정해서 쓴다.

    폼 응답·외부 데이터 자동으로 쌓기: 세팅 순서대로 따라하기

    데이터가 자동으로 쌓이는 구조를 만들면 그다음 정리·집계는 시트 함수의 몫이 된다. 내 운영 시트도 같은 구조다. 폼과 외부 도구가 쓰는 탭, 그걸 읽어 상태를 정리하는 탭, 리포트 탭. 스크린샷 대신 구조로 보면 이렇다.

    시트 구조 템플릿: [raw] 폼 응답 원본 (사람 금지 구역) / [clean] QUERY 함수로 상태별 분류 / [report] 월별 집계 + 조건부 서식 / [log] 자동화 실행 기록 남기는 탭

    구글폼 → 시트 연결 후 응답 자동 정리 구조 만들기

    구글폼의 ‘스프레드시트에 연결’을 누르면 응답 탭이 자동 생긴다. 여기서 바로 원본을 고치려 들면 안 된다. 응답 탭 옆에 탭을 하나 만들고 QUERY로 끌어오는 식이다. 예컨대 =QUERY('폼 응답 1'!A:H, "select B,C,E where E = '미결제'") 같은 형태로 쓰면 미결제 건만 별도 탭에 실시간으로 뜬다. 이러면 폼이 몇 백 건 쌓여도 정리 탭은 늘 같은 모양을 유지한다.

    IMPORTRANGE로 다른 시트 데이터 가져오기와 주의점

    다른 파일의 데이터는 IMPORTRANGE로 가져온다. 첫 실행 때 권한 승인을 한 번 눌러야 하는데 이걸 놓치고 ‘왜 안 되지’를 오래 하는 경우가 많다. 주의점은 로딩이다. 참조 범위가 크면 화면에 뜨는 데 시간이 걸리고, 그 사이 다른 함수가 빈 값을 참조해 오류를 낸다. 그래서 나는 IMPORTRANGE로 통째로 전용 탭에 받아 놓고, 다른 함수는 그 탭만 바라보게 나눠 쓴다. 원본이 덜 흔들린다.

    외부 데이터(API·다른 도구)를 쌓는 최소 구성

    외부 데이터가 필요하면 Apps Script로 받아서 쌓는 게 최소 구성이다. URL Fetch 서비스로 API를 부르고, 결과를 raw 탭에 행으로 추가한다. 실행 기록은 log 탭에 남긴다. 비용 관련해서 하나만 적자면, 나는 헤드리스로 LLM을 부를 때 기본 설정이 1회 $0.78이었던 걸 모델과 작업 디렉터리를 지정하고 불필요한 도구를 떼는 방식으로 $0.028까지 줄인 적이 있다. 외부 API를 쓰는 자동화는 이렇게 호출 단가와 횟수를 먼저 따져보고 붙여야 한다. 생략하면 청구서로 배우게 된다.

    기본형은 이렇다. 마지막 행 다음에 붙이는 구조라 덮어쓰기 사고가 없다.

    function appendOrder() {
      const sh = SpreadsheetApp.getActive().getSheetByName('raw');
      const row = [new Date(), '주문', '자동 수집'];
      sh.appendRow(row);
      SpreadsheetApp.getActive().getSheetByName('log')
        .appendRow([new Date(), 'appendOrder', 'ok']);
    }
    시간·폼·수정 트리거 일러스트

    트리거 완전 정리: 시간·폼 제출·수정 시, 언제 뭘 써야 하나

    자동화를 ‘걸어두는’ 장치가 트리거다. 어떤 트리거를 쓰느냐에 따라 실패 양상이 달라지니, 선택 기준부터 정리한다. 무인으로 돌리는 입장에서 내가 실제로 쓰는 판단 표다.

    상황 트리거 주의점
    매일 정해진 시각에 집계 갱신 시간 기반 (일 단위 타이머) 지정 시각이 아니라 그 시간대 안에 임의 실행된다
    폼 응답이 올 때마다 정리 양식 제출 시 응답 탭 반영이 늦으면 빈 값을 읽을 때가 있다
    특정 셀을 고치면 즉시 처리 설치 가능한 onEdit 수정 즉발이라 중복 실행 방지 로직이 필요하다
    1시간마다 외부 API 폴링 시간 기반 (시간 단위 타이머) 실행 한도와 API 호출 단가를 먼저 확인한다

    각 트리거의 함정: 중복 실행, 실행 한도, 타임존

    시간 기반 트리거는 ‘매일 오전 6시’로 지정해도 6시 정각이 아니라 그 시간대 안에서 구글이 정한 시점에 돈다. 나는 cron 63개를 무인으로 돌리는데, 시간 지정을 하는 순간부터 ‘정시 보장이 없다’를 전제하고 설계한다. 중복 실행도 조심한다. 사람이 셀을 빠르게 여러 번 고치면 onEdit가 그 횟수만큼 발생한다. 그래서 스크립트 첫머리에 ‘같은 행을 최근에 처리했으면 건너뛰기’ 확인을 넣는다. 타임존은 파일 설정과 스크립트 설정이 따로 놀 때가 있다. Apps Script 프로젝트 설정에서 Asia/Seoul로 맞춰두지 않으면 날짜 경계가 어긋나서 새벽 배치가 전날 데이터를 가져간다.

    매크로 녹화에서 Apps Script 트리거로 넘어가는 시점

    매크로 녹화로 시작해도 된다. 녹화하면 내부적으로 Apps Script가 만들어지니까, 나중에 확장하기도 쉽다. 넘어갈 시점의 신호는 두 가지다. 녹화된 매크로를 조건에 따라 다르게 굴러가게 하고 싶어질 때, 그리고 자동 실행을 걸고 싶을 때다. 매크로는 트리거에 조건 분기 얹기가 어색하니, 그때 코드를 열어 녹화본을 고치는 식으로 넘어가면 된다.

    자동화가 실패했을 때: 복구 5단계와 재발 방지 세팅

    여기가 이 글의 심장이다. 자동화 실패는 대부분 소리 없이 온다. 나는 이 블로그의 글도 문체·사실성 자동 검사를 통과한 것만 공개하는 구조로 운영하는데, 검사를 통과 못 한 초안은 사람이 검토한다. 이 원칙을 만든 이유가 바로 무음 실패 때문이었다. 자동화가 잘못된 걸 스스로 알려주는 경우는 생각보다 드물다.

    데이터가 꼬였을 때 복구 순서 (버전 기록 활용)

    복구는 서두르면 망가진다. 순서를 지켜라. 첫 단계로 트리거를 일시 중지한다. 이걸 안 하고 고치는 사이 배치가 또 돌아서 꼬임이 두 배가 된다. 다음은 raw 탭이 온전한지 확인한다. 원천이 살아 있으면 정리 탭은 함수 다시 당기는 걸로 끝난다. raw까지 손댔다면 파일 > 버전 기록에서 망가지기 직전 시점으로 복사본을 만든다. 원본에 바로 복원하지 말고 사본에서 검증부터. 검증이 끝나면 복구본을 새 원본으로 삼고, 마지막으로 log 탭에 뭐가 어긋났는지 한 줄 적어둔다. 이 기록이 다음 사고를 줄인다.

    무음 실패를 잡는 실패 알림 세팅법

    실패 알림은 try-catch로 에러를 잡아 본인 메일이나 슬랙으로 쏘는 게 최소 구성이다. 성공 알림도 하나 남겨두라는 게 내 방식이다. ‘오늘 6시 배치 완료’라는 한 줄이 안 오면 그 자체가 실패 신호다. 에러만 알려주는 구조는 ‘에러 없이 안 돈 경우’를 못 잡는다. 권한 만료로 멈춘 배치가 정확히 그 경우였다. 실패 처리 코드는 짧게 이런 모양이다.

    function dailyJob() {
      try {
        // 본문 처리
        MailApp.sendEmail('[email protected]', '배치 완료', 'ok');
      } catch (e) {
        MailApp.sendEmail('[email protected]', '배치 실패', e.message);
      }
    }

    절대 자동화하면 안 되는 작업의 경계선

    경계선을 세 개 둔다. 원본 삭제·파기가 결과인 작업은 자동화하지 않는다. 돈이 실제로 움직이는 결제·환불 실행은 사람 확인 없이 돌리지 않는다. 그리고 ‘판단 기준을 글로 못 쓰겠다’는 작업은 애초에 자동화 대상이 아니다. 이 세 개를 넘는 자동화는 절약해 주는 시간보다 되돌리는 데 드는 시간이 커진다.

    정리: 1인 운영 루틴과 오늘 당장 시작하는 3단계

    이 블로그는 한 달 반 동안 43편을 발행했는데, 초안 생성에서 공개까지 기계가 하고 사람이 검수하는 구조다. 그걸 가능하게 한 건 화려한 기술이 아니라 점검 루틴이다. 자동화는 한 번 만드는 게 아니라 매주 쳐다보는 시스템이다.

    주문·문의 집계 자동화 사례와 매주 월요일 5분 점검

    1인 사업자에게 시트 자동화의 최대 수혜는 집계 시간이 아니라 ‘깜빡함’이 사라지는 거다. 주문 폼, 문의 폼, 재고 시트가 각자 쌓이고 리포트 탭이 알아서 갱신되면 아침에 확인 한 번으로 끝난다. 나의 월요일 루틴은 이렇다. 배치 성공 알림이 주간 분량대로 쌓였는지 본다. log 탭에서 지난주 에러 한 줄을 훑는다. 마지막으로 raw 탭 맨 아래행의 타임스탬프가 최근인지 확인한다. 셋 다 이상 없으면 점검 끝이다. 이 루틴으로 잡은 사고가 더러 있다. 그중 반은 권한 문제였다.

    자동화 확장 순서: 시트 → 폼 → 알림 → 외부 도구

    확장은 순서가 있다. 시트 함수로 정리를 붙잡고, 폼으로 입력을 규격화하고, 알림으로 무음 실패를 막은 다음에 외부 도구를 붙인다. 이 순서를 뒤집으면 외부 도구가 고장 났을 때 원인을 특정할 수가 없다. 나도 초반에 순서를 무시했다가 어디서부터 망가졌는지 몰라 전부 끊고 다시 쌓은 적이 있다.

    오늘 당장 시작하는 3단계 행동 플랜

    1단계는 복붙 작업 하나를 골라 원본 시트와 자동화 시트를 분리하는 것부터다. 2단계는 트리거 딱 하나만 걸고 사흘이 아니라 며칠간 지켜보는 것이다. 실행 기록 탭을 같이 만들어두면 지켜보는 게 훨씬 쉬워진다. 3단계는 성공·실패 알림을 붙이는 것. 여기까지 오면 진짜 무인 운영이다. 관련해서 Apps Script 타임존 설정 실패기, 무코드 자동화의 한계와 넘어설 시점, 무음 실패를 잡는 점검 루틴 글도 함께 보면 좋다.

    자주 묻는 질문

    코딩을 전혀 몰라도 자동화할 수 있나요? 시트 함수와 매크로 녹화 수준이면 코딩 없이 충분합니다. Apps Script는 필요해지면 그때 녹화본을 조금씩 고치는 방식으로 시작하면 됩니다.

    무료로 가능한가요? 요금은 언제 드나요? 구글 시트의 함수·트리거·메일 알림은 무료 구간에서 돌아갑니다. 외부 API를 매시간 부르는 구조로 가면 그때부터 호출 비용을 따져야 합니다. 내 경우 호출 단가를 27배 줄인 적이 있으니 설정을 먼저 점검하세요.

    트리거가 갑자기 멈추면 어떻게 확인하나요? Apps Script의 ‘내 실행’ 로그부터 보세요. 로그에 실행 기록 자체가 없으면 권한 만료나 트리거 삭제를 의심합니다. 성공 알림이 안 오는 경우도 같은 방향으로 확인하면 됩니다.


    글쓴이 정보

    제가 만든 AI 파이프라인이 초안을 쓰고, 저는 검사에 걸린 것만 손봅니다. 통과하지 못한 초안은 그냥 버립니다. 파이프라인은 여기에 정리해 두었습니다.