GAS PropertiesService: 작은 설정 저장소의 범위·검증·복구

English version

TECH INSIGHT / EXPLAINED

설정 몇십 개를 저장하려고 데이터베이스부터 운영할 필요는 없다. PropertiesService는 작은 문자열 상태를 보관하기에 편리하다. 대신 실행 사용자, 입력 형식, 동시 변경과 크기 한도를 저장 함수의 계약으로 정해야 한다.

세 사람이 개인·공용 설정 서랍, 이력 크기와 잠금된 저장 절차를 설명하는 모습
개념을 설명하는 AI 제작 일러스트. 세 사람이 개인·공용 설정 서랍, 이력 크기와 잠금된 저장 절차를 설명하는 모습

실제 프로젝트의 로컬 실행 화면

기존 프로젝트의 화면 또는 함수를 로컬에서 실행해 촬영했습니다. 개인정보 없는 샘플 입력을 사용했으며, 실행한 범위는 각 이미지 아래에 설명했습니다.

기존 GAS 콘솔의 계좌 설정 창을 실제로 열어 샘플 문자열 설정을 표시했다. DEMO-ACCOUNT 등은 예시이고 키·시크릿은 비워 두었다. PropertiesService 저장·권한 검사·잠금 동작은 이 화면에서 실행하거나 검증하지 않았다.
기존 GAS 콘솔의 계좌 설정 창을 실제로 열어 샘플 문자열 설정을 표시했다. DEMO-ACCOUNT 등은 예시이고 키·시크릿은 비워 두었다. PropertiesService 저장·권한 검사·잠금 동작은 이 화면에서 실행하거나 검증하지 않았다.

저장 범위는 실행 주체와 함께 고른다

Script Properties는 해당 스크립트에서 공유하는 값, User Properties는 현재 실행 사용자에 속한 값이다. Document Properties는 문서 문맥에서 사용할 수 있는 범위이며 독립 웹 앱에서 항상 존재하는 저장소가 아니다. 웹 앱을 배포자 권한으로 실행하면 방문자별 User Properties가 자동으로 생긴다고 가정할 수 없다. 설치형 트리거도 생성자의 권한을 따른다.

계좌 식별자는 인증된 서비스 사용자와 연결하고, 공용 설정과 개인 설정을 별도 접근 함수로 구분한다. Script Properties에 승인 상태를 두었다는 이유만으로 권한 검사가 생기지는 않는다. 저장 API에서 허용된 키와 호출자 권한을 검사해야 한다. 별도 Apps Script 라이브러리로 함수를 옮길 때는 라이브러리의 리소스 공유 규칙도 확인한다.

문자열을 숫자로 바꾸기 전에 비어 있는지 본다

문자열 비교에서 "9" > "10"은 참이고 Boolean("false")도 참이다. Number만 쓰면 null이나 빈 문자열이 0으로 바뀌는 문제도 있다. 아래 함수는 예시 설정의 단위를 소수 비율로 고정하고 0.2%~2% 범위만 허용한다. 이 범위는 전략 추천이 아니라 입력 검증 예시다.

function parseGap(raw) {
  if (typeof raw !== 'string' || !/^\d+(\.\d+)?$/.test(raw.trim())) {
    throw new Error('A decimal ratio is required');
  }
  const value = Number(raw.trim());
  if (!Number.isFinite(value) || value < 0.002 || value > 0.02) {
    throw new Error('Allowed range: 0.002 to 0.02');
  }
  return value;
}
console.assert(parseGap('0.002') === 0.002);
console.assert(parseGap('0.02') === 0.02);

ON/OFF도 알 수 없는 값은 거절한다. JSON은 파싱 성공뿐 아니라 배열·필드 형식·schemaVersion을 확인한다. 손상된 저장값을 조용히 기본값으로 바꾸고 거래를 이어가기보다 오류 상태를 표시해 복구한다.

부분 저장과 읽기 응답을 제한한다

setProperties(params, false)는 전달되지 않은 기존 키를 지우지 않는다. 하지만 params를 그대로 받으면 운영자 전용 키까지 덮어쓸 수 있다. 저장 가능한 키를 명시하고 검증된 값으로 새 객체를 만든다. getProperties 전체를 UI로 반환하거나 echo로 시크릿을 되돌려주지 않는다.

입력 필드 이름을 저장 키와 분리하면 화면 문구와 순서를 바꿔도 데이터 마이그레이션을 줄일 수 있다. 예를 들어 settings.v1과 state.lastSuccessAt처럼 역할을 구분하되, 키 이름을 정하는 것만으로 접근 통제가 되지는 않는다.

90개 이력보다 직렬화된 크기가 중요하다

2026년 9월 공식 한도는 값 하나당 9KB, 프로퍼티 저장소당 500KB다. 이는 모든 프로젝트 데이터를 합친 하나의 500KB로 단순화할 수 없다. 90일치 배열도 각 항목이 길면 값 하나 한도를 넘는다. 저장 전에 JSON을 UTF-8 바이트로 측정하고 여유 있는 상한을 둔다.

날짜 키는 계좌와 시간대를 포함한 의미가 명확해야 한다. 같은 날짜의 스냅샷을 교체하고 오래된 항목을 제거하는 방식은 보존 개수가 제한된 목록이다. 장기 이력이나 체결별 감사 기록은 다른 저장소로 내보내고, 삭제·보존 정책을 기록한다.

읽기-수정-쓰기를 하나의 잠금 범위로 묶는다

이력 갱신과 설정 버전 변경은 같은 저장소를 다루는 모든 경로가 같은 LockService 규칙을 따라야 한다. 잠금 실패를 성공 저장처럼 표시하지 않는다. 여러 값을 setProperties로 모아 쓴다고 데이터베이스의 트랜잭션 보장이 생기는 것은 아니다. 상태 버전과 마지막 정상값을 남겨 중간 실패에서 복구할 수 있게 한다.

한 번 읽어 실행 안에서 재사용하면 불필요한 서비스 호출을 줄일 수 있지만 묶음 호출을 할당량 우회로 가정하지 않는다. CacheService에는 없어져도 다시 만들 수 있는 값만 둔다. 이메일 해시는 익명화 보장이 아니며 전체 속성 덤프는 로그에 남기지 않는다. 크기·조회·동시성 요구가 커지면 저장소 인터페이스를 유지하면서 DB로 옮길 시점을 판단한다.

저장 성공과 실행 상태를 구분하는 초보자 UI

참고 자료

내용·예제 검토: 2026-09-29

댓글