AI · 사내 시스템
사내 업무 시스템
노션에 흩어진 314개 DB를 팀이 더 이상 수기로 채우지 않아도 되도록. 대표가 음성으로 던진 지시를 AI가 과업으로 만들고, 검수하면 노션에 자동 반영된다.
- 기간
- 2026.04 – 2026.05
- 역할
- 기획·설계·구현 단독 (GM/PM)
- 상태
- 운영 중
- 규모
- 10,450줄
문제
복제 템플릿 200종에 서술형 양식 수십 개. 팀원은 포맷 채우기를 기피하고, 대표는 전화·카톡으로 구두 지시하니 아무것도 시스템에 남지 않았다.
해결
노션을 디스플레이 레이어로 강등하고 D1을 진실의 원천으로 삼았다. 음성·텍스트 지시를 LLM이 담당자·마감·결과물로 구조화하고, 중간관리자 검수를 통과한 과업만 노션에 단방향 push.
314개
정리 대상 노션 DB
운영 배포 완료
상태
문제
광고대행사가 노션을 업무 허브로 쓰고 있었습니다. 다만 이런 상태였습니다.
- 복제 템플릿 200종에 서술형 양식 수십 개 — 팀원이 포맷 채우기를 극도로 기피
- 데이터가 314개 DB에 산재 — 무엇이 진행 중인지 한눈에 안 보임
- 대표는 전화·카톡으로 구두 지시하는 사람 — 지시가 시스템에 안 남고 휘발
- 경영진이 현황을 보려면 매번 누군가 노션을 정리해줘야 함
입력 부담은 팀에, 가시성 부재는 경영진에. 둘 다 사람이 메우고 있었습니다.
설계 결정
| 결정 | 이유 |
|---|---|
| 노션은 디스플레이 레이어, D1이 진실의 원천 | 노션 스키마에 도메인 모델을 묶으면 피보팅 때 전부 깨진다. 코드 우선으로 분리 |
| 이중 궤도 | 기존 노션은 그대로 두고 [v2 staging]에서 실험 → 검증 후 승격. 운영 중단 0 |
| 경영진 슬라이스 먼저 | 가장 안정적인 니즈(대표 가시성)부터. 팀원 자동화는 후순위 |
| 검수 큐 | AI·직원이 만든 과업은 전부 중간관리자 검수를 통과해야 노출. 품질과 책임을 한곳으로 |
| 앱 → 노션 단방향 push | 직원은 노션을 계속 본다. 승인된 과업만 자동 생성해 불일치 제거 |
아키텍처
[입력] 음성 / 텍스트 / 카카오 [디스플레이]
PWA (홈 화면 설치, iOS 푸시) 노션 (팀·클라이언트 뷰)
│ ▲
▼ │ 단방향 push (승인 과업)
┌──────────────────────────────┐ │
│ Cloudflare Worker (Hono/TS) │──── Notion API ───┘
│ + D1 (SQLite, 진실의 원천) │
└───┬───────────────┬──────────┘
│ │
[LLM via AI Gateway] [Web Push (VAPID)]
Claude + OpenAI 폴백 매일 10시·23시 브리핑
+ Whisper STT
TypeScript 약 9,500줄 · 백엔드 41개 모듈 · 프론트 16개 컴포넌트 · 마이그레이션 7개.
핵심 기능
- 대화·음성으로 과업 생성 — “팀원1한테 클라이언트D SNS 기획 다음주 금까지 시켜”라고 말하면 Whisper가 받아 적고, AI가 담당자·프로젝트·마감·이유·결과물로 구조화해 확인 카드를 냅니다. 정보가 부족하면 되묻습니다.
- 검수 큐 — 만들어진 과업은 중간관리자에게만 보이는 검수함으로. 수정·승인하면 대시보드·브리핑·노션에 동시 반영됩니다.
- 자동 일일 브리핑 — 하루 두 번 크론이 오늘 마감·지연·팀 로드·KPI를 모아 LLM이 요약하고, 검수를 거쳐 경영진에게 푸시로 갑니다.
- 프로젝트 보드 — 상태·클라이언트별 그룹핑에 진행률과 드릴다운. 노션을 열지 않아도 현황이 보입니다.
- 노션 양방향 동기화 — 노션에서 가져올 때는 reconciliation을 포함하고, 내보낼 때는 승인 과업만 단방향으로.
- 역할 기반 권한 — 경영진은 지시·조회, 중간관리자는 검수·삭제.
어려웠던 문제
LLM 지역 차단 — 가장 오래 막힌 문제
Worker에서 LLM을 부르면 간헐적으로 403이 났습니다. 처음엔 프롬프트 문제인 줄 알았는데, 세 제공사가 전부 막히는 게 이상했습니다.
원인은 Cloudflare Worker의 아웃바운드 IP였습니다. 사용자 IP와 무관하게, 제공사 입장에서 비지원 지역 풀로 분류되는 주소에서 나가고 있었습니다. 로컬에서 되는 게 Worker에서 안 되면 대개 출구 IP입니다.
Cloudflare AI Gateway를 경유시켜 해결했습니다. API 키도 요청 형식도 그대로 두고 URL만 게이트웨이로 바꿨더니 통과했고, 덤으로 로그·캐시·rate limit이 따라왔습니다. 안전분류기 오탐은 민감 인물명을 토큰화(클라이언트A → CLIENT_A)해서 없앴습니다.
노션 양방향 동기화의 함정
- 노션 DB 쿼리는 휴지통 항목을 반환하지 않습니다. 그래서 삭제분이 D1에 영영 남습니다. “이번 sync에 안 보인 행은 archived 처리”하는 seen-set reconciliation으로 잡되, 네트워크 실패 때 전부 archive되지 않도록 가드를 뒀습니다.
- 노션 integration의
/v1/users는 대표 한 명만 노출합니다. 팀원 7명의 UUID는 기존 과업의 담당자 속성에서 긁어와 매칭했습니다. - 노션 API로는 템플릿 자동 적용이 안 됩니다. 본문은 D1에 두고, 표준 템플릿은 코드로 블록을 직접 생성했습니다.
자연어를 구조로 바꾸기
Claude의 function calling으로 create_task와 ask_detail 두 도구만 줬습니다. 지시면 추출하고, 질문이면 그냥 답하고, 정보가 부족하면 되묻습니다 — 한 대화 흐름 안에서 분기합니다.
AI가 고른 project_id·user_id는 D1에 실재하는지 검증합니다. 환각 방어입니다. “나/내가”는 발화자 본인으로 매핑합니다.
배운 것
- 제약이 설계를 만듭니다. “노션을 못 버린다”는 조직 제약이 디스플레이·진실 레이어 분리라는 깔끔한 구조로 이어졌습니다.
- 엣지 환경에서 외부 API는 IP가 변수입니다. 이걸 모르면 프롬프트만 며칠 고칩니다.
- AI 자동화의 핵심은 게이트입니다. 완전 자동보다 “AI가 초안 → 사람이 검수”가 실무에서 신뢰를 만듭니다.
English Summary
A solo-built full-stack tool that turns an ad agency’s manual, Notion-based workflow into a voice/chat-driven system. A manager speaks a task, Whisper transcribes it, Claude (via tool use) structures it into assignee/project/deadline/spec, and a review queue lets a manager approve before it auto-syncs to Notion. Includes scheduled AI daily briefings with iOS push, role-based access, and bidirectional Notion sync.
Stack: Cloudflare Workers + D1 + Hono (TypeScript), React/Vite PWA, Claude + OpenAI via Cloudflare AI Gateway, Whisper STT, Web Push, Notion API. ~9.5k LOC, solo design and build.
Notable problems solved: edge-IP region-blocking of LLM providers (solved with AI Gateway), Notion trash reconciliation, harvesting member UUIDs the Notion API wouldn’t expose, and hallucination-guarded natural-language-to-task extraction.
광고대행사명과 클라이언트명은 전부 익명 처리