프롤로그: "드라이브에 엑셀이 없는데?"

금요일 저녁, 헌금 마감을 막 끝냈다. 차주 시트도 만들었고, 이메일도 보냈고, DB 백업도 완료했다. 완벽한 마감이었다... 적어도 그렇게 생각했다.

"드라이브 0215 폴더에 헌금 집계 엑셀이 없는데?"

아차. 마감 프로세스가 5단계(시트 생성, 폴더 생성, 이메일, DB 백업)를 자동화했지만, 정작 현재 주차 Excel 업로드는 빠져있었다. 수동으로 gdrive.py push 0215를 실행해야 했다.

자동화가 99% 완성되면, 그 1%가 제일 아프다.

Phase 25: 마감 프로세스의 마지막 퍼즐

문제는 간단했다. close_offering.py차주 폴더(0222)는 만들지만, 현재 주차 폴더(0215)에 Excel을 업로드하지 않았다. 논리적으로는 맞다. 차주 준비가 마감의 목적이니까.

하지만 실전에서는? 현재 주차 Excel이 Drive에 없으면 협업이 안 된다.

해결책은 명확했다:

def _upload_excel_to_drive(date_str: str, dry_run: bool = False):
    # 현재 주차 Excel을 현재 주차 폴더에 업로드
    xlsx_path = get_xlsx_path(date_str, BASE_DIR)
    folder_id = _find_or_create_subfolder(service, mmdd)
    upload_file(xlsx_path, folder_id, f"{yyyymmdd}.xlsx")

이제 마감은 6단계가 되었다:

  1. 데이터 검증
  2. Excel 업로드 ← NEW
  3. 차주 시트 생성
  4. 차주 폴더 생성
  5. 이메일 전송
  6. DB 백업

close_offering.py 0215 한 번이면 모든 게 끝난다.

Phase 26-27: 검증의 철학적 전환

다음 문제는 더 미묘했다. 금액 검증(--check-amounts)과 데이터 검증(--check-data)은 옵션이었다. 사용자가 명시적으로 플래그를 붙여야 작동했다.

# 기존
python3 scripts/process_offering.py verify 0215 --table
# 검증 없음

python3 scripts/process_offering.py verify 0215 --table --check-amounts --check-data
# 검증 있음 (하지만 타이핑이 길다)

문제는, 사람은 잊는다. 바쁜 금요일 저녁에 플래그를 붙이는 걸 잊으면? 권분녀 님의 700,000원이 100,000원으로 입력되어도 모른다.

그래서 결정했다: 검증을 기본값으로.

# Phase 26-27
def verify(
    date_str: str,
    check_amounts: bool = True,  # False → True
    check_data: bool = True,      # False → True
):

이제 verify를 실행하면 자동으로:

  • 의심 금액 감지 (1↔7 혼동, 큰 금액)
  • 중복 감지 (동일인이 여러 카테고리)
  • 이상치 감지 (과거 패턴과 다른 금액)
  • 카테고리 추천 (과거 헌금 패턴 기반)

끄고 싶으면? --no-check-amounts --no-check-data를 쓰면 된다.

이게 옵트인(Opt-in)에서 옵트아웃(Opt-out)으로의 전환이다. 안전이 기본이 되어야 한다.

Phase 28: 교육부 헌금이 사라진 날

2월 15일, 11페이지 PDF를 처리했다. 십일조, 감사, 장년부... 다 있다. Excel 생성, 검증 통과. 완벽하다!

잠깐, 교육부 헌금은?

PDF를 다시 열어보니, 페이지 9-11에 어린이부, 중고등부, 청년부 헌금이 따로 있었다. 하지만 처음엔 페이지 1-8만 읽고 끝냈다.

문제의 근본 원인: PDF 전체 페이지 확인 프로세스가 없었다.

해결책:

  1. 명시적 가이드: "PDF X/Y 페이지 모두 읽었는가?"
  2. 체크리스트 도입:
    - [ ] PDF 전체 페이지를 읽었는가?
    - [ ] 십일조 데이터 있는가?
    - [ ] 교육부 헌금 확인했는가? (어린이부/중고등부/청년부)
    
  3. 교육부 헌금 전용 섹션: PDF 후반부(9+)에 위치, 단일 금액 전표 형태

이제 교육부 헌금은 더 이상 숨지 않는다.

Phase 29: 기계가 스스로 배우는 순간

가장 흥미로운 단계가 왔다. 매주 OCR 오인식을 교정하는데, 패턴이 보였다:

  • "고민우" → "고민수" (여러 번)
  • "홍석경" → "홍석정" (여러 번)
  • "고민수.전혜진" → "고민수,권혜진" (여러 번)

수동으로 correction_history.json에 추가하고 있었다. 하지만 생각해보니, 이미 답이 있다:

  • extracted_raw.json: OCR 원본 (오인식 포함)
  • extracted_final.json: 사용자가 수정한 최종본

둘을 비교하면? 사용자가 뭘 교정했는지 자동으로 알 수 있다.

def detect_corrections(raw_data, final_data):
    # 같은 카테고리, 같은 순서로 매칭
    for i in range(len(raw_items)):
        raw_name = raw_items[i]["name"]
        final_name = final_items[i]["name"]

        # 금액은 같고 이름만 다르면 = 교정
        if raw_amount == final_amount and raw_name != final_name:
            corrections[raw_name] = final_name

이제 한 줄이면 된다:

python3 scripts/learn_corrections.py 0215

결과:

📚 학습된 보정 패턴: 3개

단일 이름:
  - 고민우 → 고민수 (✓ 새로 추가)
  - 홍석경 → 홍석정 (✓ 새로 추가)

부부 이름:
  - 고민수.전혜진 → 고민수,권혜진 (✓ 새로 추가)

다음 주에 "고민우"가 또 나오면? 자동으로 "고민수"로 교정된다. 기계가 스스로 배운다.

에필로그: 자동화가 자동화를 낳는다

5단계를 돌아보면 패턴이 보인다:

  1. Phase 25: 수동 단계 발견 → 자동화 추가
  2. Phase 26-27: 옵션 → 기본값 (철학적 전환)
  3. Phase 28: 누락 방지 → 체크리스트 (프로세스 강화)
  4. Phase 29: 반복 작업 → 자동 학습 (메타 자동화)

각 Phase가 이전 Phase의 자동화 위에서 작동한다. 자동화가 자동화를 낳는 연쇄 반응.

최종 결과:

  • 294개 테스트 통과
  • 6단계 마감 프로세스 (1개 명령)
  • 자동 검증 (기본 활성화)
  • 자동 학습 (보정이력)

이제 헌금 처리는:

/process-offering 0215  # 추출 → 교정 → Excel 생성
/close-offering 0215    # 검증 → 업로드 → 마감

2개 명령으로 끝난다.


교훈: 자동화는 한 번에 완성되지 않는다. 매 회차마다 1%씩 개선하다 보면, 어느 순간 기계가 스스로 배우기 시작한다. 그때부터가 진짜 자동화다.

다음 단계: Phase 30-34는 무엇이 될까? 아마도 기계가 스스로 새로운 패턴을 제안하기 시작할 것이다.

"기계가 배우는 게 아니라, 기계가 가르치기 시작할 때가 진짜 AI다."