Smart Life US

← 목록 · 2026-08-11 · 엑셀·업무 자동화

구글시트 입고 예약 시스템 시트 구조 만들기 — 기본 1편

구글시트 입고 예약 시스템 시트 구조 만들기 — 기본 1편

도입: 창고 안은 정리됐는데, 문 앞은 여전히 혼잡한 이유

구글시트 입고 예약 시스템 만들기를 검색해 들어오신 분들은 대부분 창고·물류 업무를 직접 맡고 있는 실무자일 가능성이 높습니다. 이미 재고관리나 출고 자동화 정도는 어느 정도 정리해 두었지만, 입고 시간 자체를 관리하는 예약 시스템은 여전히 엑셀, 전화, 메신저에 흩어져 있는 경우가 많습니다. 이 글은 그런 상황에서 바로 복붙해 쓸 수 있는, 구글시트 기반 입고 예약 시트 구조를 처음부터 만드는 방법을 다룹니다.

입고예약 시스템 초기화 절차

앞선 글들에서 저는 구글시트로 창고 재고관리 시스템 만들기 | Apps Script 자동화 를 시작으로, 재고 자동 집계·출고 자동화·대시보드·오류 처리까지 기본 창고 작업을 Apps Script로 자동화하는 과정을 정리했습니다. 그 결과 창고 안의 재고·출고 흐름은 어느 정도 잡혔지만, 실제 현장에서는 “트럭이 언제 도착하는지” 정리되지 않아 문 앞에서 다시 병목이 생기는 문제가 남았습니다. 그래서 이번에는 아예 별도 시리즈로 입고 예약 시스템을 단계별로 만들어 보겠습니다. 이 글은 그 중 기본 1편으로, 향후 자동화를 위한 구글시트 입고 예약 시스템 시트 구조를 한 번에 잡아 두는 것이 목표입니다.

시리즈 전체 지도: 어떤 기능을 염두에 두고 구조를 짜는가

입고 예약 시스템을 구글시트와 Apps Script로 만들다 보면 기능이 금방 커집니다. 실무에서 실제로 쓰려면 최소한 예약 등록, 도착 체크인, 현황 대시보드, KPI 리포트, 운송사 포털 정도는 있어야 “엑셀 한 장”을 넘어 시스템답게 동작합니다. 그래서 이 시리즈는 갈래별로 나누어, 필요한 부분만 골라서 붙여도 동작하도록 설계했습니다.

먼저 기본 만들기 갈래에서 현재 글처럼 시트 구조와 공통 설정, 초기화 함수를 준비합니다. 이후에는 예약 등록·도착 체크인·현황 대시보드·KPI·일괄 업로드·운송사 포털·지연·노쇼 처리 순서로 확장해 나갈 예정입니다. 글마다 코드를 바로 복붙해도 서로 충돌하지 않도록, 상수와 함수 이름에 접두어를 붙이고, 공통 메뉴 구조를 유지하는 것을 원칙으로 삼습니다.

이번 글에서는 이 중 첫 단계로, 예약·도어·야드·설정·로그·현황 6개 시트를 한 번에 만들고, 이후 모든 편에서 재사용할 공통 설정 구조를 잡습니다. 구글시트 창고 예약 시스템 초기 설정 단계에서 이 부분이 제대로 잡혀 있으면, 나중에 기능을 추가할 때 구조를 다시 뜯어고치는 일을 크게 줄일 수 있습니다.

기본 구조 설계: 왜 6개 시트인가

구글시트로 입고 예약 시스템을 만들 때 가장 먼저 부딪히는 고민은 “시트를 몇 개로 나눌 것인가”입니다. 한 시트에 다 넣으면 당장은 편해 보이지만, 실제 운영에 들어가면 권한 관리·필터 복잡도·속도 문제로 금방 한계를 느낍니다. 반대로 너무 잘게 나누면 어디에 무엇이 있는지 헷갈립니다. 중형 규모 창고 기준으로 여러 형태를 써 보니, 입고 예약 시스템의 최소 단위는 아래 6개 시트로 나누는 구성이 가장 관리하기 수월했습니다.

  1. APPT_RESERVATIONS (예약 시트)

예약 번호, 날짜·시간, 운송사, 차량 번호, 팔레트 수, 상태(예약·체크인·완료·노쇼 등)를 저장하는 본체입니다. 이후 자동화의 대부분이 이 시트를 기준으로 움직입니다.

  1. APPT_DOORS (도어 시트)

도어 번호, 도어 유형(입고 전용·혼합), 일일 용량, 운영 시간대 등 고정 정보를 담습니다. 도어별 예약 가능 슬롯 계산, 유지보수 시간 반영 등에 사용합니다.

  1. APPT_YARD (야드 시트)

트레일러가 도어에 붙기 전 대기하는 야드 슬롯을 관리하는 시트입니다. 매우 작은 창고에서는 생략해도 되지만, 중형 이상에서는 야드가 병목이 되기 쉬워 별도 시트로 두는 편이 좋았습니다.

  1. APPT_SETTINGS (설정 시트)

시스템 공통 설정을 키–값 형태로 저장합니다. 예약 단위 시간(예: 30분), 일일 최대 입고 팔레트 수, 체크인 허용 범위 같은 값을 여기서 관리하면, Apps Script 코드 안에 숫자를 박아 두지 않아도 됩니다. 이후 “Apps Script 입고 예약 자동화” 단계에서 이 값을 읽어 동적으로 동작을 바꾸게 됩니다.

  1. APPT_LOG (작업 로그 시트)

예약 생성·수정·취소·노쇼 처리 등 주요 이벤트를 시간순으로 기록합니다. 나중에 “누가 언제 무엇을 바꿨는지” 확인하거나 교육용 사례로 활용하기에 좋습니다. 보다 정교한 이력 구조는 구글시트 작업 이력 자동 기록 방법 | Apps Script 9편 에서 다룬 방식을 그대로 확장할 수 있습니다.

  1. APPT_OVERVIEW (현황 시트)

오늘·이번 주 기준으로 예약·완료·노쇼 건수를 집계해서 보여 주는 뷰입니다. 초기에는 피벗테이블과 QUERY 함수만으로도 구성할 수 있고, 이후 편에서 Apps Script로 색상 표시·자동 새로고침을 붙일 예정입니다.

이렇게 나누어 두면 권한 설정과 유지보수가 훨씬 단순해집니다. 예를 들어, 현장 관리자에게는 APPT_RESERVATIONS·APPT_YARD만 편집 권한을 주고, APPT_SETTINGS는 관리자 1~2명만 수정하도록 제한하는 식입니다. 또, 시트별 책임자가 명확해져 센터별 운영 방식을 반영하기에도 좋습니다.

Apps Script로 시트와 머리글 자동 생성하기

이제 구글시트 창고 예약 시스템 초기 설정을 위해 실제 코드를 작성하겠습니다. 목표는 간단합니다. 초기화 함수 한 번으로 6개 시트를 만들고, 1행에 머리글을 세팅하며, 설정 시트에는 필수 키를 자동으로 채워 넣는 것입니다. 이렇게 해 두면 새 센터를 열 때도 스프레드시트를 복사한 뒤 초기화 함수만 실행하면 구조가 바로 잡힙니다.

구조는 다음 네 단계로 나눕니다.

  1. 입고 예약에 필요한 상수(APPT_CONFIG) 정의
  2. initApptSystem() 함수로 6개 시트 생성·머리글 세팅
  3. setupHeaders_() 로 각 시트 머리글 서식 적용
  4. ensureApptSettingsKeys_() 로 APPT_SETTINGS 필수 키 자동 삽입

각 단계별로 코드와 설치 위치, 확인 방법을 차례대로 보겠습니다.


1단계 — 입고 예약 설정 상수 정의

이 코드는 입고 예약 시스템에 필요한 시트 이름과 머리글, 필수 설정 키 목록, 설정 시트 머리글을 한 곳에 모아 두는 역할을 합니다.

설치 위치: 구글시트 → 확장 프로그램 → Apps Script → Code.gs 맨 위쪽에 붙여넣습니다.

붙여넣은 뒤에는 저장(⌘S 또는 Ctrl+S)만 하면 됩니다.

Apps Script (JavaScript)
const APPT_CONFIG = {                                           // → 입고 예약 전용 설정
  SHEET_NAMES: {                                                // → 시트 이름 모음
    RESERVATIONS: 'APPT_RESERVATIONS',                          // → 예약 시트
    DOORS: 'APPT_DOORS',                                        // → 도어 마스터
    YARD: 'APPT_YARD',                                          // → 야드 현황
    SETTINGS: 'APPT_SETTINGS',                                  // → 설정 시트
    LOG: 'APPT_LOG',                                            // → 작업 로그
    OVERVIEW: 'APPT_OVERVIEW',                                  // → 현황 요약
  },
  RESERVATION_HEADERS: [                                        // → 예약 시트 머리글
    '예약ID',                                                   // → 고유 예약 번호
    '예약일자',                                                 // → yyyy-mm-dd
    '예약시간',                                                 // → hh:mm
    '운송사',                                                   // → 운송사명
    '차량번호',                                                 // → 차량 번호
    '팔레트수',                                                 // → 입고 팔레트 수
    '제품군',                                                   // → 제품 유형
    '도어',                                                     // → 배정 도어
    '상태',                                                     // → 예약/체크인/완료 등
    '비고',                                                     // → 메모
    '생성시각',                                                 // → 예약 생성 시간
    '생성자',                                                   // → 예약 생성자
    '최종수정시각',                                             // → 마지막 변경 시간
    '최종수정자',                                               // → 마지막 변경자
  ],
  DOOR_HEADERS: [                                               // → 도어 시트 머리글
    '도어번호',                                                 // → 도어 ID
    '유형',                                                     // → 입고/혼합 등
    '일일최대팔레트',                                           // → 용량
    '시작시간',                                                 // → 운영 시작
    '종료시간',                                                 // → 운영 종료
    '사용여부',                                                 // → 활성/비활성
    '비고',                                                     // → 메모
  ],
  YARD_HEADERS: [                                               // → 야드 시트 머리글
    '슬롯ID',                                                   // → 야드 슬롯
    '상태',                                                     // → 사용중/비어있음
    '예약ID',                                                   // → 연결 예약
    '차량번호',                                                 // → 차량 번호
    '체크인시각',                                               // → 야드 진입
    '출차시각',                                                 // → 야드 이탈
    '비고',                                                     // → 메모
  ],
  SETTINGS_HEADERS: [                                           // → 설정 시트 머리글
    'KEY',                                                      // → 설정 키
    'VALUE',                                                    // → 값
    '설명',                                                     // → 설명
  ],
  SETTINGS_REQUIRED_KEYS: [                                     // → 필수 설정 키
    'TIME_SLOT_MINUTES',                                        // → 예약 단위 분
    'DAILY_MAX_PALLETS',                                        // → 일일 최대 팔레트
    'CHECKIN_EARLY_MINUTES',                                    // → 조기 체크인 허용 분
    'CHECKIN_LATE_MINUTES',                                     // → 지연 체크인 허용 분
    'DEFAULT_DOOR_TYPE',                                        // → 기본 도어 유형
  ],
  LOG_HEADERS: [                                                // → 로그 시트 머리글
    '시각',                                                     // → 로그 시각
    '사용자',                                                   // → 작업자
    '동작',                                                     // → 생성/수정/취소 등
    '예약ID',                                                   // → 대상 예약
    '설명',                                                     // → 요약 설명
    '상세내용',                                                 // → 상세 내역
  ],
  OVERVIEW_HEADERS: [                                           // → 현황 시트 머리글
    '날짜',                                                     // → 입고 일자
    '총예약건수',                                               // → 건수
    '총팔레트수',                                               // → 수량
    '완료건수',                                                 // → 완료
    '노쇼건수',                                                 // → 노쇼
    '평균대기분',                                               // → 분
  ],
};

제대로 됐는지 확인하는 법: 저장 후 편집기에서 APPT_CONFIG 부분에 빨간 밑줄이 없으면 정상입니다. 아직 화면상 변화는 없습니다.


2단계 — 시트 생성 도우미: getOrCreateSheet_()

이 함수는 “시트가 있으면 가져오고, 없으면 새로 만드는” 공통 도우미입니다. 다른 글에서 이미 사용 중인 함수가 없다면 아래 버전을 사용하면 됩니다.

설치 위치: APPT_CONFIG 아래, 다른 함수들보다 위쪽에 두면 관리하기 좋습니다.

Apps Script (JavaScript)
function getOrCreateSheet_(ss, name) {                          // → 시트 가져오기/생성
  let sheet = ss.getSheetByName(name);                          // → 이름으로 조회
  if (!sheet) {                                                 // → 없으면
    sheet = ss.insertSheet(name);                               // → 새 시트 생성
  }
  return sheet;                                                 // → 시트 반환
}

3단계 — 초기 설치 함수: initApptSystem()

이 코드는 “초기 설치”를 눌렀을 때 6개 시트를 만들고, 각 1행에 머리글을 넣으며, APPT_SETTINGS 시트에는 머리글을 세팅한 뒤 필수 키가 없으면 자동으로 추가합니다. 이미 시트가 있어도 데이터를 지우지 않고 머리글과 설정 키만 보강합니다.

설치 위치: Code.gs 중간 또는 하단에 붙여넣습니다.

붙여넣은 뒤 initApptSystem 을 한 번 실행해 권한을 허용합니다.

Apps Script (JavaScript)
function initApptSystem() {                                     // → 입고 예약 시스템 초기 설치
  const lock = LockService.getScriptLock();                     // → 동시 실행 방지 잠금
  lock.waitLock(30000);                                         // → 최대 30초 대기
  try {
    const ss = SpreadsheetApp.getActiveSpreadsheet();           // → 현재 스프레드시트
    const names = APPT_CONFIG.SHEET_NAMES;                      // → 시트 이름 모음

    const resSheet = getOrCreateSheet_(ss, names.RESERVATIONS); // → 예약 시트 확보
    const doorSheet = getOrCreateSheet_(ss, names.DOORS);       // → 도어 시트 확보
    const yardSheet = getOrCreateSheet_(ss, names.YARD);        // → 야드 시트 확보
    const setSheet = getOrCreateSheet_(ss, names.SETTINGS);     // → 설정 시트 확보
    const logSheet = getOrCreateSheet_(ss, names.LOG);          // → 로그 시트 확보
    const ovSheet = getOrCreateSheet_(ss, names.OVERVIEW);      // → 현황 시트 확보

    // 각 시트 머리글 세팅
    setupHeaders_(resSheet, APPT_CONFIG.RESERVATION_HEADERS);   // → 예약 머리글 세팅
    setupHeaders_(doorSheet, APPT_CONFIG.DOOR_HEADERS);         // → 도어 머리글 세팅
    setupHeaders_(yardSheet, APPT_CONFIG.YARD_HEADERS);         // → 야드 머리글 세팅
    setupHeaders_(logSheet, APPT_CONFIG.LOG_HEADERS);           // → 로그 머리글 세팅
    setupHeaders_(ovSheet, APPT_CONFIG.OVERVIEW_HEADERS);       // → 현황 머리글 세팅
    setupHeaders_(setSheet, APPT_CONFIG.SETTINGS_HEADERS);      // → 설정 시트 머리글 세팅

    // 설정 시트 필수 키 보강
    ensureApptSettingsKeys_(setSheet);                          // → 설정 키 채우기

    Logger.log('initApptSystem 완료');                          // → 실행 로그 남기기
  } finally {
    lock.releaseLock();                                         // → 잠금 해제
  }
}

제대로 됐는지 확인하는 법: 편집기 상단 함수 목록에서 initApptSystem 을 선택 후 실행 버튼을 누릅니다. 처음 실행 시 권한 허용 창이 뜨면 안내에 따라 승인합니다. 실행이 끝난 뒤 스프레드시트에 APPT_RESERVATIONS 등 6개 시트가 생기고, 각 시트의 1행에 머리글이 채워져 있으면 성공입니다.


4단계 — 머리글 세팅 도우미: setupHeaders_()

이 코드는 각 시트의 1행에 머리글을 입력하고, 글자를 굵게 표시하며 1행을 고정하는 역할을 합니다. 기존 데이터가 있어도 2행 이후는 건드리지 않습니다.

설치 위치: initApptSystem 함수 바로 아래에 붙여넣습니다.

Apps Script (JavaScript)
function setupHeaders_(sheet, headers) {                        // → 시트 머리글 설정
  if (!sheet) return;                                           // → 시트 없으면 중단

  const headerRow = 1;
  const headerRange = sheet.getRange(headerRow, 1, 1, headers.length);

  headerRange.setValues([headers]);                             // → 머리글 입력
  headerRange.setFontWeight('bold');                            // → 굵게 표시

  sheet.setFrozenRows(headerRow);                               // → 1행 고정

  // 기존 데이터 열이 머리글보다 많을 수 있으니, 나머지 셀은 그대로 둡니다.
}

제대로 됐는지 확인하는 법: initApptSystem 을 다시 실행한 후, 각 시트의 첫 줄이 굵게 표시되고 스크롤해도 항상 상단에 고정되어 있으면 정상입니다. 기존 데이터가 있다면 2행 이후 내용은 그대로 유지되는지 함께 확인합니다.


5단계 — 설정 시트 키 자동 채우기: ensureApptSettingsKeys_()

이 코드는 APPT_SETTINGS 시트에 필수 설정 키가 모두 있는지 확인하고, 없으면 새 행으로 자동 추가합니다. 이미 존재하는 키는 덮어쓰지 않기 때문에, 운영 중에 VALUE 값을 수정해도 안심하고 초기화 함수를 다시 돌릴 수 있습니다.

APPT_SETTINGS 시트는 1행 = 머리글(KEY, VALUE, 설명), 2행 이후 = 데이터 구조를 기준으로 합니다.

설치 위치: setupHeaders_ 함수 아래에 붙여넣습니다.

Apps Script (JavaScript)
function ensureApptSettingsKeys_(sheet) {                       // → 필수 설정 키 채우기
  if (!sheet) return;                                           // → 시트 없으면 중단

  const requiredKeys = APPT_CONFIG.SETTINGS_REQUIRED_KEYS;      // → 필수 키 목록
  if (!requiredKeys || requiredKeys.length === 0) return;       // → 없으면 종료

  const lastRow = sheet.getLastRow() || 1;                      // → 최소 1행(머리글)
  // 2행부터 실제 KEY 값 읽기
  const existingKeys = lastRow > 1
    ? sheet.getRange(2, 1, lastRow - 1, 1)                      // → A열만
        .getValues()
        .map(row => String(row[0] || '').trim())
        .filter(key => key)
    : [];

  const toAppend = [];
  for (const key of requiredKeys) {                             // → 필수 키 반복
    if (!existingKeys.includes(key)) {                          // → 없으면
      toAppend.push([key, '', '']);                             // → KEY / VALUE / 설명(공란)
    }
  }

  if (toAppend.length > 0) {
    sheet.getRange(lastRow + (lastRow === 1 ? 0 : 1), 1, toAppend.length, 3)
         .setValues(toAppend);                                  // → 빈 값으로 추가
  }
}

제대로 됐는지 확인하는 법: initApptSystem 을 다시 실행한 뒤 APPT_SETTINGS 시트를 열어 봅니다.

  • 1행: KEY | VALUE | 설명 머리글이 들어가 있어야 합니다.
  • 2행 이후 A열 KEY에 TIME_SLOT_MINUTES, DAILY_MAX_PALLETS, CHECKIN_EARLY_MINUTES, CHECKIN_LATE_MINUTES, DEFAULT_DOOR_TYPE 가 한 줄씩 들어가 있으면 성공입니다.

이후 B열 VALUE에 각 센터 운영 기준대로 값을 채워 넣으면 됩니다. 설명(C열)은 나중에 운영 중에 작성해도 무방합니다.


6단계 — 메뉴에서 한 번에 실행하기: onOpen과 예약 도구 메뉴

매번 Apps Script 편집기를 열어 initApptSystem 을 실행하는 것은 실무에서 번거롭습니다. 시트를 열었을 때 상단 메뉴에 “예약 도구 → 초기 설치” 항목을 만들어 두면, 운영 중에도 구조 점검이 필요할 때 한 번씩 눌러 줄 수 있습니다.

설치 위치: Code.gs 맨 아래에 붙여넣습니다. 다른 글의 onOpen() 과 충돌하지 않도록, 입고 예약 전용 프로젝트에서 사용하는 것을 권장합니다.

Apps Script (JavaScript)
function onOpen() {                                             // → 시트를 열 때 실행
  const ui = SpreadsheetApp.getUi();                            // → UI 객체
  const menu = ui.createMenu('예약 도구');                      // → 메뉴 생성
  addApptBaseMenu_(menu);                                       // → 기본 항목 추가
  menu.addToUi();                                               // → 메뉴 표시
}

function addApptBaseMenu_(menu) {                               // → 기본 갈래 메뉴
  menu.addItem('초기 설치', 'initApptSystem');                  // → 초기 설치 버튼
}

제대로 됐는지 확인하는 법: 스크립트를 저장한 뒤 스프레드시트를 새로 열어 상단 메뉴를 확인합니다. “예약 도구” 메뉴가 보이고, 그 안에 “초기 설치” 항목이 있다면 정상입니다. “초기 설치”를 클릭하면 initApptSystem 이 실행되고, 앞에서 설명한 6개 시트·머리글·설정 키가 맞게 구성되어 있어야 합니다.


실무 팁: 구조를 잡을 때 미리 생각해 둘 것들

실제 창고에서 구글시트 입고 예약 시스템을 운영해 보면, 코드보다 구조 설계가 더 많은 문제를 좌우합니다. 이번 편에서 시트 구조와 초기화 로직에 많은 비중을 둔 이유도 여기에 있습니다. 실무에서 특히 도움이 되었던 포인트를 몇 가지 정리합니다.

  1. 머리글 이름은 사람 눈에 잘 보이되, 자주 바꾸지 않을 표현으로 정하기

“예약일자”를 나중에 “입고일자”로 바꾸고 싶다면, 코드에서는 특정 머리글 텍스트 대신 열 위치(1열, 2열)를 기준으로 접근하는 방식이 더 안전합니다. 이번 글의 코드에서는 머리글 텍스트를 읽어서 로직에 쓰지 않고, 단순히 1행에 세팅만 합니다. 이후 열 참조가 필요한 부분은 별도의 상수로 관리할 예정입니다.

  1. APPT_SETTINGS 시트는 최대한 일찍 만들어 두기

예약 단위, 일일 최대 팔레트 수, 체크인 허용 범위 같은 값은 실제 운영을 시작하면 조정이 잦습니다. 코드 안에 숫자로 박아 두면, 변경 때마다 개발자나 파워 유저의 손을 빌려야 합니다. 이번 글에서 SETTINGS_HEADERS, SETTINGS_REQUIRED_KEYS, ensureApptSettingsKeys_() 를 통해 최소한의 틀을 먼저 세워 둔 이유가 여기에 있습니다.

  1. 동시 실행과 구조 꼬임을 예방하는 습관: LockService 사용하기

초기 설치 함수조차 동시에 두 번 실행되면 머리글이 꼬이거나 시트가 중복 생성되는 사례가 나올 수 있습니다. 예약 저장·정리 함수에서는 더 정교한 잠금과 검증이 필요하며, 이 부분은 이후 “예약 저장 로직” 편에서 LockService, try/catch, 백업 구조와 함께 구체적으로 다룰 예정입니다. 관련 기초 개념은 구글시트 Apps Script 오류 처리 백업 방법 | LockService·try/catch·DriveApp 백업 글을 참고하시면 좋습니다.

  1. 시트 이름과 코드 상수 이름을 명확히 분리해 두기

시트 이름은 'APPT_RESERVATIONS' 처럼 고정 문자열로 두고, 코드에서는 APPT_CONFIG.SHEET_NAMES.RESERVATIONS 식으로 참조하는 패턴을 유지하면 됩니다. 나중에 시리즈 다른 편 코드와 합칠 때도, 접두어(APPT_)만 보고 범위를 구분할 수 있어 충돌을 줄일 수 있습니다.


자주 발생하는 오류와 해결 방법

이번 초기 설정 단계에서 실무자분들이 자주 겪는 오류를 정리해 두면, 현장에서 시간을 아낄 수 있습니다.

  1. getOrCreateSheet_ 가 정의되지 않았다는 오류

이 글에서는 편의상 도우미 함수를 짧게 포함했지만, 이전에 다른 프로젝트에서 사용하던 getOrCreateSheet_() 코드가 이미 있다면 이름이 겹쳐 오류가 날 수 있습니다. 이때는 역할이 같은지 비교해 본 뒤 하나만 남기고 중복 선언을 제거하는 것이 좋습니다. 이름이 다르다면, initApptSystem 안에서 사용하는 함수 이름만 본인이 쓰던 이름으로 바꿔도 됩니다.

  1. 권한 관련 오류

initApptSystem 이 시트 생성·수정 권한을 요구하기 때문에, 처음 실행할 때 구글 계정 권한 승인 절차를 반드시 거쳐야 합니다. Apps Script 편집기에서 직접 initApptSystem 을 한 번 실행해 허용을 마친 뒤, 상단 메뉴 “예약 도구 → 초기 설치”를 사용하는 순서를 추천합니다. 승인 없이 바로 메뉴에서 실행하면 같은 오류 메시지가 반복됩니다.

  1. APPT_SETTINGS 값이 비어 있는 채로 운영을 시작하는 문제

다른 팀원이 같은 스프레드시트를 복사해 새 센터용으로 사용할 때 자주 발생합니다. 이를 방지하려면, 초기 설치 후 설정 시트에서 최소한 TIME_SLOT_MINUTES, DAILY_MAX_PALLETS 두 값은 운영 전에 반드시 채우도록 체크리스트에 넣어 두는 것이 좋습니다.


맺음말: 오늘 할 일 하나 — 초기화 함수까지 실행해 보기

입고 예약 시스템은 “입력 폼”보다 그 위에 얹힐 시트 구조와 설정 틀이 먼저입니다. 이번 글에서는 구글시트 입고 예약 시스템 시트 구조 만들기를 목표로, 6개 시트 구성, 공통 설정 상수(APPT_CONFIG), 초기화 함수(initApptSystem), 설정 키 자동 채우기(ensureApptSettingsKeys_), 머리글 세팅(setupHeaders_), 메뉴 연동(onOpen)까지 한 번에 정리했습니다.

오늘 당장 할 수 있는 행동은 한 가지입니다. 이 글의 코드를 순서대로 Apps Script에 붙여넣고 저장한 뒤, 스프레드시트 상단에서 “예약 도구 → 초기 설치”를 한 번 눌러 보는 것입니다. 그 결과로 6개 시트가 생기고 머리글과 설정 키가 정리되어 있다면, 이미 입고 예약 시스템의 기반 절반은 준비된 상태입니다.

다음 편에서는 이 구조 위에 실제 예약을 한 줄씩 쌓을 수 있도록, 예약 등록용 컬럼 설계와 기본 검증 로직, 그리고 저장 함수의 안전장치들을 단계적으로 추가하겠습니다.