---
title: "[N3] 고객시트 실데이터 + custom_fields 이관 (SHEET_EXTRAS 제거) — 완료"
from: claude-code
to: ["jadong"]
project: "callcenter-os"
date: 2026-07-06T09:07:33.582106+09:00
status: sent
type: report
---

# N3 완료 — 고객시트 실데이터 전환 (PR #21)

**브랜치** `feat/n3-sheet-live` · **PR** https://github.com/shinjadong/callcenter-os/pull/21 · 2026-07-06

## 무엇
callcenter-os 콕핏 M6 고객시트(`customers/[id]`)를 mock→core 실데이터로 전환. 평수/팔로우업 로컬 표시맵(`SHEET_EXTRAS`) 삭제 → 실 필드(`custom.area` / `Lead.followup_at`) 배선.

## 변경
- **page.tsx**: `"use client"` + `listLeads()`(X-MM-Token) 실데이터 + `NEXT_PUBLIC_DATA_MODE=mock` 폴백(M5 패턴) + 로딩/에러 셸
- **CustomerSheet.tsx**: `SHEET_EXTRAS` 삭제 → `areaOf(custom.area)` / `formatFollowup(followup_at, ISO→MM/DD HH:mm)`
- **fields.ts(신규)**: 로컬 util, `formatFollowup`은 Asia/Seoul 고정 TZ(CI TZ 무관 결정적). `core-api.ts`(N1 소유) 미접촉
- **seed_demo.py + mocks/leads.ts**: `area`+`followup_at` 12건 동일 정렬(리안치과·우리동물병원 followup null). `area`는 미정의 동적필드라 역할필터 미대상(region 선례)

## 검증 (증적 docs/design/verify/n3-seed.txt)
- web vitest **54 pass**(신규 fields 6 + CustomerSheet +2)
- `next build` exit0(11라우트, `/customers/[id]`=ƒ 4.63kB, lint/types OK, 인라인hex 0)
- core pytest **143 pass**(M5 기준 무회귀)
- 시드 재실행 idempotent(fresh 12 → 재실행 0)
- LeadOut 직렬화(consultant 역할): `area` 12/12 · `followup_at` 10/12 생존 → listLeads 실응답이 시트에 area+followup 전달 증명(MM 스택 불요)

## 다음
PR 머지는 PM 세션(N3 범위 밖). 병렬 WS: N1(실시간 폴링→WS), N2(MM 채널게시+담당 실명).
