구글시트 도크 도어 자동 생성 방법: 30개·야드 슬롯 50개 한 번에 만들기
도입: 도크 도어·야드 슬롯, 왜 아직도 손으로 치고 있나
구글시트로 입고 예약 시스템을 만들다 보면 꼭 필요한 것이 도크 도어와 야드 슬롯 목록입니다. 그런데 현장에서는 이 간단한 목록을 아직도 손으로 하나씩 입력하는 경우가 많습니다. 도어가 30개, 야드 슬롯이 50개만 되어도 번호를 일일이 치다 보면 중간에 빠뜨리거나 잘못 쓰는 일이 자주 생깁니다. 이 글에서는 이런 반복 작업을 없애는 구글시트 도크 도어 자동 생성 방법을 다룹니다.
앞선 글인 구글시트 입고 예약 시스템 시트 구조 만들기 — 기본 1편에서는 예약용 기본 시트 구조와 설정 시트를 만들어 두었습니다. 이번 2편에서는 그 구조 위에 Apps Script 코드로 도크 도어 30개(D01~D30), 야드 슬롯 50개(Y01~Y50)를 자동 생성하고, 이후 예약 로직에서 활용할 수 있도록 ‘사용 중’인 도어·슬롯만 읽어 오는 함수와 테스트 함수까지 준비합니다. 코드 한 번으로 시드를 넣고, 테스트 실행 로그로 결과를 바로 확인할 수 있도록 구성합니다.
또 하나 중요한 점이 있습니다. 이 시리즈의 스크립트는 결국 하나의 Apps Script 프로젝트로 합쳐서 쓰는 것을 전제로 합니다. 구글시트 입고 예약 시스템 시트 구조 만들기 — 기본 1편에서도 onOpen이 등장했기 때문에 같은 프로젝트에 그대로 붙여 넣으면 onOpen 함수 이름이 충돌합니다. 이 글에서는 이를 피하기 위해:
- 실제 메뉴를 만들어 붙이는 코드는
APPT_addSeedMenu_(menu)라는 도우미 함수로 분리하고, - 프로젝트 전체에서는
onOpen을 단 하나만 두고, 그 안에서APPT_addSeedMenu_(menu)를 포함해 각 편의 메뉴 도우미를 모아서 호출하는 방식을 권장합니다.
아래에서 onOpen 코드를 보여 드릴 때, 이미 1편에서 onOpen을 만들어 둔 독자는 함수 선언부를 새로 추가하지 말고, 본문에서 APPT_addSeedMenu_(menu); 한 줄만 합쳐 주시면 됩니다. 글 마지막에 “두 글의 onOpen을 합치는 법”을 한 문단으로 다시 정리합니다.
구글시트로 도크 도어·야드 슬롯을 관리해야 하는 이유
실제 물류센터에서 입고 예약을 운영하다 보면, 도크 도어와 야드 슬롯 정보가 엑셀 파일, 종이, 담당자 머릿속에 따로따로 있는 경우가 많습니다. 이 상태에서는 예약을 시스템으로 옮겨도 현장과 데이터가 어긋나기 쉽습니다. 구글시트 한 곳에 정리해 두어야 예약 자동화가 안정적으로 돌아갑니다.
첫째, 도크 도어와 야드 슬롯이 표 형태로 정리되어 있어야 합니다. 도어 번호, 설명(위치, 특이사항 등), 사용 여부 정도를 기본 컬럼으로 두면 대부분의 입고 예약 운영에 충분히 대응할 수 있습니다. 불필요한 컬럼을 늘리기보다 실제로 쓰는 정보부터 최소한으로 맞추는 편이 유지보수에 유리합니다.
둘째, 번호 규칙을 처음부터 고정하는 것이 중요합니다. 예를 들어 D01~D30, Y01~Y50처럼 자리수를 두 자리로 고정해 두면 정렬·필터·피벗 리포트에서 순서가 꼬이지 않습니다. 현장에서는 D1, D2, D10처럼 섞인 상태로 시작해 나중에 다시 손으로 고치는 일이 자주 발생합니다. 코드로 자동 생성하면 이런 패턴을 한 번에 통일할 수 있습니다.
셋째, 사용 여부를 시트에서 바로 조정할 수 있어야 합니다. 특정 도어가 공사 중이거나, 특정 야드 슬롯을 장기 보세용으로 빼 놓을 때 ACTIVE 값을 FALSE로만 바꾸면 됩니다. 이후 예약 로직은 이 값을 기준으로 사용 중인 슬롯만 불러오도록 만들 수 있습니다. 이번 글의 listActiveDoors_()와 listActiveYardSlots_() 함수는 이 역할을 담당하며, ACTIVE 열이 체크박스가 아니라 TRUE/FALSE 텍스트로 입력되어 있어도 처리할 수 있게 설계합니다.
이렇게 구글시트에 도어·야드 정보를 올려 두면, 추후 예약 화면, 대시보드, 자동 알림 등 다른 기능에서 동일한 마스터 데이터를 재사용할 수 있습니다. 이미 운영 중인 창고라도 지금부터 구조를 잡아 두면, 향후 WMS·TMS와 연동할 때도 전환 비용을 줄일 수 있습니다.
APPT 전용 상수로 시트 구조 정의하기
이번 시리즈의 Apps Script 코드는 결국 하나의 프로젝트 안에 합쳐집니다. 그래서 상수와 함수 이름이 서로 부딪치지 않도록 APPT_ 접두어를 붙여 관리합니다. 앞 편에서 만든 공용 함수(getOrCreateSheet_() 등)는 그대로 사용한다고 가정하고, 이 글에서는 도크 도어·야드 슬롯 시트에 필요한 상수만 정의합니다.
이 상수들은 구글시트 입고 예약 시스템 만들기에서 반복해서 참조하는 값입니다. 시트 이름이나 헤더가 바뀌더라도 상수 정의만 한 번 수정하면 되기 때문에, 실제 운영 환경에서 구조 변경이 있을 때 대응이 수월해집니다.
1) 이 코드는 도크 도어·야드 슬롯 시트 이름과 헤더 정의를 모아 둡니다.
2) 붙여넣는 위치: 구글시트 → 확장 프로그램 → Apps Script → Code.gs 상단, 다른 설정 모음과 함께 둡니다.
3) 붙여넣은 뒤 할 일: 저장(⌘S 또는 Ctrl+S)만 하면 됩니다.
const APPT_SHEET_NAME_DOORS = 'DOORS'; // → 도크 도어 시트 이름
const APPT_SHEET_NAME_YARD = 'YARD'; // → 야드 슬롯 시트 이름
const APPT_DOOR_HEADERS = [ // → 도크 도어 헤더 목록
'DOOR_ID', // → 도어 코드 (D01 등)
'DESCRIPTION', // → 설명·위치 메모
'ACTIVE' // → 사용 여부
];
const APPT_YARD_HEADERS = [ // → 야드 슬롯 헤더 목록
'YARD_ID', // → 야드 코드 (Y01 등)
'DESCRIPTION', // → 설명·위치 메모
'ACTIVE' // → 사용 여부
];동작 확인 방법: 아직 함수는 만들지 않았기 때문에 화면에는 변동이 없습니다. 스크립트가 오류 없이 저장되면 다음 단계로 진행하면 됩니다.
도크 도어 30개 자동 생성: APPT_seedDockDoors30
이제 D01~D30까지 도크 도어 30개를 한 번에 생성하는 Apps Script 함수를 만듭니다. 이 함수는 DOORS 시트를 만들고, 항상 동일한 구조로 초기화한 다음 ID와 ACTIVE 값을 채웁니다. 이미 데이터가 있어도 clearContents()와 clearFormats()로 모두 지운 뒤 다시 쓰기 때문에, 기존 설명이나 ACTIVE 값은 덮어쓰게 됩니다. 실무에서는 이 점을 알고 재실행 여부를 결정해야 합니다.
또한, 시트를 크게 수정하는 함수이기 때문에 LockService로 잠금을 걸어, 여러 사용자가 동시에 메뉴 버튼을 눌러도 충돌 없이 순서대로 처리되도록 합니다. 잠금은 중복 실행을 막는 것이 아니라 동시에 실행되는 것을 직렬 처리로 바꾼다는 점을 염두에 두면 됩니다.
1) 이 코드는 DOORS 시트를 생성·초기화하고 D01~D30과 ACTIVE=true를 입력합니다.
2) 붙여넣는 위치: Apps Script 편집기 → Code.gs → 위에서 정의한 상수 아래쪽.
3) 붙여넣은 뒤 할 일: 저장 후, 함수 목록에서 APPT_seedDockDoors30 선택 → 실행 → 최초 1회 권한 허용.
function APPT_seedDockDoors30() { // → 도어 30개 생성
const lock = LockService.getScriptLock(); // → 스크립트 잠금
lock.waitLock(30000); // → 최대 30초 대기
try { // → 오류 대비
const ss = SpreadsheetApp.getActive(); // → 현재 스프레드시트
const sheet = getOrCreateSheet_( // → 시트 없으면 생성
ss,
APPT_SHEET_NAME_DOORS, // → DOORS 시트 이름
APPT_DOOR_HEADERS // → 헤더 행 정의
);
sheet.clearContents(); // → 내용 전체 초기화
sheet.clearFormats(); // → 서식 초기화
sheet.getRange(1, 1, 1, APPT_DOOR_HEADERS.length) // → 1행 헤더 범위
.setValues([APPT_DOOR_HEADERS]); // → 헤더 쓰기
const rowCount = 30; // → 도어 개수 30개
const data = []; // → 데이터 배열 준비
for (let i = 1; i <= rowCount; i++) { // → 1~30 반복
const id = 'D' + String(i).padStart(2, '0'); // → D01 형식 코드
data.push([id, '', true]); // → ID·설명·사용여부
}
sheet.getRange(2, 1, data.length, data[0].length) // → 데이터 영역
.setValues(data); // → 데이터 쓰기
sheet.autoResizeColumns(1, APPT_DOOR_HEADERS.length);// → 열 너비 자동
} finally { // → 예외 여부와 무관
lock.releaseLock(); // → 잠금 해제
}
}동작 확인 방법: 구글시트로 돌아와 DOORS 시트가 생성되었는지 확인합니다. 1행에 DOOR_ID / DESCRIPTION / ACTIVE가 보이고, 2행부터 31행까지 D01~D30이 채워져 있으며 ACTIVE 열이 모두 TRUE이면 정상입니다. 나중에 도어를 임시로 빼고 싶다면 해당 행의 ACTIVE 값을 FALSE로만 바꾸면 됩니다.
야드 슬롯 50개 자동 입력: APPT_seedYardSlots50
다음으로 Y01~Y50까지 야드 슬롯 50개를 자동 생성하는 함수를 만듭니다. 패턴은 도어와 동일하며, 시트 이름과 헤더 상수만 다르게 사용합니다. 이 함수도 기존 YARD 시트 내용을 모두 지우고 새로 채우는 방식이므로, 이미 입력해 둔 설명이나 ACTIVE 값이 있다면 재실행 전에 백업 여부를 한 번 검토하는 것이 좋습니다.
1) 이 코드는 YARD 시트를 생성·초기화하고 Y01~Y50과 ACTIVE=true를 입력합니다.
2) 붙여넣는 위치: Apps Script 편집기 → Code.gs → APPT_seedDockDoors30 바로 아래.
3) 붙여넣은 뒤 할 일: 저장 후, 함수 목록에서 APPT_seedYardSlots50을 선택해 실행합니다.
function APPT_seedYardSlots50() { // → 야드 50개 생성
const lock = LockService.getScriptLock(); // → 스크립트 잠금
lock.waitLock(30000); // → 최대 30초 대기
try { // → 오류 대비
const ss = SpreadsheetApp.getActive(); // → 현재 스프레드시트
const sheet = getOrCreateSheet_( // → 시트 없으면 생성
ss,
APPT_SHEET_NAME_YARD, // → YARD 시트 이름
APPT_YARD_HEADERS // → 헤더 행 정의
);
sheet.clearContents(); // → 내용 전체 초기화
sheet.clearFormats(); // → 서식 초기화
sheet.getRange(1, 1, 1, APPT_YARD_HEADERS.length) // → 1행 헤더 범위
.setValues([APPT_YARD_HEADERS]); // → 헤더 쓰기
const rowCount = 50; // → 야드 개수 50개
const data = []; // → 데이터 배열 준비
for (let i = 1; i <= rowCount; i++) { // → 1~50 반복
const id = 'Y' + String(i).padStart(2, '0'); // → Y01 형식 코드
data.push([id, '', true]); // → ID·설명·사용여부
}
sheet.getRange(2, 1, data.length, data[0].length) // → 데이터 영역
.setValues(data); // → 데이터 쓰기
sheet.autoResizeColumns(1, APPT_YARD_HEADERS.length);// → 열 너비 자동
} finally { // → 예외 여부와 무관
lock.releaseLock(); // → 잠금 해제
}
}동작 확인 방법: 스프레드시트에 YARD 시트가 생겼는지 확인합니다. 1행에 YARD_ID / DESCRIPTION / ACTIVE가 보이고, 2행부터 51행까지 Y01~Y50이 채워져 있으며 ACTIVE 열이 TRUE이면 성공입니다. 이후 특정 슬롯을 잠시 제외하려면 ACTIVE를 FALSE로만 조정하면 됩니다.
‘사용 중’ 도어만 읽기: listActiveDoors_와 테스트 함수
도어·야드 목록을 시드로 만들어 두었다면, 이제 예약 로직에서 실제로 사용할 수 있는 목록을 읽어 오는 단계가 필요합니다. 실무에서는 공사·고장·장기 보세 등으로 특정 도어를 빼야 하는 일이 빈번합니다. 이때 시트에서 ACTIVE만 바꾸고, 코드에서는 “ACTIVE인 행만 가져온다”는 규칙을 두면 운영이 단순해집니다.
listActiveDoors_()는 DOORS 시트에서 ACTIVE 값을 읽어 TRUE로 판단되는 도어 ID만 배열로 반환하는 유틸리티 함수입니다. ACTIVE 열은 체크박스로 TRUE/FALSE가 들어갈 수도 있고, 텍스트로 'TRUE'라고 적혀 있을 수도 있으므로, 둘 다 처리할 수 있도록 값을 정규화합니다. 이 함수 자체는 외부 메뉴에서 직접 실행하지 않고, 테스트용으로 APPT_testListActiveDoors를 별도로 만들어 로그에서 결과를 확인합니다.
1) 이 코드는 DOORS 시트에서 ACTIVE가 TRUE인 도어 ID 목록을 배열로 반환합니다.
2) 붙여넣는 위치: Apps Script 편집기 → Code.gs → 두 개의 seed 함수 아래.
3) 붙여넣은 뒤 할 일: 저장 후, APPT_testListActiveDoors를 실행하고 실행 로그를 확인합니다.
function listActiveDoors_() { // → 사용 도어 목록
const ss = SpreadsheetApp.getActive(); // → 현재 스프레드시트
const sheet = ss.getSheetByName(APPT_SHEET_NAME_DOORS);// → DOORS 시트 찾기
if (!sheet) { // → 시트 없을 때
throw new Error('DOORS 시트가 없습니다.'); // → 오류 알림
}
const lastRow = sheet.getLastRow(); // → 마지막 행 번호
if (lastRow < 2) { // → 데이터 없음
return []; // → 빈 배열 반환
}
const range = sheet.getRange(2, 1, lastRow - 1, 3); // → ID~ACTIVE 범위
const values = range.getValues(); // → 값 읽기
const activeIds = []; // → 결과 배열
for (let i = 0; i < values.length; i++) { // → 행 반복
const row = values[i]; // → 현재 행
const id = row[0]; // → DOOR_ID
const active = row[2]; // → ACTIVE 값
if (!id) { // → ID 없으면
continue; // → 건너뛰기
}
const normalized = (typeof active === 'boolean') // → 불리언 여부
? active // → 그대로 사용
: String(active).toUpperCase() === 'TRUE'; // → TRUE 문자 처리
if (normalized) { // → 사용 중인 경우
activeIds.push(id); // → ID 추가
}
}
return activeIds; // → 사용 도어 목록
}
function APPT_testListActiveDoors() { // → 테스트용 함수
const doors = listActiveDoors_(); // → 사용 도어 조회
Logger.log(JSON.stringify(doors)); // → 결과 로그 출력
}동작 확인 방법: Apps Script 편집기 상단에서 함수 목록에서 APPT_testListActiveDoors를 선택해 실행합니다. 실행 후 상단 메뉴에서 실행 로그를 열었을 때 ["D01","D02",...,"D30"]처럼 배열이 보이면 정상입니다. DOORS 시트에서 특정 행의 ACTIVE를 FALSE로 바꾸거나 'TRUE'/'true' 텍스트로 입력한 뒤 다시 실행하면, TRUE로 해석되는 도어만 결과에 포함되는지 확인할 수 있습니다.
‘사용 중’ 야드 슬롯 읽기: listActiveYardSlots_와 테스트
야드 슬롯도 도어와 동일한 방식으로 관리합니다. listActiveYardSlots_()는 YARD 시트에서 ACTIVE가 TRUE로 판단되는 행만 골라 YARD_ID를 배열로 반환합니다. 추후에는 이 결과를 바탕으로 구글시트 야드 슬롯 자동 입력 후 예약 화면에서 드롭다운, 자동 배정 로직 등에 활용할 수 있습니다.
1) 이 코드는 YARD 시트에서 ACTIVE가 TRUE인 야드 ID 목록을 배열로 반환합니다.
2) 붙여넣는 위치: Apps Script 편집기 → Code.gs → listActiveDoors_() 아래.
3) 붙여넣은 뒤 할 일: 저장 후, APPT_testListActiveYardSlots를 실행하고 실행 로그를 확인합니다.
function listActiveYardSlots_() { // → 사용 야드 목록
const ss = SpreadsheetApp.getActive(); // → 현재 스프레드시트
const sheet = ss.getSheetByName(APPT_SHEET_NAME_YARD); // → YARD 시트 찾기
if (!sheet) { // → 시트 없을 때
throw new Error('YARD 시트가 없습니다.'); // → 오류 알림
}
const lastRow = sheet.getLastRow(); // → 마지막 행 번호
if (lastRow < 2) { // → 데이터 없음
return []; // → 빈 배열 반환
}
const range = sheet.getRange(2, 1, lastRow - 1, 3); // → ID~ACTIVE 범위
const values = range.getValues(); // → 값 읽기
const activeIds = []; // → 결과 배열
for (let i = 0; i < values.length; i++) { // → 행 반복
const row = values[i]; // → 현재 행
const id = row[0]; // → YARD_ID
const active = row[2]; // → ACTIVE 값
if (!id) { // → ID 없으면
continue; // → 건너뛰기
}
const normalized = (typeof active === 'boolean') // → 불리언 여부
? active // → 그대로 사용
: String(active).toUpperCase() === 'TRUE'; // → TRUE 문자 처리
if (normalized) { // → 사용 중인 경우
activeIds.push(id); // → ID 추가
}
}
return activeIds; // → 사용 야드 목록
}
function APPT_testListActiveYardSlots() { // → 테스트용 함수
const slots = listActiveYardSlots_(); // → 사용 야드 조회
Logger.log(JSON.stringify(slots)); // → 결과 로그 출력
}동작 확인 방법: 함수 목록에서 APPT_testListActiveYardSlots를 실행한 뒤 실행 로그를 열면, ["Y01","Y02",...,"Y50"] 형태의 배열이 보여야 합니다. YARD 시트에서 ACTIVE를 FALSE로 바꾸거나 'TRUE' 텍스트로 입력해 본 뒤 다시 실행해, 활성·비활성 구분이 원하는 대로 적용되는지 확인합니다.
메뉴에서 버튼 한 번으로 실행하기
onOpen 공용 메뉴 + APPT_addSeedMenu_ 도우미로 분리하기
실무에서는 스크립트 편집기에 들어가 함수 이름을 고르는 방식보다는, 시트를 열었을 때 상단 메뉴에서 버튼을 클릭해 실행하는 방식이 훨씬 자연스럽습니다. 이번 글에서는 입고 예약 시리즈 전체에서 공용으로 쓸 메뉴 이름을 ‘예약 도구’로 정하고, 이 편에서는 도크 도어·야드 슬롯 자동 생성 메뉴를 추가합니다.
여기서 한 가지 주의해야 할 점이 있습니다.
- 1편 글에서도
onOpen이 이미 정의되어 있고 - 이번 글에서도 그대로
onOpen을 또 선언하면
두 파일을 한 Apps Script 프로젝트에 넣었을 때 onOpen이 중복 정의 충돌을 일으킵니다.
이를 피하기 위해 이 글에서는 다음 구조를 사용합니다.
- 공용
onOpen함수는 프로젝트 전체에 딱 한 번만 만든다. - 각 글(모듈)에서는 직접
onOpen을 만들지 않고,
APPT_addSeedMenu_(menu) 같은 “메뉴를 추가하는 도우미 함수”만 제공한다.
- 최종적으로 공용
onOpen안에서
APPT_addSeedMenu_(menu); 를 포함해 시리즈별 APPT_add○○Menu_(menu); 를 차례로 호출한다.
이미 1편에서 onOpen을 만들어 둔 경우라면, 아래 onOpen 전체를 복붙하지 말고 1편의 onOpen 안에 APPT_addSeedMenu_(menu); 한 줄만 추가해 주면 됩니다. 만약 아직 onOpen이 하나도 없는 상태라면, 아래 코드를 그대로 사용해도 됩니다.
1) 이 코드는 시트를 열 때 상단에 ‘예약 도구’ 메뉴를 만들고, 도크 도어·야드 슬롯 자동 생성 항목을 추가합니다.
2) 붙여넣는 위치: Apps Script 편집기 → Code.gs
- 공용
onOpen이 이미 있다면:APPT_addSeedMenu_(menu)함수만 추가하고, 기존onOpen본문에서APPT_addSeedMenu_(menu);를 호출 - 공용
onOpen이 없다면: 아래onOpen+APPT_addSeedMenu_(menu)를 함께 추가
3) 붙여넣은 뒤 할 일: 저장 후 시트를 새로고침해 메뉴가 나타나는지 확인합니다.
// 공용 onOpen 예시 (프로젝트에 딱 1개만 존재해야 함):
function onOpen() { // → 시트 열릴 때 실행
const ui = SpreadsheetApp.getUi(); // → UI 객체
const menu = ui.createMenu('예약 도구'); // → 예약 도구 메뉴
// 시리즈별 서브 메뉴 도우미 호출
// 예: 1편에서 정의한 공용 메뉴 도우미가 있다면 여기에 함께 호출
// APPT_addCommonMenu_(menu); // ← 1편에서 쓴 이름 예시 (실제 이름에 맞게 사용)
APPT_addSeedMenu_(menu); // → 이 편 메뉴 추가
menu.addToUi(); // → 메뉴 표시
}
// 이 글(도어·야드 시드) 전용 메뉴 도우미
function APPT_addSeedMenu_(menu) { // → 생성 메뉴 정의
menu.addItem('도어30개 생성', 'APPT_seedDockDoors30'); // → 도어 생성
menu.addItem('야드50개 생성', 'APPT_seedYardSlots50'); // → 야드 생성
}1편 코드와 onOpen을 합치는 방법 요약
- 1편 파일 안에 이미
function onOpen() { ... }가 있다면,
2편(이 글)의 onOpen 선언은 추가하지 않고 삭제하고,
APPT_addSeedMenu_(menu) 함수만 아래쪽에 붙여 넣습니다.
- 그런 다음 1편의
onOpen함수 본문에서 메뉴를 만드는 부분에 있는menu객체에 대해
APPT_addSeedMenu_(menu); 한 줄을 추가합니다.
- 구조 예시:
function onOpen() {
const ui = SpreadsheetApp.getUi();
const menu = ui.createMenu('예약 도구');
APPT_addCommonMenu_(menu); // 1편에서 쓰던 공용 메뉴들
APPT_addSeedMenu_(menu); // 2편(이 글)의 도어·야드 시드 메뉴 추가
menu.addToUi();
}이렇게 하면 같은 프로젝트에 여러 파일을 넣어도 onOpen이 중복 선언되지 않고, 시리즈별 기능이 한 메뉴 안에 자연스럽게 합쳐집니다.
동작 확인 방법: 시트를 새로고침했을 때 상단에 ‘예약 도구’ 메뉴가 생기고, 그 안에 ‘도어30개 생성’과 ‘야드50개 생성’ 항목이 보이면 성공입니다. 메뉴를 눌렀을 때 DOORS·YARD 시트가 새로 생성되거나 기존 내용이 초기화되면서 목록이 다시 채워지는지 함께 확인합니다.
실무 팁: 재시드·동시 실행·오류를 안전하게 다루는 방법
실제 창고 운영에서 이런 스크립트를 사용하다 보면, 의도치 않은 재실행이나 동시 실행으로 인한 문제가 생길 수 있습니다. 몇 가지 주의점을 정리해 두면, 도입 단계에서 불필요한 혼란을 줄일 수 있습니다.
첫째, 재시드 시 기존 설명·ACTIVE 값이 초기화된다는 점을 명확히 인지해야 합니다.
APPT_seedDockDoors30과 APPT_seedYardSlots50는 clearContents()로 시트 전체 내용을 지우고 다시 쓰기 때문에, 현장에서 ACTIVE를 FALSE로 바꿔 둔 도어·야드, DESCRIPTION에 적어 둔 메모가 모두 사라집니다. 숫자만 다시 맞추고 싶을 때도 영향 범위를 고려해 실행해야 합니다. 중요한 메모가 있다면 재시드 전에 다른 시트로 복사해 두는 것이 안전합니다.
둘째, 동시에 두 사람이 메뉴를 눌러도 데이터가 깨지지 않도록 잠금을 사용하는 것이 좋습니다.
이번 코드에는 LockService.getScriptLock().waitLock(30000)을 넣어 두었습니다. 덕분에 두 사람이 거의 같은 시점에 도어 생성 메뉴를 눌러도 한 번씩 순서대로 실행됩니다. 다만 두 번째 실행도 같은 내용을 다시 채우는 것이지, 시드 자체를 막는 것은 아니라는 점을 이해하고 사용해야 합니다.
셋째, ACTIVE 값을 체크박스든 텍스트든 일관되게 TRUE/FALSE 기준으로 관리하는 편이 좋습니다.
이번 예제에서는 기본값으로 true를 입력하고, 읽을 때는 불리언 값 또는 'TRUE' 텍스트를 모두 TRUE로 인정하는 방식입니다. 실무에서는 체크박스를 선호하는 경우가 많지만, 기존 데이터에 이미 텍스트가 섞여 있다면 점진적으로 체크박스로 바꾸면서도 코드가 둘 다 처리할 수 있도록 유지하는 전략이 현실적입니다.
넷째, 오류 메시지를 활용해 초기 세팅 상태를 점검할 수 있습니다.
예를 들어 DOORS 또는 YARD 시트가 없는 상태에서 APPT_testListActiveDoors나 APPT_testListActiveYardSlots를 실행하면, 코드가 명시적으로 에러를 던지도록 되어 있습니다. 이 경우에는 먼저 seed 함수를 실행해 시트를 만든 뒤 다시 테스트하면 됩니다. Apps Script 사용 경험이 적은 운영자에게는, 이런 테스트 함수를 통해 “현재 어떤 시점까지 세팅이 된 상태인지”를 눈으로 보여 주는 것이 도입에 큰 도움이 됩니다.
Apps Script와 LockService, 오류 처리에 익숙해지면 이후 예약 본문 저장, 이력 보관, 자동 백업 같은 기능도 같은 패턴으로 확장할 수 있습니다. 관련 개념은 구글시트 Apps Script 오류 처리 백업 방법 | LockService·try/catch·DriveApp 백업 같은 글과 함께 보시면 이해에 도움이 됩니다.
맺음말
이 글에서는 구글시트에서 도크 도어 30개와 야드 슬롯 50개를 Apps Script로 한 번에 생성하는 방법과, 이후 예약 로직에서 활용할 수 있는 ‘사용 중’ 도어·야드 슬롯만 읽어 오는 함수와 테스트 방법까지 정리했습니다. 수십 개의 도어·슬롯을 손으로 입력하던 작업을 버튼 한 번으로 끝내면, 초기 구축뿐 아니라 레이아웃 변경 이후 재정비 작업도 짧은 시간 안에 처리할 수 있습니다.
특히 이번 편에서 onOpen을 공용 메뉴 함수와 APPT_addSeedMenu_(menu) 도우미로 분리해 둔 덕분에, 앞선 1편 코드와 한 프로젝트 안에서 합쳐도 이름 충돌 없이 확장할 수 있습니다. 공용 onOpen은 프로젝트에 하나만 두고, 시리즈별로 APPT_add○○Menu_(menu)를 추가 호출하는 패턴을 유지하면, 이후 3편·4편으로 기능을 늘려 갈 때도 구조가 깔끔하게 유지됩니다.
지금 바로 할 수 있는 행동은 한 가지입니다. 현재 사용 중인 입고 예약 구글시트를 열어, 이 글의 APPT_seedDockDoors30과 APPT_seedYardSlots50 코드를 붙여 넣고 메뉴에서 실행해 보시기 바랍니다. DOORS·YARD 시트가 자동으로 채워지는 것을 한 번 경험해 두면, 이후 예약 화면과 자동 배정 로직을 설계할 때 훨씬 안정된 기반 위에서 작업을 이어갈 수 있습니다. 다음 편에서는 이렇게 준비한 도어·야드 목록을 이용해, 예약 입력 시 도어·야드를 자동으로 선택·검증하는 로직을 추가하는 방법을 다루겠습니다.