8 commit 모두 룰 준수, 새 endpoint 7개 + 모달 2개 + 페이지 2개 + 섹션 4개 모두 박힘.
그러나 DiagnoseFlow2.tsx 본체에 모달 wiring이 없어 사용자가
실제 v3 흐름을 안 탐. 이건 PM 작업지시서 룰 작성 책임 (가드레일이
너무 엄격해서 본체 수정 자체를 막음). STAGE 2.5로 fix.
작업지시서 #3 가드레일에 박힌 표현:
app/diagnose/* 격리 영역 절대 수정 금지
(예외: P3 신규 컴포넌트 AgentGateModal.tsx · OtpVerifyModal.tsx만 추가 OK)
"신규 컴포넌트 추가만 OK"로 해석되어 코덱스가 본체 (DiagnoseFlow2.tsx)를
안 건드림. 정확히 룰 따른 것. 결과: 모달은 박혔지만 호출 안 되는 dead code.
의도는 "본체 임의 수정 금지, 단 모달 wiring을 위한 최소 변경 OK"였어야 함.
PM 작성 실수.
| 단계 | 현재 (production+staging) | v3 의도 (미작동) |
|---|---|---|
| 진단 폼 끝 [지원금 받기] | POST /api/keeper-out/diagnose 즉시 발송 (hotfix 박혀있어 잔액/캡 체크) |
AgentGateModal → request-otp → OtpVerifyModal → verify → 24h 안내 |
| 1만원 발송 | 즉시 (잔액≥5만원 + cap 미달 시) | 24h 휴먼 승인 후 (TM 1차 / fallback 2차) |
| admin 큐 (pending/fallback) | 비어있음 (사용자가 v3 흐름 안 탐) | 채워짐 (TM이 콜 outcome 입력) |
DiagnoseFlow2.tsx 본체에 wiring 박아야 v3 패러다임이 실제 작동.| 항목 | 판단 | PM 평가 |
|---|---|---|
| T+20~24h 정책 | (c) 하이브리드 채택 — 작업지시서 기본값 | OK 룰 따름 |
approved_by FK 안전 |
유효 UUID 있을 때만 저장, 없으면 NULL (auth.users 매핑 시점 미정) | OK FK 실패 방지 합리적 |
| /diagnose 본체 미수정 | 가드레일 룰 정확히 따름 | PM 책임 룰 작성 실수, 코덱스 잘못 X |
| 코덱스가 직접 짚은 것 | "PM이 OTP 모달을 /diagnose 플로우에 연결하라고 판단하면 가드레일을 별도 해제해야 합니다" | ★ EXCELLENT 자체 진단 정확 |
| 변경 | 파일 | 역할 |
|---|---|---|
| 수정 | app/diagnose/DiagnoseFlow2.tsx | submit() 함수를 v3 흐름으로 교체. URL ?ref={code} 추출. |
// 현재 (line 172):
async function submit() {
setStep("submitting");
const photo_urls = await uploadPhotos();
const res = await fetch("/api/keeper-out/diagnose", { ... });
const data = await res.json();
setStep(data.payback_token ? "reveal" : "done_basic");
}
// v3 흐름 (교체):
async function submit() {
// ① AgentGateModal 띄움 (영업원 코드 + 이름)
// URL ?ref={code}가 있으면 prefill, 없으면 빈 input
setShowAgentModal(true);
}
async function onAgentConfirm(agent_name, agent_code) {
setShowAgentModal(false);
setStep("submitting");
const photo_urls = await uploadPhotos();
// ② request-otp 호출
const res1 = await fetch("/api/keeper-out/diagnose/request-otp", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
payload: { ...buildPayload(), photo_urls },
agent_name, agent_code,
}),
});
const { otp_session_id } = await res1.json();
// ③ OtpVerifyModal 띄움 (5분 카운트다운)
setOtpSessionId(otp_session_id);
setShowOtpModal(true);
}
async function onOtpVerify(otp_code) {
// ④ verify 호출
const res2 = await fetch("/api/keeper-out/diagnose/verify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
otp_session_id, otp_code, payload: buildPayload(), agent_code,
}),
});
const data = await res2.json();
setShowOtpModal(false);
// ⑤ "본사 콜센터에서 곧 연락" 안내 화면
setStep("review_pending"); // 새 step
}
STAGE 2 PM PASS 받음. 단 wiring 미완 — STAGE 2.5 진행.
[원인]
PM 작업지시서 #3 가드레일이 "신규 모달만 추가 OK"로 작성돼 본체 수정 차단됨.
의도는 "본체 임의 수정 금지, 단 모달 wiring은 OK"였음.
PM이 가드레일 명시적 해제 — 너는 잘못 X.
[STAGE 2.5 — 가드레일 해제]
app/diagnose/DiagnoseFlow2.tsx 본체 수정 OK. 단 다음 룰:
- 기존 /api/keeper-out/diagnose POST 호출 제거 (deprecated, hotfix 흐름)
- 모달 wiring + 새 흐름만 추가
- 색깔 청록 #009090 등 절대 X (이건 어차피 /diagnose 격리는 청록 OK이지만 본체엔 박지 말 것 — 기존 톤 유지)
- search/q1/q2/pain/q3/q4/contact/photo step 자체는 그대로
[작업 — 1 commit]
(1) URL ?ref={code} 추출
- useSearchParams() 사용
- DiagnoseFlow2 안에서 const ref = searchParams.get("ref")
- AgentGateModal에 prefill로 전달
(2) state 추가
- showAgentModal: boolean
- showOtpModal: boolean
- otpSessionId: string | null
- agentName / agentCode: string
(3) submit() 함수 교체 (line 172부터)
기존 fetch("/api/keeper-out/diagnose") 호출 제거.
대신 setShowAgentModal(true)만.
(4) 새 함수 onAgentConfirm(agent_name, agent_code):
- setShowAgentModal(false), setStep("submitting")
- photo_urls = await uploadPhotos()
- fetch("/api/keeper-out/diagnose/request-otp", body: { payload, agent_name, agent_code })
- 응답 에러 처리 (잔액 미달, agent invalid, V4 unique 충돌, V8 place 검증 실패 등)
- 성공: setOtpSessionId(data.otp_session_id), setShowOtpModal(true)
(5) 새 함수 onOtpVerify(otp_code):
- fetch("/api/keeper-out/diagnose/verify", body: { otp_session_id, otp_code, payload, agent_code })
- 응답 에러 처리 (OTP 만료, 시도 초과 등)
- 성공: setShowOtpModal(false), setStep("review_pending") <- 새 step
(6) 새 step "review_pending" 렌더 추가
기존 reveal/done_basic처럼 별도 화면.
카피 (지시서 docs/keeper-out/anti-abuse/05-human-approval-queue.md §7 참조):
```
✅ 진단 완료!
📞 본사 콜센터에서 곧 연락드릴 예정이에요
💸 1만원 N페이 (입력하신 010-XXXX-XXXX)
본사 확인 콜 종료 후 24시간 내 발송됩니다
🔒 보안을 위해 자동 즉시 발송이 아닌 본사 확인 후
발송하는 정책으로 운영하고 있어요
```
(7) JSX에 모달 2개 마운트
{showAgentModal && }
{showOtpModal && }
(8) 모달 props는 컴포넌트 시그니처 확인 후 맞추기
grep -A 5 "interface.*Props" app/diagnose/components/AgentGateModal.tsx
grep -A 5 "interface.*Props" app/diagnose/components/OtpVerifyModal.tsx
[검증]
1. npx tsc --noEmit → 0
2. npx eslint app/diagnose/DiagnoseFlow2.tsx → 0
3. npm run build → success
4. dev 서버 띄우고 /diagnose 접속 → search → q1 → ... → photo → [지원금 받기]
① AgentGateModal 등장 → 영업원 코드 입력 → confirm
② "submitting" → request-otp 호출 → otp_session_id 응답 (실제 OTP SMS 도착 확인)
③ OtpVerifyModal 등장 → SMS 받은 OTP 6자리 입력
④ verify 응답 → "본사 콜센터에서 곧 연락" 안내 화면
⑤ /keeper-out/admin/pending 큐에 신규 row 진입 확인 (Supabase MCP로 확인)
[커밋]
feat(keeper-out/diagnose): v3 OTP 흐름 wiring (AgentGate + OtpVerify 모달 호출 + review_pending step)
[보고 형식]
## STAGE 2.5 wiring 결과 보고
### 1. 커밋 sha (1개)
### 2. /diagnose 흐름 변경 — 어떤 step이 어떻게 바뀌었나
### 3. 검증 결과 (tsc/eslint/build/dev 실제 흐름 테스트)
### 4. URL ?ref={code} 동작 확인 (테스트한 ref)
### 5. admin/pending 큐에 row 진입 확인 (Supabase row count or screenshot)
### 6. 막힌 곳 / 의문
[가드레일 — 같은 룰 그대로]
- 청록 #009090 등 X (admin 영역에)
- 한화·키퍼·하나비전 텍스트 X
- next.config / package.json 수정 X
- staging만 push, main은 PM 검증 후 자동님 결정
- untracked 13개 보존
[시작]
지금 진행. 작업 끝나면 위 보고 형식으로 회신.