소개
우리 공장(나주공장)은 코팅현황, 생산계획 대비 실적, 히터코일/메시 출하현황, 진공증착(VM) 생산실적 같은 핵심 데이터를 전부 엑셀 파일로 관리하고 있었어요. 현장에서 매일 엑셀을 갱신하긴 하지만, 그 숫자를 그래프로 보거나 추이를 확인하려면 매번 엑셀을 열어서 피벗테이블을 만들어 야 했고, 여러 사람이 최신 파일을 어디서 받아야 하는지도 헷갈렸어요.
그래서 코딩을 전혀 몰라도 Claude Code에게 자연어로 요청만 하면서, 이 엑셀 데이터를 실시간으로 보여주는 웹 대시보드(naju.kbmtt.com)를 만들어보기로 했어요. 목표는 세 가지였어요:
회사 서버 공유폴더에 있는 엑셀 파일을 사람이 손대지 않아도 자동으로 웹 대시보드에 반영되게 하기
코팅/생산계획/출하/진공증착 데이터를 각각 한눈에 보는 그래프로 만들기
로그인/관리자 승인 등 최소한의 보안은 갖추기
Next.js + Supabase(데이터베이스·로그인) + Vercel(배포)로 만들었고, 2026-07-25에 시작해서 지금까지 약 12일간 65개의 커밋을 거쳐 발전해왔어요. 처음엔 "기능을 만드는" 단계였는데, 최근에는 "실제로 안전하고 안정적으로 돌아가게 다듬는" 단계로 넘어갔어요.
건물과 자동차 이미지가 포함된 웹사이트의 스크린샷
한국어 메뉴 스크린샷
Microsoft Power BI 대시보드 스크린샷
한국어 텍스트가 있는 검은 화면
진행 방법
사용한 도구
Claude Code: 실제 코드 작성, 파일 수정, 터미널 명령 실행, 데이터베이스 점검, 심지어 테스트 계정을 만들었다 지우면서 실제로 검증하는 것까지 전부 이 안에서 진행했어요. 저는 코드를 한 줄도 직접 안 쳤어요.
Supabase: 데이터베이스(각 표별 원본 데이터 저장) + 로그인/회원가입 기능
Vercel: 만든 사이트를 실제 인터넷에 올리는 배포 서비스 (GitHub에 코드를 올리면 자동으로 반영)
Resend: 회원가입 확인 메일 등을 보내는 이메일 발송 서비스
Windows 작업 스케줄러 + PowerShell: 사무실 PC를 24시간 켜두고, 하루 2번 자동으로 엑셀을 찾아서 업로드
어떻게 활용했나 — 단계별로
1) 기본 뼈대 만들기 (07/25~07/28) Next.js로 기본 틀을 만들고, Supabase 로그인을 붙이고, 코팅현황 대시보드부터 하나씩 만들어갔어요. 이때는 배포 환경변수(비밀키 같은 설정값)가 왜 안 읽히는지 몰라서 디버그용 로그를 여러 번 추가했다가 지우는 시행착오도 있었어요.
2) 자동 업로드 파이프라인 구축 (07/29~07/30) 관리자가 화면에서 엑셀을 직접 올리는 기능에서 시작해서, "토큰"으로 인증하는 자동 업로드 API를 만들고, 현장 PC에서 그 API로 파일을 보내는 PowerShell 스크립트까지 만들었어요. 생산계획/출하현황/진공증착 대시보드도 이 시기에 추가했고요.
3) 다듬기와 자동화 마무리 (07/31~08/04) 기존 로직을 이해하려고 이렇게 물었어요:
엑셀 업로드 로직 자세히 보여줘
그다음 실제 회사 네트워크 폴더에 있는 파일 4개를 지정해서 업로드를 요청했고, 이어서 완전 자동화를 요청했어요:
4개의 파일에 접근 가능한 회사 내 데스크탑 PC를 24시간 on해두고 나주 대시보드에 4개의 파일을 자동으로 업로드하려고 하면 어떻게 하면 될지? 차근차근 알려줘
작업 스케줄러 등록까지 마친 뒤, 실제 화면에서 숫자가 이상해 보여서 이렇게 물었어요:
히터코일 출하량이 중복된 것 같아. 다른 업로드 데이터 포함 점검해줘.
Claude Code가 sync_log(업로드 기록 표)를 직접 조회해서, 두 개의 업로드가 거의 동시에 실행되면서 데이터가 뒤섞인 걸 찾아냈어요. 원인은 작업 스케줄러의 "여러 인스턴 스 동시 실행 허용" 기본값이었고, 재업로드 한 번으로 해결했어요. 업무 로직도 하나 바꿨어요 — "세정출하"라는 상태를 수주잔량이 아니라 출하량으로 잡아야 한다는 걸 알게 되어서 반영했고, 회원가입 메일이 하나도 안 가는 문제(Supabase 기본 메일 발송 한도)도 이때 Resend 커스텀 SMTP로 해결했어요. 도메인을 누가 관리하는지도 몰랐는데, Claude Code가 네임서버를 조회해서 관리 업체(㈜룩엔에스)를 직접 찾아내고, 그 업체에 보낼 요청 문구까지 만들어줬어요.
4) 보안 점검과 강화 (08/04) 기능은 다 됐다 싶었는데, 데이터베이스 접근 권한 전체를 한번 점검해보고 싶어서 물었어요:
supabase 이메일 발송량 제한을 초과했다고 뜨는데, 해결방법 알려줘 (→ 이 문제 해결 이후, 김에 전체 보안도) supabase 에 올라가는 자료는 무엇이고? 보안문제는 없는지? 점검해줘
여기서 꽤 심각한 문제가 나왔어요 — "관리자 승인 대기" 화면은 그냥 화면에서만 막아놓은 것이었고, 실제 데이터베이스는 로그인만 하면 승인 여부와 상관없이 모든 데이터를 읽고 쓸 수 있게 열려 있었어요. 이 문제를 고친 뒤, 한번 더 확인차 이렇게 물었어요:
다른 표들도 이런 보안 문제 없는지 다시 한번 확인해줘
Claude Code가 실제로 임시 테스트 계정을 만들어서 "승인 전엔 0건 조회, 승인 후엔 조회는 되지만 쓰기는 여전히 막힘"까지 하나하나 확인하고, 테스트 계정은 바로 삭제했어요.
5) 마무리 다듬기 — 모바일, 세부 권한, 첫인상 (08/06) 사용해보다가 발견한 것들을 하나씩 고쳤어요. 스마트폰에서 관리자 메뉴로 갈 방법이 없다는 걸 발견해서:
스마트폰에서도 PC와 동일하게 관리자 메뉴 선택가능하도록 하고, 세부 대시보드에서 대시보드 선택화면으로 이동할 수 있도록 해줘
관리자가 여러 명이 되면서 필요해진 세밀한 권한 조정도 요청했어요:
관리자 화면에 사용자 별로 열어볼 수 있는 대시보드를 설정할 수 있는 기능을 만들어줘
관리지 지정과 해제는 기본관리자만 가능하도록 해줘.
마지막으로 로그인 화면에 회사 사진을 넣어 첫인상도 다듬었어요.
코드 예시 — 안전장치가 실제로 버그를 잡아낸 순간
업로드 코드(lib/ingest.ts)에는 "넣은 만큼 실제로 들어갔는지 다시 세어서 확인"하는 안전장치가 있어요. 동시 업로드 중복 버그를 정확히 잡아낸 부분이에요.
// 비우기와 넣기가 한 덩어리로 묶여 있지 않아서, 같은 표에 업로드가 겹치면
// 한쪽이 비우는 사이 다른 쪽이 넣어 행이 뒤섞인 채 쌓인다. 넣은 만큼
// 들어갔는지 마지막에 세어 확인한다.
const finalCount = await countRows(supabase, table);
if (finalCount !== rows.length) {
throw new IngestError(
저장 결과가 맞지 않습니다 (넣으려던 ${rows.length}건 → 실제 ${finalCount}건). +
업로드가 동시에 두 번 이상 실행됐을 수 있습니다. 잠시 뒤 한 번만 다시 올려주세요.,
);
}보안 점검에서 나온 수정은, "로그인만 하면 OK"에서 "승인된 사람만"으로 데이터베이스 규칙 자체를 바꾼 것이었어요.
-- 이전: 로그인만 하면(authenticated) 누구나 전부 읽기/쓰기 가능
create policy "authenticated can read coating records"
on public.coating_records for select to authenticated using (true);
-- 이후: 승인된 회원만 읽기 가능, 쓰기 정책은 아예 없앰 (쓰기는 서버만)
create policy "approved users can read coating records"
on public.coating_records for select to authenticated
using (public.is_approved_user(auth.uid()));📸 스크린샷 삽입 위치: 여기에 (1) Vercel 배포 상태(Ready) 화면, (2) Resend DNS 인증 화면, (3) 관리자 화면의 사용자별 대시보드 체크박스, (4) 새로 바뀐 로그인 화면(공장 사진) 캡처를 넣으면 좋아요. 대화 중 캡처해서 공유했던 이미지들을 이 자리에 붙여넣어 주세요.
결과와 배운 점
배운 점 / 나만의 꿀팁
"성공"이라는 응답을 그대로 믿지 않기: 업로드 API가 200 OK를 반환해도, 실제 DB에 몇 건이 들어갔는지 다시 세어보는 안전장치가 없었다면 중복 버그를 몰랐을 거예요.
"잘 만들었다"와 "안전하다"는 다른 문제였어요: 기능이 다 동작한다고 보안까지 저절로 되는 게 아니더라고요. "보안 점검해줘"라고 따로 물어보고 나서야, 승인 대기 화면이 눈속임에 불과했다는 걸 알았어요. 기능 개발이 끝난 뒤엔 꼭 한 번 별도로 점검을 요청하는 게 좋아요.
AI가 테스트 계정을 만들고 지우면서 직접 검증하게 하기: "된다고 알려줬으니 믿자"가 아니라, 실제로 임시 계정을 만들어 승인 전/후로 로그인해보고, 끝나면 흔적 없이 지우는 방식으로 검증받으니 훨씬 믿음이 갔어요.
로그인 화면은 AI가 대신 못 넘어간다: Vercel/Supabase 대시보드는 보안상 AI가 대신 로그인해줄 수 없어서, 그 부분만큼은 제가 직접 화면을 캡처해서 공유해야 했어요. 처음엔 답답했지만, 오히려 비밀번호 같은 민감 정보가 안전하게 지켜진다는 뜻이기도 했어요.
한 번에 한 단계씩 진행하니 비전공자도 따라갈 수 있었어요: "8단계 중 3단계" 식으로 나눠서, 매번 뭘 했는지 요약받고 다음으로 넘어가니 중간에 뭘 하는지 놓치지 않았어요.
시행착오
초반(07/26~07/27)에는 배포 환경변수가 왜 안 읽히는지 몰라서 디버그 로그를 여러 번 추가/제거하는 삽질이 있었어요.
작업 스케줄러의 "다중 인스턴스 허용" 기본값 때문에 실제 운영 데이터가 두 배로 뻥튀기되는 사고가 있었어요.
기본 관리자 이메일을 바꿨더니 회원 목록이 사라진 적이 있어요: 새 관리자 이메일 계정이 화면상으로는 "기본 관리자"로 잘 보였는데, 데이터베이스 안쪽의 "관리자" 표시가 별도로 꺼져 있어서 다른 회원 목록을 못 불러오는 문제였어요. 겉보기 상태와 데이터베이스 실제 값이 따로 놀 수 있다는 걸 배웠어요.
도움이 필요한 부분
메시 출하현황 표에는 개별 출하를 구분하는 번호 컬럼이 없어서, 실제로는 다른 출하인데 "중복"처럼 보이는 행이 많아요. 원인은 파악했지만, 원본 엑셀 구조를 바꾸는 건 현장 협의가 필요해서 지금은 보류 중이에요.
앞으로의 계획
메시 출하현황에 구분 번호 컬럼을 추가 할지 현장과 협의
대시보드 종류를 필요에 따라 계속 늘려가기
자동화가 조용히 멈추는 상황(사이트 접속 불가, 파일 갱신 누락 등)을 더 빨리 알아챌 수 있는 알림 보강
사용자별 대시보드 접근 권한 기능을 실제 현장 인원 배치에 맞춰 세팅
도움 받은 글 (옵션)
Claude Code / Claude Agent SDK 공식 문서 (Anthropic)
Supabase, Vercel, Resend 각 서비스의 공식 문서