# [Claude Code] 종이 점검확인서 242건, 스마트폰 서명 웹앱으로 바꿨다
## 📝 한줄 요약
공공기관에 납품한 공기청정기의 현장 점검·서명 확인서를 종이로 받던 방식을, Claude Code로 스마트폰 웹폼 하나 만들어서 구글시트 자동 기록으로 바꿨다.
바쁘시면 이것만 읽어도 돼요:
- Claude Code로 "현장 기사가 폰으로 체크하고 손글씨 서명하면 구글시트에 바로 쌓이는 웹앱"을 만듦
- 처음엔 환경변수 이름 하나 안 맞아서 배포가 계속 실패 — "그럴듯한 이름"이 아니라 코드가 실제로 요구하는 이름을 다시 확인해야 했음
- 서비스 계정을 실수로 지워서 다시 만드는 해프닝도 있었음
- 진짜 막힌 지점은 "개인 구글 계정으로 만든 서비스 계정은 드라이브 저장 용량이 없다"는 것 — 구글 워크스페이스가 있어야만 되는 구조였음
- 구글드라이브 대신 Vercel Blob Storage로 통째로 아키텍처를 바꿔서 해결
- 막히는 지점마다 "왜 안 되지"에서 멈추지 않고 원인을 하나씩 캐물어서 근본 구조 문제(계정 종류)까지 찾아낸 게 핵심
## 🎯 이런 분들께 도움돼요
- 공공기관·대기업에 납품하면서 현장 점검확인서, 검수서 같은 종이 서류를 매번 취합·보관해야 하는 담당자
- 개발자가 아니지만 Claude Code로 사내 업무용 웹앱을 직접 만들어보고 싶은 분
- 구글시트 연동, 전자서명 같은 기능이 필요한데 어디서부터 시작해야 할지 막막한 분
- Vercel 배포 중 환경변수 오류로 시간을 날려본 적 있는 분
## 😫 문제 상황 (Before)
공공기관에 설치된 공기청정기의 정기 점검·필터 교체를 결과를 확인서로 남겨 공공기관에 제출한다. 이 확인서는 순번·날짜·점검자·관리번호·본부·사업소··운용장소·기기상태 같은 항목에, 담당자의 직책·이름·서명까지 받는 표 형식 문서다.
이걸 종이로 돌리면 현장 기사가 손으로 적고 서명을 받은 뒤, 그 종이를 다시 모아서 정리하고 보관해야 한다. 항목이 200건대로 많다 보니 취합 과정 자체가 부담이고, 원본 종이를 분실하거나 서명을 놓치는 리스크도 있다. 이 반복 작업을 웹으로 옮기면 현장에서 바로 입력하고 서명까지 받아 기록이 즉시 시트에 쌓이니, 더 미룰 이유가 없었다.
## 🛠️ 사용한 도구
- 도구: Claude Code (초기 스캐폴딩·삽질 구간), Claude Desktop Cowork (이후 로컬 파일 편집·터미널 작업)
- 연동 서비스: Google Sheets API, Google Cloud 서비스 계정, Vercel(배포), Vercel Blob Storage(이미지 저장)
- 특이사항: GitHub 연동 없이 Vercel에 수동 업로드하는 방식으로 배포
---
## 🔧 작업 과정
### 종이 확인서를 웹앱 하나로 — "smrt-inspection" 첫 설계
시작은 단순했다. 점검자가 날짜·직책·이름을 입력하고 서명을 남기면, 그 정보가 자동으로 구글시트에 기록되는 폼이 필요했다. 서명은 이미지로 받아야 하니 한 건당 날짜·직책·이름·서명, 이렇게 이미지 4장이 함께 붙는 구조로 설계했다.
Claude Code로 프로젝트를 스캐폴딩하면서 스프레드시트와 연결할 전용 구글 서비스 계정을 발급받아 Google Sheets API·Drive API를 연결했다. 시트에는 이미지를 파일 그대로 넣는 대신 이미지 미리보기 수식(=IMAGE(url))으로 뜨도록 만들어서, 담당자가 시트만 열어도 서명이 제대로 들어왔는지 바로 확인할 수 있게 했다.
여기까지는 순조로웠다. 문제는 이걸 실제로 배포하면서부터 시작됐다.
---
### 배포하자마자 막힘 — 환경변수 이름 하나가 전부를 틀어막다
Vercel에 올리고 나니 서비스가 스프레드시트를 못 찾고, 인증도 계속 실패했다. 처음엔 "환경변수를 빼먹었나" 싶어서 이것저것 다시 채워봤지만 그래도 안 됐다.
원인은 이름이었다. 실제 코드가 요구하는 환경변수명은 서비스 계정 인증정보 전체를 담는 값, 스프레드 시트 ID, 드라이브 폴더 ID, 접속용 비밀번호(PIN) 이렇게 네 가지였는데, 처음 설정할 때 이와 다른 이름으로 넣어뒀던 것이다. "그럴듯한 이름"이 아니라 코드 안에서 실제로 참조하는 변수명을 한 글자씩 맞춰야 한다는 걸 이 과정에서 다시 확인했다.
이름을 맞췄더니 이번엔 JSON 파싱 에러가 났다. 서비스 계정 키 JSON을 예쁘게 줄바꿈된 상태로 붙여넣었더니 Vercel이 이를 제대로 읽지 못한 것이다. 원인을 물어보니 Vercel 환경변수에 JSON을 넣을 때는 줄바꿈 없이 한 줄로 압축된 형태여야 한다는 답이 돌아왔고, PowerShell로 JSON 파일을 한 줄로 압축해 클립보드에 바로 복사하는 방법을 알려줬다. 그대로 붙여넣자 인증이 통과됐다.
---
### 서비스 계정을 실수로 지웠다 — 되짚어보니 배운 게 있는 사고
작업 도중 사용하던 서비스 계정을 실수로 삭제하는 일이 있었다. 다행히 큰 문제는 아니었다. 새 서비스 계정을 발급받고 Sheets·Drive API 권한을 다시 연결하는 것으로 복구됐지만, 이 일로 "서비스 계정은 한 번 삭제하면 키를 되살릴 수 없고 무조건 재발급"이라는 걸 몸으로 배웠다.
---
### 진짜 막힌 지점 — "왜 이미지가 안 올라가지?"에서 계정 구조 문제까지
가장 오래 붙잡고 있었던 건 서명 이미지 업로드였다. 인증도 통과했고 코드도 문제없어 보이는데 이미지가 드라이브에 올라가지 않았다. 여기서 "코드를 더 고치면 되겠지"로 넘어가지 않고, 왜 안 되는지를 계속 물고 늘어진 게 방향을 바꿨다.
원인은 코드가 아니라 계정 구조에 있었다. 개인 Gmail 계정 기반으로 만든 구글 클라우드 서비스 계정은 드라이브에 파일을 올릴 저장 용량 자체가 없고, 공유 드라이브를 쓰려 면 구글 워크스페이스 조직이 필요했다. 즉 지금 쓰는 계정 형태로는 애초에 될 수 없는 구조였다.
그래서 이미지 저장소를 구글 드라이브에서 Vercel이 제공하는 별도의 파일 저장 서비스(Vercel Blob Storage)로 통째로 바꾸는 쪽으로 결정했다. 제출 처리 로직에서 이미지를 업로드하는 부분을 이 새 저장 서비스로 연결하고, 더 이상 필요 없어진 구글 드라이브 접근 권한은 제거했다. 대신 새 저장 서비스용 접근 키 하나를 환경변수로 추가했다. 시트에서 서명 이미지가 바로 보이는 방식은 그대로 유지할 수 있어서, 사용자가 보는 결과물은 달라지지 않으면서 내부 구조만 더 안정적인 방식으로 바뀌었다.
이 무렵부터는 Claude Desktop의 Cowork로 넘어와 로컬 파일을 직접 열어 고치고 터미널 작업을 이어갔다.
---
## ✅ 결과 (After)
### Before vs After
| 항목 | Before | After |
|------|--------|-------|
| 점검확인서 작성 방식 | 현장에서 종이에 수기 작성 → 별도 취합 | 스마트폰 웹폼 입력 → 구글시트 자동 기록 |
| 서명 확인 | 종이 원본 보관·재확인 필요 | 시트에서 =IMAGE(url)로 즉시 확인 |
| 이미지 저장소 | (설계 초기) 구글 드라이브 — 개인 계정 용량 문제로 불가 | Vercel Blob Storage |
| 취합·보관 소요 시간 | 확인 필요 (실 운영 데이터로 추후 검증) | 확인 필요 (실 운영 데이터로 추후 검증) |
### 결과물
- 서명 4종(날짜·직책·이름·서명)을 받는 모바일 웹폼
- 제출 즉시 구글시트에 행이 추가되고, 서명 이미지는 시트에서 바로 미리보기로 확인 가능
---
## 💬 이 과정에서 배운 AI 활용 팁
### 효과적이었던 것
1. 에러 메시지 를 그대로 붙여넣고 "왜 안 되는지" 원인을 파고들게 한 것 — 표면적인 코드 수정이 아니라 "개인 계정에는 드라이브 저장 용량이 없다"는 구조적 원인까지 찾아낼 수 있었다
2. 환경변수 문제처럼 "이름이 안 맞는" 종류의 오류는, 추측하지 말고 코드에서 실제로 참조하는 변수명을 그대로 확인하는 습관이 필요했다
3. 아키텍처를 바꿔야 하는 상황(드라이브 → Blob Storage)에서도, 사용자 입장에서 보이는 결과(시트에서 이미지 확인)는 그대로 유지하도록 설계 방향을 잡을 수 있었다
### 이렇게 하면 안 돼요
1. 환경변수 값을 대충 짐작해서 채우고 넘어가기 — 코드가 요구하는 정확한 이름을 확인하지 않으면 원인 파악에 더 오래 걸린다
2. 인증 키(JSON) 같은 민감한 값을 형식 확인 없이 그대로 붙여넣기 — 줄바꿈 형식 때문에 파싱 에러가 날 수 있다
3. 서비스 계정처럼 삭제하면 복구가 안 되는 리소스를 다룰 때 "일단 지우고 다시 만들지" 식으로 접근하기 — 재발급 자체는 가능하지만 연결된 권한을 다시 다 맞춰야 한다
## 🌍 다른 업무에 적용한다면?
현장에서 종이로 받는 확인서·검수서·점검표가 있는 업무라면 구조는 거의 그대로 재사용할 수 있다. 항목(순번·날짜·담당자·상태)을 입력받는 폼 + 서명 이미지 + 구글시트 자동 기록, 이 세 가지 조합이면 대부분의 "현장 확인 후 서명 받는" 업무를 웹으로 옮길 수 있다. 서울교통공사 건 외에 다른 공공기관·거래처 납품 건에도 같은 틀을 붙이면 확인서 관리 방식을 통일할 수 있을 것으로 본다.
## 🚀 앞으로의 계획
- Vercel Blob 연동이 실제 제출 흐름에서 끝까지 정상 동작하는지 최종 검증
- 새 저장 서비스용 접근 키가 Vercel 환경변수에 정확히 반영됐는지 재확인
- 더 이상 쓰지 않는 드라이브 폴더 ID 환경변수 정리
한국사이트 스크린샷