유주영HR Operations · DSRVEN
작업 파일

자기계발비 정합성 감사 도구

HR-04감사완료

구글시트 운영에서 숫자가 서로 맞지 않는 상태를 찾아내는 읽기 전용 감사 도구. 규정 기준 검사 8종으로 동명이인·팀명 불일치·한도 초과를 심각도와 함께 산출. 결과가 웹앱 이관의 근거가 됨.

기간
2026.06
스택
Google Apps Script
대체한 것
검증되지 않던 시트

구글시트로 운영되던 자기계발비 관리에서 숫자가 서로 맞지 않는 상태를 찾아내는 감사 도구. 데이터를 절대 고치지 않고, 문제만 찾아 별도 탭에 적는다. 이 진단이 나중에 사내 웹앱으로 이관하는 근거가 됐다.


1. 한눈에

역할 규정 해석 · 검사 규칙 설계 · 구현 (1인)
기간 2026-06
스택 Google Apps Script · Spreadsheet API
규모 306줄 · 검사 항목 8종 · 심각도 3단계
성격 READ-ONLY — 원본 데이터를 한 셀도 수정하지 않는다
근거 복리후생 운영 규정 제7조 · 지출 규정
후속 여기서 확인한 문제가 사내 웹앱 이관 결정의 근거가 됨

2. 배경 — 무엇이 문제였나

자기계발비는 개인별로 월 한도와 연 한도가 있고, 대상 카테고리가 정해져 있으며, 시용기간이 끝나기 전 결제분은 지원 대상이 아니다. 즉 규정이 꽤 촘촘한 제도다.

그런데 운영은 구글시트로 하고 있었다. 시트 안에는 성격이 다른 표 세 개가 있었다.

  • 멤버 DB — 성명, 입사일, 시용 종료일, 부서, 연간 한도
  • 집행 내역 — 결제일, 성명, 카테고리, 금액, 승인 여부
  • 팀별 한도표 — 팀명, 한도

세 표는 성명과 팀명이라는 문자열로만 연결되어 있었다. 그리고 사람이 매일 손으로 편집하는 문서였다.

그래서 이런 일이 조용히 벌어질 수 있었다.

  • 동명이인이 있으면 집행 내역의 “홍길동”이 누구 것인지 알 수 없다. 두 사람의 사용액이 한 사람에게 합산된다.
  • 부서명이 팀별 한도표와 한 글자라도 다르면 그 사람은 팀 집계에서 통째로 빠진다.
  • 결제일이 날짜로 인식되지 않는 형식으로 들어가면 월별 집계에서 사라진다.
  • 그리고 이 모든 경우에 시트는 아무 말도 하지 않는다. 합계는 여전히 그럴듯한 숫자를 보여준다.

실제로 시트 안에서 두 숫자가 서로 맞지 않는 상태가 방치되어 있었다. 문제는 “틀렸다”가 아니라 “틀렸는지 아무도 알 수 없다” 는 것이었다.


3. 무엇을 만들었나

시트를 열면 커스텀 메뉴가 생기고, 거기서 “정합성 감사 실행”을 누르면 검사 결과가 전용 탭에 쌓인다.

  구글시트 (사람이 매일 편집)
   ├ 멤버 DB
   ├ 집행 내역
   └ 팀별 한도표
          │
          │  ← 읽기만 한다
          ▼
   ┌─────────────────────┐
   │  표 위치 자동 탐지    │  헤더 시그니처로 찾는다
   │  locateTable_()      │  (시트 구조가 바뀌어도 동작)
   └──────────┬──────────┘
              ▼
   ┌─────────────────────┐
   │  검사 8종 실행        │
   │  구조 · 매칭 · 규정   │
   └──────────┬──────────┘
              ▼
   🔍 정합성_감사 탭 ── 심각도 · 영역 · 행 번호 · 설명

검사 항목

심각도 항목 무엇이 위험한가
🔴 동명이인 존재 이름 매칭이 성립하지 않는다 → 고유 ID 필요
🔴 동명이인 이름을 참조한 집행 건 누구의 사용액인지 확정 불가
🔴 월 한도 초과 규정 위반 집행
🔴 연 한도 초과 개인별 연간 한도 우선 적용
🟠 부서 누락 / 팀명 불일치 팀 집계에서 조용히 누락
🟠 알 수 없는 카테고리 규정상 지원 대상 5종을 벗어남
🟠 결제일 날짜 인식 불가 월별 집계에서 사라짐
🟠 시용기간 종료 전 결제 규정상 지원 제외 — 예외 승인 여부 확인 필요
🟡 지급일자 인식 불가 집계에는 영향 없으나 추적 곤란

각 항목은 어느 행에서 발견됐는지와 왜 문제인지를 문장으로 남긴다. “동명이인 2명”이 아니라 “이 이름은 동명이인이라 집행내역을 이름으로만 매칭하면 사용액이 섞일 수 있음” 이라고 쓴다. 감사 결과를 읽는 사람이 곧바로 조치할 수 있어야 하기 때문이다.


4. 설계에서 신경 쓴 세 가지

① 절대 고치지 않는다

이 도구는 원본 데이터를 단 한 셀도 수정하지 않는다. 발견 사항은 전용 리포트 탭에만 쓴다. 파일 첫머리 주석에 그렇게 명시해 뒀다.

이유는 단순하다. 이 시트는 내 것이 아니다. 여러 사람이 매일 편집하는 운영 문서이고, 자동으로 값을 고치는 스크립트가 붙는 순간 아무도 그 시트를 믿을 수 없게 된다. “누가 바꿨는지 모르는 값”이 생기는 것은 지금의 문제(정합성 붕괴)보다 나쁘다.

진단 도구와 수정 도구를 섞지 않았다. 찾는 것과 고치는 것은 다른 일이고, 고치는 판단은 사람이 한다.

② 표 위치를 고정하지 않는다

시트의 표 위치를 좌표로 박아두면, 누군가 행 하나를 삽입하는 순간 스크립트가 엉뚱한 데이터를 읽는다. 그러고도 에러 없이 결과를 낸다.

그래서 표를 헤더 시그니처로 찾는다. 성명·입사일·부서가 한 행에 모두 있으면 그게 멤버 DB고, 결제일·성명·카테고리가 있으면 집행 내역이다. 시트 상단 일부를 훑어 자동으로 찾고, 못 찾으면 그 사실 자체를 🔴 발견 사항으로 기록한다.

컬럼도 마찬가지로 순서가 아니라 헤더 이름의 부분 일치로 찾는다. 사람이 컬럼을 옮기거나 이름을 조금 바꿔도 견딘다. 사람이 편집하는 문서를 읽는 코드는, 문서가 변한다는 전제 위에 서야 한다.

③ 규정 근거를 코드에 붙였다

한도 금액, 대상 카테고리, 시용기간 제외 원칙은 전부 규정에서 온 값이다. 그래서 파일 상단에 근거 조항(복리후생 제7조 / 지출규정)을 적고, 한도와 카테고리를 이름 붙인 상수로 분리했다.

규정이 바뀌면 고칠 곳이 한 군데이고, 왜 그 숫자인지가 코드 안에 있다.


5. 이 도구가 실제로 한 일 — 이관의 근거가 됐다

감사 결과가 보여준 것은 개별 오류가 아니라 구조적 한계였다.

  • 동명이인 문제는 시트에서는 원리적으로 풀 수 없다. 고유 ID가 필요하고, 그건 시트가 아니라 데이터베이스의 일이다.
  • 팀명 문자열 불일치도 같은 성격이다. 참조 무결성이 없는 저장소에서는 계속 발생한다.
  • 날짜 형식 문제 역시 자유 입력 셀에서는 반복된다.

즉 이 도구는 “지금 몇 건이 틀렸는가”를 알려준 동시에, “이 방식으로는 계속 틀릴 것” 을 증명했다.

그래서 다음 단계는 시트를 더 잘 관리하는 것이 아니라, 자기계발비 관리를 사내 웹앱으로 옮기는 것이 됐다. 개인 한도·잔여·사용 내역과 전사 집행률을 다루는 기능이 이후 사내 통합 플랫폼(HR/GA Hub)에 구현됐다.

고치기 전에 먼저 진단했고, 진단이 이관 결정의 근거가 됐다.