9/9 완료 · 실사용 가능

메일로그

MAILLOG — inbox to structured record

해외 발전 플랜트 시운전 주간보고 이메일과 LL(Lessons Learned) 로그를 업로드 한 번으로 구조화된 DB에 쌓고, 필요할 때마다 그 DB에서 다시 산출물을 뽑아내는 개인 포트폴리오 프로젝트.

Stack
Cloudflare · Supabase
추출 방식
정규식 + LLM 하이브리드
데이터
가상/테스트 전용
접근 제어
로그인 + RLS
목적

왜 이 파이프라인이 필요했는가

해외 EPC 프로젝트는 현장마다 매주 주간보고 이메일이 들어오고, 사고·이슈는 LL·Project Issue·Pending List처럼 제각각 다른 엑셀 대장에 흩어져 쌓입니다. 그 안의 사실 — 호기별 진행상황, 마일스톤 날짜, 인력 파견, 이슈 조치이력 — 은 매번 사람이 다시 읽고 옮겨 적어야 다음 보고서(주간보고, LL보고서)가 나올 수 있었습니다. 메일로그는 이 반복 작업을 업로드 한 번으로 대체하는 것이 목적입니다 — 이메일 자체가 DB가 되고, 산출물은 그 DB에서 그때그때 다시 뽑아내는 방식으로.

무엇으로 만들었나

프론트엔드 · 백엔드 · 개발 방식 세 축

Frontend

사용자가 보는 화면

브라우저에서 바로 접속하는 웹앱. Cloudflare Pages에 정적 배포해 별도 서버 관리 없이 항상 접속 가능하도록 설계.

ReactViteCloudflare Pages
Backend

데이터와 추출 엔진

이메일 원본은 R2에, 구조화된 사실은 Supabase Postgres에. 기존 CCC 프로젝트의 DB를 emailpipeline 전용 스키마로 격리해 재사용.

SupabasePostgreSQLCloudflare WorkersR2
개발 방식

설계 우선, 단계별 검증

Claude Code와 함께 9단계로 나눠 설계 문서를 먼저 확정하고, 매 단계 실제 코드를 짜서 가상 데이터로 로컬 검증한 뒤에만 다음 단계로 진행.

스펙 기반 개발9단계 순차 진행단계별 로컬 검증
핵심 기능

DB 스키마 기준, 6개 모듈

업로드 & 자동 분류

제목 패턴으로 주간보고 A형/B형, LL 대장을 자동 판별하고 RE:/FW: 스레드를 자동으로 묶는다.

하이브리드 추출 엔진

정규식으로 먼저 구조를 뽑고, 자유서술에 섞였거나 애매한 부분만 LLM에 보완 요청. 확정 전까지는 항상 검수 대기 상태.

마일스톤 추적

주차별 스냅샷을 쌓아 계획일이 실제로 얼마나, 언제부터 밀렸는지 이력으로 보존한다.

이슈 통합 로그

LL·Project Issue·Pending List, 서로 다른 4종 대장을 하나의 스키마로 통합하고 이슈 1건의 여러 조치이력을 자동 병합.

인력 파견 이력

표가 아니라 문장 속에 섞인 파견·휴가 정보까지 추출 대상으로 포착해 별도 이력으로 남긴다.

산출물 생성

DB에 쌓인 사실로부터 주간보고 A/B형, LL보고서를 요청 시점 기준으로 재구성해 뽑아낸다.

설계 원칙

기능보다 먼저 지키기로 정한 5가지

정규식이 먼저, LLM은 빈 곳만

이메일 전체를 매번 LLM에 넘기지 않는다. 정규식으로 확정 못 한 필드만 골라 LLM에 보완 요청 — 비용과 신뢰도를 같이 잡기 위함.

자동 확정은 없다

정규식이든 LLM이든, 뽑아낸 값은 일단 pending_review. 사람이 한 번 확인해야 confirmed로 넘어간다.

억지로 채우지 않는다

못 뽑은 필드는 null로 두고 원문 스니펫만 보관한다. 실제로 그렇게 불완전한 데이터가 오기 때문.

지우지 않고 쌓는다

마일스톤은 덮어쓰지 않고 매주 스냅샷으로 적재해, 일정이 "얼마나 밀렸는지"까지 추적 가능하게 한다.

학습 데이터는 정답을 모른 채 만든다

추출 로직을 검증할 가상 이메일은 목표 DB 스키마를 보지 않고, 실제 서술 스타일만 참고해 노이즈까지 그대로 재현해서 만든다. 스키마를 알고 표본을 만들면 "깔끔하게 답이 보이는" 인풋만 생기고, 테스트가 테스트로서 의미를 잃기 때문 — 실제로 이 원칙 덕분에 검증 단계에서 진짜 파싱 버그를 발견했다.

어떻게 만들었나

9단계를 순서대로 — 설계 확정 후 코드, 코드 후 검증

STAGE 1산출물 포맷 정의완료
실제 사내 주간보고·LL 대장 6건을 구조만 일반화 추출해, 주간보고 A형(현장 상세)/B형(포트폴리오 롤업)과 LL 통합 컬럼셋을 확정.
STAGE 2DB 스키마 설계완료
14개 테이블 설계. phase_master로 공정단계 약어 체계를 여러 산출물이 공유하도록 정규화.
STAGE 3가상 이메일 데이터셋완료
가상 프로젝트 3개 × 4주치 A/B형 보고 + 이슈 대장. 목표 스키마를 보지 않고 상태값 표기 불일치·섹션 생략 같은 노이즈를 의도적으로 포함.
STAGE 4하이브리드 추출 로직완료
정규식 파서를 실제로 구현해 가상 데이터셋 전체에 실행 — 실제 파싱 버그 1건(섹션 경계 인식 오류)을 발견해 즉시 수정.
STAGE 5인프라 셋업완료
DB 마이그레이션 SQL, Workers/Pages 스캐폴드를 로컬에서 실제 실행 — CORS 버그 1건을 발견해 수정. Supabase 마이그레이션 적용(14개 테이블), R2 버킷 생성, Worker 실배포까지 완료.
STAGE 6업로드→파싱→저장 파이프라인완료
이메일(/api/emails) + xlsx 이슈대장(/api/issues) 업로드→파싱→Supabase 적재 전부 라이브 검증 완료 — 인력파견 이력, 마일스톤 표까지 저장. 진행 중 API 키 동기화 누락, 스키마 미노출, 권한 미부여, 배열 insert 키셋 불일치 등 실제 이슈 4건을 부딪히며 해결. LLM 실연동만 회사 결제 승인 대기로 보류.
STAGE 7산출물 생성 로직완료
DB → 주간보고 A/B형·LL보고서 렌더링 라이브 검증 완료. 진행 중 프로젝트 정체성 분열 버그(이메일은 이름으로, xlsx는 코드로 프로젝트를 찾다 보니 같은 프로젝트가 두 행으로 쪼개짐)를 발견해 마스터 시드로 해결.
STAGE 8UI완료
두산 표준양식(흰배경+네이비) 기반 고밀도 대시보드 — 메일 업로드, 산출물 생성/미리보기, 이슈 히트맵, 마일스톤 간트까지 실배포·브라우저 검증 완료.
STAGE 9인증 · 접근 제어 · 실제 이메일 대응완료
로그인 게이트(프론트) + API 토큰 검증(백엔드) + Supabase RLS로 3중 접근 제어를 갖추고, 실제 Outlook .eml(MIME) 형식까지 정규식 파서가 처리하도록 일반화. 진행 중 실제 결함 다수를 발견해 수정 — 긴 헤더를 가진 실메일에서 MIME 판별이 실패하던 버그, 업로드 실패가 화면에 아예 안 보이던 버그, 아무것도 못 뽑았는데 "성공"으로 표시되던 허위 성공 버그. 메일 카드 클릭 시 원문 팝업, 발신/수신 표시, 프로젝트별 필터, 선택 삭제까지 추가.
현재 상태

지금 시점에서 솔직한 진행 상황

완료 Stage
9 / 9
API 배포
Live
앱 배포
Live
접근 제어
로그인 + RLS
전 구간 완료 — 업로드부터 산출물 생성, 로그인 게이트가 걸린 실사용 화면까지 전부 라이브: maillog-doosan.pages.dev. 실제 Outlook 이메일(.eml) 형식 대응, 메일 원문 팝업 조회, 프로젝트별 필터, 가상 데이터 정리용 삭제 기능까지 9단계 설계→구현→실배포 검증을 마쳤습니다.