패스트뷰
경력근거: 즉시출고 재고: 금융사 즉시출고 재고를 1시간 단위로 갱신해 홈과 검색에 공급하는 연동을 만들어요.
'즉시출고 재고: 금융사 즉시출고 재고를 1시간 단위로 갱신해 홈과 검색에 공급하는 연동을 만들어요.' 와 '22개 제휴 금융사와 외부 파트너 연동을 운영하고, 데이터 정합성을 책임져요.' 는 둘 다 이 자리의 주요업무에 적힌 일입니다. 공고는 고객을 '차를 사는 사람, 그리고 매일 차살때로 고객을 상담하는 딜러' 두 그룹으로 나누고, 함께 풀 질문으로 '금융사 즉시출고 재고를 실시간으로 보여주면, 바로 계약으로 이어지는 상담을 얼마나 늘릴 수 있을까요?' 를 듭니다. 즉시출고 차는 금융사가 가진 재고라 차살때가 팔림을 직접 보지 못하고, 한 시간마다 받는 재고가 끊기거나 홈·검색에 늦게 닿으면 그 사이 신청이 팔린 차로 들어와 딜러가 상담 자리에서 처음 압니다. 그 두 그룹 가운데 이 화면은 딜러를 사용자로 세우고, 3주차에 같은 판정을 홈·검색 노출에 겁니다. 금융사 재고 피드의 모양은 공고에 없어 금융사 네 곳 분량의 회차별 재고 파일을 제가 만들었습니다. 이 포트폴리오는 한 시간 단위 재고 연동과 그 정합성 판정을 Laravel 배치와 MySQL 로 구현하는 일을 보여주며, 자동차 금융 상품의 전문성은 주장하지 않습니다.
주요업무에 금융사 즉시출고 재고를 1시간 단위로 갱신해 홈과 검색에 공급하는 연동이 있고, 3개월 안에 출시할 후보로도 즉시출고 재고 연동을 듭니다. 이 화면은 그 갱신 회차 기록으로 상담 신청을 판정합니다.
22개 제휴 금융사 연동을 운영하며 데이터 정합성을 책임지고, Redis·배치·스케줄러 운영과 장애 대응 체계를 갖춘다고 적혀 있습니다. 금융사별 마지막 성공 회차를 세어 갱신이 멈춘 금융사의 신청을 따로 세우는 판정이 그 정합성을 다룹니다.
공고는 고객을 차를 사는 사람과 매일 차살때로 고객을 상담하는 딜러 두 그룹으로 나누고, 딜러가 매일 쓰는 도구를 바꿔 같은 딜러가 더 많은 고객을 잘 상담하게 할 수 있는지 묻습니다. 상담 전에 바꿔 안내할 신청을 보여주는 이 화면의 사용자가 그 딜러입니다.
차살때 딜러가 카카오톡 상담을 시작하기 전에 여는 관리자 페이지입니다. 오늘 배정된 즉시출고 상담 신청마다 고객이 본 차가 신청 직전 재고 회차와 가장 늦은 회차에 있었는지, 월 납입료가 신청 화면보다 1천 원 넘게 달라졌는지, 그 금융사의 재고 갱신이 두 시간 넘게 멈췄는지를 따져 다섯 판정 가운데 하나를 매기고, 팔린 차에는 다른 금융사 재고까지 살펴 같은 트림 대체 후보를 신청 금액에 가까운 순으로 세웁니다. 그로스팀은 3주차부터 이 화면에 슬랙 알림으로 들어옵니다. 어느 금융사의 갱신이 120분을 넘겨 멈추면 알림 링크가 화면 위 금융사 띠의 그 칸을 열고, 그로스팀은 거기서 실패 회차와 사유를 보고 연동을 고칩니다. 금융사 재고는 금융사마다 받는 피드를 Laravel 스케줄러가 매시간 읽어 회차별로 쌓은 기록입니다.
차살때로 매일 고객을 상담하는 딜러와 즉시출고 연동을 맡은 차살때 그로스팀. 딜러는 카카오톡 상담을 시작하기 전 관리자 페이지에서 오늘 배정된 즉시출고 상담 신청의 판정을 보고, 팔린 차는 같은 차종의 다른 즉시출고 차로 바꿔 안내하고 바뀐 월 납입료로 견적을 다시 낸다. 그로스팀은 같은 화면에서 갱신이 멈춘 금융사 연동과 팔린 차를 계속 보여 준 홈·검색 노출을 고친다
즉시출고 차는 금융사가 가진 재고라서 차살때는 한 시간마다 받는 재고 피드에서 차가 빠졌는지로 팔림을 압니다. 피드가 끊기거나 홈·검색이 지난 회차를 계속 보여 주면 고객은 이미 팔린 차나 금액이 바뀐 차로 상담을 신청하고, 딜러는 카카오톡 상담을 시작한 뒤에야 그 사정을 압니다. 신청 시각을 한국 시각으로 맞추고, 그 금융사의 신청 직전 회차와 가장 늦은 회차에 그 차가 있었는지, 마지막 성공 동기화가 언제였는지를 견주면 딜러는 첫 메시지를 보내기 전에 바꿔 안내할 신청을 압니다.
딜러가 관리자 페이지에서 자기 번호를 고르면 오늘 배정된 즉시출고 상담 신청이 다섯 판정으로 나뉘고, 신청을 누르면 그 차가 금융사 회차마다 있었는지와 신청 금액·지금 금액, 같은 트림 대체 후보가 나옵니다. 화면 위 금융사 띠에는 금융사마다 마지막 성공 회차와 실패 사유가 있습니다. 금융사 재고는 작성자가 만든 네 금융사의 회차별 피드 파일을 Laravel 스케줄러가 매시간 읽어 쌓은 것입니다.
시각 변환, 직전 회차, 120분, 1천 원에서 판정이 한 끗 차이로 뒤집히는 사례 40건에 손으로 정답을 달아 판정과 맞대고, 어긋난 건마다 갈린 단계를 표시한 리포트가 나옵니다. 딜러 화면의 걸린 신청에는 Claude Haiku 4.5 가 쓴 첫 카카오톡 메시지 초안이 뜨고, 입력에 없는 금액을 쓴 초안은 기본 문장으로 바뀝니다. 2주차부터 동기화 배치와 판정 API 는 AWS EC2 와 RDS(MySQL) 에서 매시간 돕니다.
갱신이 120분을 넘긴 금융사가 생기면 그로스팀 슬랙 채널에 실패 사유와 걸린 신청 수가 올라가고, 알림 링크는 판정 화면 금융사 띠의 그 칸으로 들어옵니다. 홈·검색 즉시출고 목록 API 는 금융사마다 가장 늦은 성공 회차만 읽고 회차가 끝날 때마다 Redis 캐시를 비우며, 갱신이 멈춘 금융사의 차는 목록에서 내립니다. 오늘 아침 신청 기록을 다시 흘려 이미 팔린 차로 들어온 신청 가운데 몇 건이 생기지 않았을지 셉니다.
딜러 DL-104 가 09:20 에 판정 화면을 열면 오늘 배정된 즉시출고 신청 네 건이 판정별로 나뉘고, REQ-20931 을 누르면 AC-24117 이 a-capital 07:00 회차에 있다가 신청 직전 08:00 회차에서 빠졌다는 칸과 같은 트림 대체 후보 AC-24152(월 55만 9천 원)·BC-30588(월 56만 1천 원)이 나옵니다.
신청 시각이 UTC 로 남은 기록, 09:00 회차 한 번만 실패한 c-autolease 와 두 회차를 놓친 d-capital, 월 납입료가 꼭 1천 원 오른 BC-30570, 견적 금액 없이 들어온 REQ-20934, 08:00 회차에서만 빠졌던 AC-24165 를 섞어도 판정이 판정식대로 나옵니다. c-autolease 신청은 08:00 회차로 판정하고, d-capital 신청 두 건은 차가 남았든 빠졌든 갱신 멈춤으로 나옵니다.
깨진 피드 다섯 종(응답 시간 초과, JSON 문법 오류, 바뀐 필드 이름, 금액 칸의 '64만 8천' 같은 글자, 시간대가 빠진 기준 시각)을 흘려도 동기화 배치는 그 회차를 failed 로 남기고 다음 회차를 돌며, 판정 화면은 열린 채 금융사 띠에 실패 사유를 보여줍니다.
작성자가 손으로 정답을 단 판정 테스트 40건에서 판정이 정답과 같은 건수를 셉니다. 단, 피드 파일과 신청 기록, 정답을 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건에서의 동작입니다.
위 수치는 작성자가 만든 피드와 신청 기록의 자가채점이며, 팔린 차로 들어온 신청을 실제로 상담 전에 몇 건 잡는지는 차살때의 금융사 재고 연동 기록과 딜러 상담 결과가 있어야 잽니다. 이 포트폴리오는 그 측정을 바로 돌릴 수 있는 상태까지 만듭니다.
c-autolease 의 응답 지연과 d-capital 의 JSON 문법 오류는 제가 피드를 깨뜨려 만든 실패라, 실제 금융사 연동에서 끊김·형식 변경·지연 가운데 무엇이 흔하고 몇 회차씩 이어지는지는 모릅니다. 판정 테스트 40건의 정답도 제가 달아서 다 맞아도 제가 정한 판정식을 코드로 옮겼다는 데서 멈추고, 실제 실패 양상은 차살때의 연동 기록을 받아야 압니다.
REQ-20931 의 23:12Z 를 시간대 없이 읽으면 직전 회차가 전날로 잡히고, 한국 시각 08:12 로 바꿔야 a-capital 08:00 회차가 됩니다. c-autolease 는 한 회차만 실패해 80분이라 08:00 회차로 판정하고 d-capital 은 두 회차를 놓쳐 140분이라 갱신 멈춤입니다. BC-30570 은 월 납입료가 꼭 1천 원 올라 '넘으면' 을 '이상' 으로 쓰면 걸리고, REQ-20934 는 quoted_monthly 가 null 이라 금액 비교를 건너뜁니다. AC-24165 는 08:00 회차에서만 빠졌다가 09:00 회차에 돌아와, 카드 판정식을 글자대로 쓰면 지금 재고에 있는 차를 팔렸다고 안내하게 됩니다.
한 번 실패한 금융사는 직전 성공 회차로 판정하므로 c-autolease 의 08:00 뒤에 팔린 차는 그대로 안내 가능으로 나옵니다. 딜러가 그 사정을 보고 상담을 시작하도록 화면 위 금융사 띠에 마지막 성공 시각과 실패 사유를 띄웁니다.
금융사 22곳의 실제 피드는 필드 이름과 금액 단위, 갱신 주기가 제가 만든 네 모양과 다르고, 팔린 재고 번호를 다른 차에 다시 쓰는 금융사가 있으면 vehicle_id 만으로는 팔림을 놓칩니다. 실제 도입에서는 금융사마다 피드 명세를 받아 동기화 배치의 읽기 규칙과 120분·1천 원 기준부터 다시 맞춥니다.
이 포트폴리오는 한 시간 단위 재고 연동의 실행 기록과 회차별 재고로 상담 신청을 판정하는 백엔드 구현을 보여주며, 자동차 금융 상품과 금융사 재고 운영의 전문성은 주장하지 않습니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
차살때 앱에서 들어와 딜러에게 배정된 즉시출고 상담 신청입니다. 앱 서버가 신청 시각을 UTC(Z)로 남기고, 고객이 신청 화면에서 본 트림과 월 납입료도 담습니다. 홈 배너에서 견적 화면을 거치지 않고 들어와 quoted_monthly 가 null 인 신청(REQ-20934)과, 갱신이 멈춘 금융사의 차로 들어온 신청 둘, 신청 직전 회차에서만 빠졌던 차로 들어온 신청(REQ-20938)을 넣었습니다. 신청 기록은 작성자가 만든 더미입니다.
| request_id | dealer_id | lender_id | vehicle_id | trim_shown | quoted_monthly | requested_at |
|---|---|---|---|---|---|---|
| REQ-20918 | DL-121 | c-autolease | CO-1188 | 카니발 9인승 노블레스 | 612,000 | 2026-10-13T22:50:00Z |
| REQ-20923 | DL-104 | d-capital | DC-77031 | EV6 롱레인지 어스 | 571,000 | 2026-10-13T23:05:00Z |
| REQ-20931 | DL-104 | a-capital | AC-24117 | 쏘렌토 1.6 HEV 시그니처 | 552,000 | 2026-10-13T23:12:00Z |
| REQ-20934 | DL-121 | c-autolease | CO-1203 | EV3 롱레인지 어스 | — | 2026-10-13T23:20:00Z |
| REQ-20938 | DL-117 | a-capital | AC-24165 | 셀토스 1.6T 시그니처 | 412,000 | 2026-10-13T23:28:00Z |
아래 JSON Schema 를 그대로 만족하는 즉시출고 상담 신청을 30건 더 만들어 주세요. {"type":"object","properties":{"request_id":{"type":"string","description":"상담 신청 번호입니다"},"dealer_id":{"type":"string","description":"신청을 배정받은 딜러 번호입니다"},"lender_id":{"type":"string","description":"고객이 본 즉시출고 차를 가진 금융사입니다"},"vehicle_id":{"type":"string","description":"금융사가 매긴 즉시출고 재고 번호입니다"},"trim_shown":{"type":"string","description":"고객이 신청 화면에서 본 차종·트림입니다"},"quoted_monthly":{"type":["integer","null"],"minimum":1,"description":"고객이 신청 화면에서 본 월 납입료(원)입니다. 홈 배너에서 견적 화면을 거치지 않고 들어온 신청은 null 입니다"},"requested_at":{"type":"string","description":"신청 시각입니다. 앱 서버가 UTC 로 남겨 Z 로 끝납니다"}},"required":["request_id","dealer_id","lender_id","vehicle_id","trim_shown","quoted_monthly","requested_at"]} lender_id·vehicle_id·trim_shown 은 함께 주는 stock_snapshots 의 행에서 고르고, quoted_monthly 는 신청 직전 회차의 monthly_payment 를 쓰며, requested_at 은 2026-10-13T21:00:00Z~2026-10-14T00:30:00Z 사이의 UTC 로 적으세요. 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) 신청 직전 회차에 이미 없던 차로 들어온 신청, (2) 신청 뒤 회차에서 빠진 차, (3) 지금 회차 월 납입료가 신청 금액과 꼭 1천 원 다른 신청과 수만 원 다른 신청, (4) quoted_monthly 가 null 인 신청, (5) 갱신이 멈춘 금융사의 차로 들어온 신청, (6) 신청 직전 회차에는 없었고 가장 늦은 회차에 다시 나타난 차로 들어온 신청(기대 판정은 이미 팔린 차가 아니라 월 납입료 비교 결과입니다). 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도(requested_at 이 '10/14 08:12' 같은 표기, quoted_monthly 가 '61만 2천' 같은 글자)는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"request_id":{"type":"string","description":"상담 신청 번호입니다"},"dealer_id":{"type":"string","description":"신청을 배정받은 딜러 번호입니다"},"lender_id":{"type":"string","description":"고객이 본 즉시출고 차를 가진 금융사입니다"},"vehicle_id":{"type":"string","description":"금융사가 매긴 즉시출고 재고 번호입니다"},"trim_shown":{"type":"string","description":"고객이 신청 화면에서 본 차종·트림입니다"},"quoted_monthly":{"type":["integer","null"],"minimum":1,"description":"고객이 신청 화면에서 본 월 납입료(원)입니다. 홈 배너에서 견적 화면을 거치지 않고 들어온 신청은 null 입니다"},"requested_at":{"type":"string","description":"신청 시각입니다. 앱 서버가 UTC 로 남겨 Z 로 끝납니다"}},"required":["request_id","dealer_id","lender_id","vehicle_id","trim_shown","quoted_monthly","requested_at"]}작성자가 금융사 네 곳(a-capital·b-capital·c-autolease·d-capital) 분량으로 만든 회차별 즉시출고 피드 파일을 동기화 배치가 매시간 읽어 쌓은 재고 표입니다. 회차마다 그때 피드에 있던 차가 한 행씩 있고, 빠진 차는 그 회차에 행이 없습니다. 07:00 회차 뒤에 빠진 AC-24117, 08:00 회차에서만 빠졌다가 09:00 회차에 돌아온 AC-24165, 08:00 회차 뒤에 빠진 BC-30552, 09:00 회차에서 월 납입료가 1천 원 오른 BC-30570, 08:00 회차에서 3만 6천 원 오른 CO-1188, 서로 다른 금융사에 같은 트림으로 올라온 쏘렌토와 그랜저가 있습니다. 천 원 단위로 금액을 주는 피드는 배치가 원 단위로 바꿔 넣습니다.
| lender_id | vehicle_id | model_trim | monthly_payment | synced_at |
|---|---|---|---|---|
| a-capital | AC-24117 | 쏘렌토 1.6 HEV 시그니처 | 552,000 | 2026-10-14T07:00:00+09:00 |
| a-capital | AC-24130 | 아반떼 1.6 인스퍼레이션 | 318,000 | 2026-10-14T07:00:00+09:00 |
| a-capital | AC-24165 | 셀토스 1.6T 시그니처 | 412,000 | 2026-10-14T07:00:00+09:00 |
| a-capital | AC-24130 | 아반떼 1.6 인스퍼레이션 | 318,000 | 2026-10-14T08:00:00+09:00 |
| a-capital | AC-24130 | 아반떼 1.6 인스퍼레이션 | 318,000 | 2026-10-14T09:00:00+09:00 |
아래 JSON Schema 를 그대로 만족하는 재고 행을 금융사 4곳 × 회차 6개(04:00~09:00) 분량으로 더 만들어 주세요. {"type":"object","properties":{"lender_id":{"type":"string","description":"재고를 가진 금융사입니다"},"vehicle_id":{"type":"string","description":"금융사가 매긴 즉시출고 재고 번호입니다"},"model_trim":{"type":"string","description":"차살때 표기의 차종·트림입니다"},"monthly_payment":{"type":"integer","minimum":1,"description":"그 회차 피드의 월 납입료(원)입니다. 천 원 단위로 주는 피드는 동기화 배치가 원 단위로 바꿔 넣습니다"},"synced_at":{"type":"string","description":"이 행을 쌓은 회차 시각입니다. 그 회차 sync_runs 의 ran_at 과 같고 +09:00 입니다"}},"required":["lender_id","vehicle_id","model_trim","monthly_payment","synced_at"]} 금융사마다 회차당 2~5대를 두고, 같은 vehicle_id 는 회차가 바뀌어도 model_trim 을 그대로 두며, synced_at 은 sync_runs 의 success 행 ran_at 과 같게 맞추세요. 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) 한 회차에서 빠져 다시 나타나지 않는 차, (2) 다음 회차에서 월 납입료가 꼭 1천 원 바뀐 차와 수만 원 바뀐 차, (3) 서로 다른 금융사에 같은 model_trim 으로 올라온 차, (4) 한 회차에서 빠졌다가 다음 회차에 다시 나타나는 차(가장 늦은 회차에 있으므로 이 차로 들어온 신청은 이미 팔린 차가 아니라 월 납입료 비교로 판정합니다). 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도(monthly_payment 가 '648,000' 같은 문자열, synced_at 에 시간대가 없는 값)는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"lender_id":{"type":"string","description":"재고를 가진 금융사입니다"},"vehicle_id":{"type":"string","description":"금융사가 매긴 즉시출고 재고 번호입니다"},"model_trim":{"type":"string","description":"차살때 표기의 차종·트림입니다"},"monthly_payment":{"type":"integer","minimum":1,"description":"그 회차 피드의 월 납입료(원)입니다. 천 원 단위로 주는 피드는 동기화 배치가 원 단위로 바꿔 넣습니다"},"synced_at":{"type":"string","description":"이 행을 쌓은 회차 시각입니다. 그 회차 sync_runs 의 ran_at 과 같고 +09:00 입니다"}},"required":["lender_id","vehicle_id","model_trim","monthly_payment","synced_at"]}동기화 배치가 금융사마다 회차를 돌 때 남긴 실행 기록입니다. status 는 success·failed 이고 detail 에 반영한 대수나 실패 사유가 있습니다. 작성자가 피드를 일부러 깨뜨려 c-autolease 는 09:00 회차 한 번, d-capital 은 08:00·09:00 두 회차가 실패하게 했습니다.
| lender_id | ran_at | status | detail |
|---|---|---|---|
| a-capital | 2026-10-14T07:00:00+09:00 | success | 피드 3대 반영 |
| a-capital | 2026-10-14T08:00:00+09:00 | success | 피드 1대 반영 |
| a-capital | 2026-10-14T09:00:00+09:00 | success | 피드 3대 반영 |
| b-capital | 2026-10-14T07:00:00+09:00 | success | 피드 1대 반영 |
| b-capital | 2026-10-14T08:00:00+09:00 | success | 피드 2대 반영 |
아래 JSON Schema 를 그대로 만족하는 실행 기록을 금융사 4곳 × 회차 6개(04:00~09:00) 분량으로 더 만들어 주세요. {"type":"object","properties":{"lender_id":{"type":"string","description":"동기화한 금융사입니다"},"ran_at":{"type":"string","description":"회차 시각입니다. 매시 정각에 돌고 +09:00 입니다"},"status":{"type":"string","enum":["success","failed"],"description":"그 회차 동기화 결과입니다"},"detail":{"type":"string","description":"성공이면 반영한 대수, 실패면 실패 사유입니다"}},"required":["lender_id","ran_at","status","detail"]} ran_at 은 매시 정각 +09:00 이고, success 행의 detail 은 '피드 N대 반영' 꼴로, failed 행은 실패 사유로 적으세요. 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) 한 회차만 실패한 금융사, (2) 두 회차 이상 연달아 실패한 금융사, (3) 실패 뒤 다시 성공한 금융사. 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도(status 가 'ok' 같은 enum 밖 값, ran_at 이 빈 문자열)는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"lender_id":{"type":"string","description":"동기화한 금융사입니다"},"ran_at":{"type":"string","description":"회차 시각입니다. 매시 정각에 돌고 +09:00 입니다"},"status":{"type":"string","enum":["success","failed"],"description":"그 회차 동기화 결과입니다"},"detail":{"type":"string","description":"성공이면 반영한 대수, 실패면 실패 사유입니다"}},"required":["lender_id","ran_at","status","detail"]}| PHP (Laravel) | 매시간 도는 stock:sync 스케줄러 명령, 금융사별 피드 읽기 클래스, 판정 서비스, 딜러용 REST API 를 Laravel 로 씁니다. 스케줄러는 withoutOverlapping 으로 같은 회차를 겹쳐 돌리지 않습니다. |
| MySQL | consult_requests·stock_snapshots·sync_runs 세 표를 담고, (lender_id, synced_at)·(lender_id, vehicle_id, synced_at) 인덱스로 신청마다 직전 회차를 고르는 조회를 EXPLAIN 으로 확인합니다. 판정 조회는 읽기 전용 레플리카 연결로 보냅니다. |
| Redis | 스케줄러 큐와 중복 실행 잠금에 쓰고, 3주차에는 회차가 끝날 때마다 홈·검색 즉시출고 목록 캐시를 금융사 단위로 비웁니다. |
| REST | GET /api/dealer/instant-consults?dealer_id=&as_of= 가 판정, 회차 근거, 대체 후보를 돌려줍니다. |
| Next.js · React | 딜러용 관리자 페이지의 금융사 띠, 판정별 신청 목록, 회차 칸 상세 패널을 만듭니다. |
| AWS | 2주차부터 EC2 에서 스케줄러를 cron 으로 돌리고, RDS(MySQL) 와 그 읽기 전용 레플리카에 재고와 판정 조회를 둡니다. |
| LLM · Claude | 2주차에 Claude Haiku 4.5 로 걸린 신청마다 딜러가 보낼 첫 카카오톡 메시지 초안을 씁니다. |
| Claude Code | 판정 서비스는 Claude Code 로 짜되, 판정이 뒤집히는 사례 테스트를 먼저 써 두고 생성된 코드를 그 테스트로 검수한 뒤 합칩니다. |
✗ fail → REQ-20931 의 직전 회차가 08:00 이 아니면 requested_at 을 한국 시각으로 바꾸는 줄부터 고칩니다.
✓ pass → 여기서 멈춰도 완결입니다. 더 키우려면 판정이 뒤집히는 사례 40건과 딜러 첫 메시지 초안으로 갑니다.
✓ pass → 여기까지도 완결입니다. 더 키우려면 같은 기준을 홈·검색 목록에 걸고 갱신 멈춤 알림을 더합니다.
위 예측 UI 는 3주차까지 완주했을 때의 화면입니다. 1주차에 실제로 만드는 것은 아래 표시된 화면 하나입니다.
verdict사유 라벨 · request_id + 한 줄 요약(근거 수치 포함)화면·코드·면접에서 이 단어를 그대로 씁니다. 키는 출력 스키마의 enum 과 같습니다.
그대로 안내 가능그대로 안내금융사 재고 갱신이 멈춤갱신 멈춤이미 팔린 차로 들어온 신청이미 팔린 차신청 뒤에 팔린 차신청 뒤 팔림월 납입료가 바뀐 차월 납입료 변경즉시출고 상담 신청 하나에 판정 하나와 그 근거(한국 시각 신청 시각, 마지막 성공 회차와 지난 분, 직전 회차와 가장 늦은 회차의 재고 여부, 월 납입료 두 값과 차이, 같은 트림 대체 후보)를 남기는 형식입니다.
{"type":"object","properties":{"request_id":{"type":"string"},"dealer_id":{"type":"string"},"lender_id":{"type":"string"},"vehicle_id":{"type":"string"},"trim_shown":{"type":"string"},"requested_at_kst":{"type":"string","description":"정적 계산값입니다. requested_at(UTC)에 9시간을 더해 +09:00 으로 적은 신청 시각입니다"},"as_of":{"type":"string","description":"판정 기준 시각입니다. 화면을 연 시각이고 샘플은 2026-10-14T09:20:00+09:00 입니다"},"verdict":{"type":"string","enum":["그대로 안내 가능","금융사 재고 갱신이 멈춤","이미 팔린 차로 들어온 신청","신청 뒤에 팔린 차","월 납입료가 바뀐 차"],"description":"금융사 재고 갱신이 멈춤, 이미 팔린 차로 들어온 신청, 신청 뒤에 팔린 차, 월 납입료가 바뀐 차 순으로 먼저 걸린 하나입니다. 이미 팔린 차로 들어온 신청은 신청 직전 회차와 가장 늦은 회차에 모두 그 차가 없을 때만입니다. 하나도 걸리지 않으면 그대로 안내 가능입니다"},"last_success_at":{"type":["string","null"],"description":"sync_runs 에서 이 lender_id 의 status 가 success 인 가장 늦은 ran_at 입니다"},"minutes_since_success":{"type":["integer","null"],"minimum":0,"description":"정적 계산값입니다. as_of − last_success_at 을 분으로 센 값이고, 120 을 넘으면 금융사 재고 갱신이 멈춤입니다"},"round_before_request":{"type":["string","null"],"description":"이 lender_id 의 success 회차 가운데 ran_at 이 requested_at_kst 와 같거나 이른 가장 늦은 회차입니다. 갱신 멈춤이면 null 입니다"},"in_round_before_request":{"type":["boolean","null"],"description":"round_before_request 회차의 stock_snapshots 에 같은 vehicle_id 행이 있는지입니다"},"latest_round":{"type":["string","null"],"description":"이 lender_id 의 가장 늦은 success 회차입니다. 갱신 멈춤이면 null 입니다"},"in_latest_round":{"type":["boolean","null"],"description":"latest_round 회차의 stock_snapshots 에 같은 vehicle_id 행이 있는지입니다"},"last_seen_round":{"type":["string","null"],"description":"이 vehicle_id 가 stock_snapshots 에 나온 가장 늦은 synced_at 입니다"},"quoted_monthly":{"type":["integer","null"],"description":"consult_requests.quoted_monthly 그대로입니다"},"latest_monthly":{"type":["integer","null"],"description":"latest_round 회차에서 이 차의 monthly_payment 입니다"},"monthly_gap_won":{"type":["integer","null"],"description":"latest_monthly − quoted_monthly 입니다. 둘 중 하나가 null 이면 null 입니다"},"payment_check":{"type":"string","enum":["1천 원 이하 차이","1천 원 넘게 차이","견적 금액 없음","견주지 않음"],"description":"월 납입료를 견준 결과입니다. 갱신 멈춤이나 팔린 차 판정이면 견주지 않음입니다"},"alternatives":{"type":"array","items":{"type":"object","properties":{"lender_id":{"type":"string"},"vehicle_id":{"type":"string"},"monthly_payment":{"type":"integer"},"synced_at":{"type":"string"}},"required":["lender_id","vehicle_id","monthly_payment","synced_at"]},"description":"팔린 차 두 판정에만 채웁니다. 갱신 멈춤이 아닌 금융사의 latest_round 재고 가운데 model_trim 이 trim_shown 과 같은 차를 |monthly_payment − quoted_monthly| 가 작은 순으로 둡니다"},"evidence":{"type":"array","items":{"type":"object","properties":{"table":{"type":"string","enum":["consult_requests","stock_snapshots","sync_runs"]},"row":{"type":["string","null"],"description":"그 표의 키입니다. consult_requests 는 request_id, stock_snapshots 는 lender_id/vehicle_id/synced_at, sync_runs 는 lender_id/ran_at 입니다. agg 항목이면 null 입니다"},"field":{"type":"string"},"value":{"type":["string","integer","null"]},"agg":{"type":"string","enum":["count","sum","avg","min","max"]},"scope":{"type":"string","description":"agg 항목이 센 조건입니다"}},"required":["table","row","field","value"]}},"notes":{"type":"array","items":{"type":"string"},"description":"판정에 들지 않았지만 딜러가 상담 전에 볼 사실입니다"},"summary":{"type":"string","description":"딜러가 읽는 한 문장입니다"}},"required":["request_id","dealer_id","lender_id","vehicle_id","trim_shown","requested_at_kst","as_of","verdict","last_success_at","minutes_since_success","round_before_request","in_round_before_request","latest_round","in_latest_round","last_seen_round","quoted_monthly","latest_monthly","monthly_gap_won","payment_check","alternatives","evidence","notes","summary"]}[
{
"request_id": "REQ-20931",
"dealer_id": "DL-104",
"lender_id": "a-capital",
"vehicle_id": "AC-24117",
"trim_shown": "쏘렌토 1.6 HEV 시그니처",
"requested_at_kst": "2026-10-14T08:12:00+09:00",
"as_of": "2026-10-14T09:20:00+09:00",
"verdict": "이미 팔린 차로 들어온 신청",
"last_success_at": "2026-10-14T09:00:00+09:00",
"minutes_since_success": 20,
"round_before_request": "2026-10-14T08:00:00+09:00",
"in_round_before_request": false,
"latest_round": "2026-10-14T09:00:00+09:00",
"in_latest_round": false,
"last_seen_round": "2026-10-14T07:00:00+09:00",
"quoted_monthly": 552000,
"latest_monthly": null,
"monthly_gap_won": null,
"payment_check": "견주지 않음",
"alternatives": [
{
"lender_id": "a-capital",
"vehicle_id": "AC-24152",
"monthly_payment": 559000,
"synced_at": "2026-10-14T09:00:00+09:00"
},
{
"lender_id": "b-capital",
"vehicle_id": "BC-30588",
"monthly_payment": 561000,
"synced_at": "2026-10-14T09:00:00+09:00"
}
],
"evidence": [
{
"table": "consult_requests",
"row": "REQ-20931",
"field": "requested_at",
"value": "2026-10-13T23:12:00Z"
},
{
"table": "consult_requests",
"row": "REQ-20931",
"field": "vehicle_id",
"value": "AC-24117"
},
{
"table": "sync_runs",
"row": "a-capital/2026-10-14T08:00:00+09:00",
"field": "status",
"value": "success"
},
{
"table": "stock_snapshots",
"row": null,
"field": "vehicle_id",
"value": 0,
"agg": "count",
"scope": "a-capital 08:00 회차의 AC-24117 행"
},
{
"table": "stock_snapshots",
"row": "a-capital/AC-24117/2026-10-14T07:00:00+09:00",
"field": "synced_at",
"value": "2026-10-14T07:00:00+09:00"
},
{
"table": "sync_runs",
"row": "a-capital/2026-10-14T09:00:00+09:00",
"field": "ran_at",
"value": "2026-10-14T09:00:00+09:00"
},
{
"table": "stock_snapshots",
"row": "a-capital/AC-24152/2026-10-14T09:00:00+09:00",
"field": "monthly_payment",
"value": 559000
},
{
"table": "stock_snapshots",
"row": "b-capital/BC-30588/2026-10-14T09:00:00+09:00",
"field": "monthly_payment",
"value": 561000
}
],
"notes": [
"신청 시각 23:12Z 는 한국 시각 08:12 이고, 그 직전 회차는 a-capital 08:00 입니다.",
"AC-24117 은 07:00 회차까지 있었고 08:00 회차부터 없습니다. 홈·검색이 08:00 회차 뒤에도 이 차를 보여 준 것입니다.",
"대체 후보는 같은 트림을 신청 금액 55만 2천 원에 가까운 월 납입료 순으로 세웠습니다."
],
"summary": "고객이 신청하기 전인 08:00 회차에서 이미 빠진 차라, 같은 트림의 AC-24152(월 55만 9천 원)나 BC-30588(월 56만 1천 원)로 바꿔 안내합니다."
},
{
"request_id": "REQ-20944",
"dealer_id": "DL-117",
"lender_id": "b-capital",
"vehicle_id": "BC-30552",
"trim_shown": "그랜저 2.5 캘리그래피",
"requested_at_kst": "2026-10-14T08:31:00+09:00",
"as_of": "2026-10-14T09:20:00+09:00",
"verdict": "신청 뒤에 팔린 차",
"last_success_at": "2026-10-14T09:00:00+09:00",
"minutes_since_success": 20,
"round_before_request": "2026-10-14T08:00:00+09:00",
"in_round_before_request": true,
"latest_round": "2026-10-14T09:00:00+09:00",
"in_latest_round": false,
"last_seen_round": "2026-10-14T08:00:00+09:00",
"quoted_monthly": 702000,
"latest_monthly": null,
"monthly_gap_won": null,
"payment_check": "견주지 않음",
"alternatives": [
{
"lender_id": "c-autolease",
"vehicle_id": "CO-1210",
"monthly_payment": 719000,
"synced_at": "2026-10-14T08:00:00+09:00"
}
],
"evidence": [
{
"table": "consult_requests",
"row": "REQ-20944",
"field": "requested_at",
"value": "2026-10-13T23:31:00Z"
},
{
"table": "stock_snapshots",
"row": "b-capital/BC-30552/2026-10-14T08:00:00+09:00",
"field": "synced_at",
"value": "2026-10-14T08:00:00+09:00"
},
{
"table": "stock_snapshots",
"row": "b-capital/BC-30552/2026-10-14T08:00:00+09:00",
"field": "monthly_payment",
"value": 702000
},
{
"table": "sync_runs",
"row": "b-capital/2026-10-14T09:00:00+09:00",
"field": "status",
"value": "success"
},
{
"table": "stock_snapshots",
"row": null,
"field": "vehicle_id",
"value": 0,
"agg": "count",
"scope": "b-capital 09:00 회차의 BC-30552 행"
},
{
"table": "stock_snapshots",
"row": "c-autolease/CO-1210/2026-10-14T08:00:00+09:00",
"field": "monthly_payment",
"value": 719000
}
],
"notes": [
"신청한 08:31 직전의 08:00 회차에는 BC-30552 가 월 70만 2천 원으로 있었고, 09:00 회차에서 빠졌습니다.",
"대체 후보 CO-1210 은 c-autolease 의 가장 늦은 성공 회차인 08:00 기준이고, 이 금융사의 09:00 회차는 실패했습니다."
],
"summary": "신청 뒤 09:00 회차에서 빠진 차라, 같은 트림의 CO-1210(월 71만 9천 원, 신청 금액보다 1만 7천 원 높음)으로 바꿔 안내합니다."
},
{
"request_id": "REQ-20918",
"dealer_id": "DL-121",
"lender_id": "c-autolease",
"vehicle_id": "CO-1188",
"trim_shown": "카니발 9인승 노블레스",
"requested_at_kst": "2026-10-14T07:50:00+09:00",
"as_of": "2026-10-14T09:20:00+09:00",
"verdict": "월 납입료가 바뀐 차",
"last_success_at": "2026-10-14T08:00:00+09:00",
"minutes_since_success": 80,
"round_before_request": "2026-10-14T07:00:00+09:00",
"in_round_before_request": true,
"latest_round": "2026-10-14T08:00:00+09:00",
"in_latest_round": true,
"last_seen_round": "2026-10-14T08:00:00+09:00",
"quoted_monthly": 612000,
"latest_monthly": 648000,
"monthly_gap_won": 36000,
"payment_check": "1천 원 넘게 차이",
"alternatives": [],
"evidence": [
{
"table": "consult_requests",
"row": "REQ-20918",
"field": "quoted_monthly",
"value": 612000
},
{
"table": "stock_snapshots",
"row": "c-autolease/CO-1188/2026-10-14T08:00:00+09:00",
"field": "monthly_payment",
"value": 648000
},
{
"table": "stock_snapshots",
"row": "c-autolease/CO-1188/2026-10-14T07:00:00+09:00",
"field": "monthly_payment",
"value": 612000
},
{
"table": "sync_runs",
"row": "c-autolease/2026-10-14T08:00:00+09:00",
"field": "ran_at",
"value": "2026-10-14T08:00:00+09:00"
},
{
"table": "sync_runs",
"row": "c-autolease/2026-10-14T09:00:00+09:00",
"field": "status",
"value": "failed"
}
],
"notes": [
"c-autolease 는 09:00 회차가 실패해 08:00 회차로 판정했습니다. 마지막 성공에서 80분이 지나 갱신 멈춤에 들지 않습니다.",
"신청 화면의 61만 2천 원은 신청 직전 07:00 회차 값과 같습니다."
],
"summary": "같은 차가 08:00 회차에도 있지만 월 납입료가 61만 2천 원에서 64만 8천 원으로 3만 6천 원 올라, 바뀐 금액으로 견적을 다시 냅니다."
},
{
"request_id": "REQ-20923",
"dealer_id": "DL-104",
"lender_id": "d-capital",
"vehicle_id": "DC-77031",
"trim_shown": "EV6 롱레인지 어스",
"requested_at_kst": "2026-10-14T08:05:00+09:00",
"as_of": "2026-10-14T09:20:00+09:00",
"verdict": "금융사 재고 갱신이 멈춤",
"last_success_at": "2026-10-14T07:00:00+09:00",
"minutes_since_success": 140,
"round_before_request": null,
"in_round_before_request": null,
"latest_round": null,
"in_latest_round": null,
"last_seen_round": "2026-10-14T07:00:00+09:00",
"quoted_monthly": 571000,
"latest_monthly": null,
"monthly_gap_won": null,
"payment_check": "견주지 않음",
"alternatives": [],
"evidence": [
{
"table": "sync_runs",
"row": "d-capital/2026-10-14T07:00:00+09:00",
"field": "ran_at",
"value": "2026-10-14T07:00:00+09:00"
},
{
"table": "sync_runs",
"row": "d-capital/2026-10-14T07:00:00+09:00",
"field": "status",
"value": "success"
},
{
"table": "sync_runs",
"row": null,
"field": "status",
"value": 2,
"agg": "count",
"scope": "d-capital 07:00 뒤 failed 행"
},
{
"table": "sync_runs",
"row": "d-capital/2026-10-14T09:00:00+09:00",
"field": "detail",
"value": "피드 파일 JSON 문법 오류(41행)"
},
{
"table": "stock_snapshots",
"row": "d-capital/DC-77031/2026-10-14T07:00:00+09:00",
"field": "synced_at",
"value": "2026-10-14T07:00:00+09:00"
}
],
"notes": [
"d-capital 은 08:00·09:00 회차가 연달아 실패해 마지막 성공 07:00 에서 140분이 지났습니다.",
"07:00 회차에는 DC-77031 이 신청 금액과 같은 월 57만 1천 원으로 있었지만, 그 뒤 두 시간 사이에 팔렸는지는 이 기록에 없습니다."
],
"summary": "d-capital 재고가 07:00 뒤로 갱신되지 않아, 상담 전에 금융사에 이 차가 남았는지 먼저 묻습니다."
},
{
"request_id": "REQ-20957",
"dealer_id": "DL-117",
"lender_id": "d-capital",
"vehicle_id": "DC-77040",
"trim_shown": "스포티지 1.6T 시그니처",
"requested_at_kst": "2026-10-14T09:07:00+09:00",
"as_of": "2026-10-14T09:20:00+09:00",
"verdict": "금융사 재고 갱신이 멈춤",
"last_success_at": "2026-10-14T07:00:00+09:00",
"minutes_since_success": 140,
"round_before_request": null,
"in_round_before_request": null,
"latest_round": null,
"in_latest_round": null,
"last_seen_round": null,
"quoted_monthly": 466000,
"latest_monthly": null,
"monthly_gap_won": null,
"payment_check": "견주지 않음",
"alternatives": [],
"evidence": [
{
"table": "consult_requests",
"row": "REQ-20957",
"field": "requested_at",
"value": "2026-10-14T00:07:00Z"
},
{
"table": "sync_runs",
"row": "d-capital/2026-10-14T07:00:00+09:00",
"field": "ran_at",
"value": "2026-10-14T07:00:00+09:00"
},
{
"table": "sync_runs",
"row": null,
"field": "status",
"value": 2,
"agg": "count",
"scope": "d-capital 07:00 뒤 failed 행"
},
{
"table": "stock_snapshots",
"row": null,
"field": "vehicle_id",
"value": 0,
"agg": "count",
"scope": "d-capital 07:00 회차의 DC-77040 행"
}
],
"notes": [
"DC-77040 은 d-capital 의 마지막 성공 07:00 회차에도 없어, 갱신이 멈추지 않았다면 이미 팔린 차로 들어온 신청에 들었을 신청입니다. 갱신 멈춤이 앞서 이 판정을 씁니다.",
"신청 시각 00:07Z 는 한국 시각 09:07 입니다."
],
"summary": "d-capital 재고가 07:00 뒤로 갱신되지 않았고 그 회차에도 이 차가 없어, 금융사에 재고부터 묻습니다."
},
{
"request_id": "REQ-20950",
"dealer_id": "DL-117",
"lender_id": "b-capital",
"vehicle_id": "BC-30570",
"trim_shown": "투싼 1.6T 인스퍼레이션",
"requested_at_kst": "2026-10-14T08:49:00+09:00",
"as_of": "2026-10-14T09:20:00+09:00",
"verdict": "그대로 안내 가능",
"last_success_at": "2026-10-14T09:00:00+09:00",
"minutes_since_success": 20,
"round_before_request": "2026-10-14T08:00:00+09:00",
"in_round_before_request": true,
"latest_round": "2026-10-14T09:00:00+09:00",
"in_latest_round": true,
"last_seen_round": "2026-10-14T09:00:00+09:00",
"quoted_monthly": 489000,
"latest_monthly": 490000,
"monthly_gap_won": 1000,
"payment_check": "1천 원 이하 차이",
"alternatives": [],
"evidence": [
{
"table": "consult_requests",
"row": "REQ-20950",
"field": "quoted_monthly",
"value": 489000
},
{
"table": "stock_snapshots",
"row": "b-capital/BC-30570/2026-10-14T09:00:00+09:00",
"field": "monthly_payment",
"value": 490000
},
{
"table": "stock_snapshots",
"row": "b-capital/BC-30570/2026-10-14T08:00:00+09:00",
"field": "synced_at",
"value": "2026-10-14T08:00:00+09:00"
}
],
"notes": [
"월 납입료가 09:00 회차에서 1천 원 올랐고, 판정식은 1천 원을 넘어야 걸리므로 그대로 안내 가능입니다. 딜러는 09:00 회차 금액 49만 원으로 안내합니다."
],
"summary": "신청 직전 회차와 지금 회차에 모두 있는 차이고 월 납입료 차이가 1천 원이라, 지금 금액 49만 원으로 상담을 시작합니다."
},
{
"request_id": "REQ-20934",
"dealer_id": "DL-121",
"lender_id": "c-autolease",
"vehicle_id": "CO-1203",
"trim_shown": "EV3 롱레인지 어스",
"requested_at_kst": "2026-10-14T08:20:00+09:00",
"as_of": "2026-10-14T09:20:00+09:00",
"verdict": "그대로 안내 가능",
"last_success_at": "2026-10-14T08:00:00+09:00",
"minutes_since_success": 80,
"round_before_request": "2026-10-14T08:00:00+09:00",
"in_round_before_request": true,
"latest_round": "2026-10-14T08:00:00+09:00",
"in_latest_round": true,
"last_seen_round": "2026-10-14T08:00:00+09:00",
"quoted_monthly": null,
"latest_monthly": 433000,
"monthly_gap_won": null,
"payment_check": "견적 금액 없음",
"alternatives": [],
"evidence": [
{
"table": "consult_requests",
"row": "REQ-20934",
"field": "quoted_monthly",
"value": null
},
{
"table": "stock_snapshots",
"row": "c-autolease/CO-1203/2026-10-14T08:00:00+09:00",
"field": "monthly_payment",
"value": 433000
},
{
"table": "sync_runs",
"row": "c-autolease/2026-10-14T09:00:00+09:00",
"field": "status",
"value": "failed"
}
],
"notes": [
"홈 배너에서 견적 화면을 거치지 않고 들어온 신청이라 quoted_monthly 가 null 이고, 월 납입료는 견주지 않았습니다.",
"c-autolease 는 09:00 회차가 실패해 08:00 회차로 판정했습니다."
],
"summary": "08:00 회차에 있는 차이고 신청에 견적 금액이 없어, 08:00 회차 금액 43만 3천 원으로 견적을 처음 냅니다."
},
{
"request_id": "REQ-20938",
"dealer_id": "DL-117",
"lender_id": "a-capital",
"vehicle_id": "AC-24165",
"trim_shown": "셀토스 1.6T 시그니처",
"requested_at_kst": "2026-10-14T08:28:00+09:00",
"as_of": "2026-10-14T09:20:00+09:00",
"verdict": "그대로 안내 가능",
"last_success_at": "2026-10-14T09:00:00+09:00",
"minutes_since_success": 20,
"round_before_request": "2026-10-14T08:00:00+09:00",
"in_round_before_request": false,
"latest_round": "2026-10-14T09:00:00+09:00",
"in_latest_round": true,
"last_seen_round": "2026-10-14T09:00:00+09:00",
"quoted_monthly": 412000,
"latest_monthly": 412000,
"monthly_gap_won": 0,
"payment_check": "1천 원 이하 차이",
"alternatives": [],
"evidence": [
{
"table": "consult_requests",
"row": "REQ-20938",
"field": "requested_at",
"value": "2026-10-13T23:28:00Z"
},
{
"table": "stock_snapshots",
"row": "a-capital/AC-24165/2026-10-14T07:00:00+09:00",
"field": "synced_at",
"value": "2026-10-14T07:00:00+09:00"
},
{
"table": "stock_snapshots",
"row": null,
"field": "vehicle_id",
"value": 0,
"agg": "count",
"scope": "a-capital 08:00 회차의 AC-24165 행"
},
{
"table": "stock_snapshots",
"row": "a-capital/AC-24165/2026-10-14T09:00:00+09:00",
"field": "synced_at",
"value": "2026-10-14T09:00:00+09:00"
},
{
"table": "consult_requests",
"row": "REQ-20938",
"field": "quoted_monthly",
"value": 412000
},
{
"table": "stock_snapshots",
"row": "a-capital/AC-24165/2026-10-14T09:00:00+09:00",
"field": "monthly_payment",
"value": 412000
}
],
"notes": [
"직전 회차에는 없었다가 다시 나타남: AC-24165 는 07:00 회차에 있다가 신청 직전 08:00 회차에서 빠졌고, 09:00 회차에 같은 월 41만 2천 원으로 돌아왔습니다.",
"카드 판정식 글자대로면 이미 팔린 차로 들어온 신청이지만, 지금 재고에 있는 차라 월 납입료를 견줘 판정했습니다."
],
"summary": "신청 직전 08:00 회차에서만 빠졌다가 09:00 회차에 같은 금액으로 다시 나타난 차라, 지금 금액 41만 2천 원으로 상담을 시작합니다."
}
][자동 검증 · 코드가 판정합니다] 1. verdict 가 그대로 안내 가능·금융사 재고 갱신이 멈춤·이미 팔린 차로 들어온 신청·신청 뒤에 팔린 차·월 납입료가 바뀐 차 다섯 값 중 하나인지, payment_check 가 1천 원 이하 차이·1천 원 넘게 차이·견적 금액 없음·견주지 않음 네 값 중 하나인지 확인합니다. 2. 필수 필드 request_id·dealer_id·lender_id·vehicle_id·trim_shown·requested_at_kst·as_of·verdict·last_success_at·minutes_since_success·round_before_request·in_round_before_request·latest_round·in_latest_round·last_seen_round·quoted_monthly·latest_monthly·monthly_gap_won·payment_check·alternatives·evidence·notes·summary 가 모두 존재하는지 확인합니다. 3. requested_at_kst 가 requested_at(UTC, Z)에 9시간을 더해 +09:00 으로 적은 값인지 다시 계산합니다. REQ-20931 의 2026-10-13T23:12:00Z 는 2026-10-14T08:12:00+09:00 입니다. 4. last_success_at 이 sync_runs 에서 그 lender_id 의 status 가 success 인 가장 늦은 ran_at 이고, minutes_since_success 가 as_of − last_success_at 을 분으로 센 값인지 다시 계산합니다. minutes_since_success 가 120 을 넘으면 verdict 는 금융사 재고 갱신이 멈춤입니다. 성립 사례는 d-capital 의 REQ-20923·REQ-20957(140분), 불성립 사례는 09:00 회차 한 번만 실패한 c-autolease 의 REQ-20934(80분)입니다. 5. round_before_request 가 그 lender_id 의 success 회차 가운데 ran_at 이 requested_at_kst 와 같거나 이른 가장 늦은 회차이고, latest_round 가 가장 늦은 success 회차인지 다시 계산합니다. in_round_before_request·in_latest_round 는 그 회차의 stock_snapshots 에 같은 vehicle_id 행이 있는지로 다시 계산합니다. 6. 갱신 멈춤이 아니고 in_round_before_request 와 in_latest_round 가 모두 false 이면 verdict 는 이미 팔린 차로 들어온 신청입니다. 이 조건을 다시 계산해 성립 사례 REQ-20931(08:00·09:00 회차 모두 AC-24117 없음)과 불성립 사례 REQ-20938(08:00 회차에 없던 AC-24165 가 09:00 회차에 다시 있음)을 확인합니다. 7. in_round_before_request 가 true 이고 in_latest_round 가 false 이면 verdict 는 신청 뒤에 팔린 차입니다. 이 조건을 다시 계산해 성립 사례 REQ-20944(08:00 있음, 09:00 없음)와 불성립 사례 REQ-20950(두 회차 모두 있음)을 확인합니다. 8. monthly_gap_won 이 latest_monthly − quoted_monthly 인지 다시 계산하고, in_latest_round 가 true 이고 그 절댓값이 1000 을 넘으면 verdict 는 월 납입료가 바뀐 차입니다. 성립 사례는 REQ-20918(648,000 − 612,000 = 36,000), 불성립 사례는 REQ-20950(490,000 − 489,000 = 1,000)입니다. quoted_monthly 가 null 이면 monthly_gap_won 은 null 이고 payment_check 는 견적 금액 없음입니다(REQ-20934). 9. 위 네 판정에 걸리지 않으면 verdict 는 그대로 안내 가능입니다. REQ-20934·REQ-20938·REQ-20950 이 이 경우입니다. 10. verdict 가 이미 팔린 차로 들어온 신청이나 신청 뒤에 팔린 차이면, alternatives 가 갱신 멈춤이 아닌 금융사의 latest_round 재고 가운데 model_trim 이 trim_shown 과 같은 행이고 |monthly_payment − quoted_monthly| 가 작은 순인지 다시 계산합니다. REQ-20931 은 AC-24152(7,000 차이), BC-30588(9,000 차이) 순이고, 갱신이 멈춘 d-capital 재고는 후보에 들지 않습니다. 11. evidence 의 table·field 가 consult_requests·stock_snapshots·sync_runs 에 실재하는 컬럼인지 대조합니다. 12. agg 가 없는 evidence 의 value 가 그 row 의 그 컬럼 원문 값과 같은지, agg 가 count 인 value 가 scope 조건으로 센 행 수인지 확인합니다. 13. summary 와 notes 가 존댓말로 끝나는지 확인합니다. [수동 검증 · 사람이 봅니다] 1. 대체 후보 가운데 무엇을 먼저 권할지는 딜러가 고객의 조건을 듣고 정합니다. 화면은 월 납입료가 가까운 순으로만 세웁니다. 2. 갱신이 멈춘 금융사의 신청은 딜러가 금융사에 재고를 물어 확인한 뒤 상담을 시작합니다. 3. 한 번 실패한 금융사의 판정은 직전 성공 회차 기준이라, 딜러는 화면 위 금융사 띠의 마지막 성공 시각을 보고 상담 첫마디를 정합니다. 4. 1천 원 기준이 금융사 반올림 차이만 덮는지는 그로스팀이 실제 피드의 회차별 변동을 보고 정합니다. [평가 러너 · 2주차] 1. 시각 변환, 직전 회차 고르기, 120분, 1천 원 기준에서 판정이 뒤집히는 사례 40건에서 verdict 가 손으로 단 정답과 같은 건수를 셉니다. 2. 정답과 다른 건마다 어느 단계(시각 변환·회차 고르기·금액 비교·갱신 멈춤)에서 갈렸는지 같은 줄에 남깁니다. 3. 첫 메시지 초안 가운데 입력에 없는 금액이나 트림을 쓰거나 약속 표현이 들어가 기본 문장으로 바뀐 초안 수를 셉니다. [판정식에 더한 정의 · 오너 확인 항목] 1. 신청에 재고 번호만 있으면 딜러는 고객이 어떤 차를 봤는지 모르고, 금융사 재고에서 빠진 차는 대체 후보를 고를 트림도 남지 않습니다. 실패 회차에 이유가 없으면 금융사 띠가 실패 횟수만 보여 그로스팀이 무엇을 고칠지 모릅니다. 그래서 카드 inputs 에 없던 consult_requests.trim_shown 과 sync_runs.detail 을 더했고, 두 열 모두 판정식에는 쓰지 않습니다. 2. 회차는 sync_runs 의 success 행 하나이고, 그 회차 재고는 synced_at 이 그 ran_at 과 같은 stock_snapshots 행입니다. 3. requested_at 은 앱 서버가 UTC(Z)로 남겨 9시간을 더해 견줍니다. 카드의 '이전' 은 같거나 이른 시각으로 읽었습니다. 4. 카드의 '지금' 은 화면을 연 시각(as_of)이고 샘플은 2026-10-14 09:20 입니다. 120분을 넘어야 갱신 멈춤이고 120분 정각은 들지 않습니다. 5. 갱신이 멈춘 금융사의 신청은 회차 비교와 월 납입료 비교를 하지 않고 그 필드를 null 로 둡니다. 6. 카드 verdict_rule 보다 좁힌 정의입니다. 카드 글자대로면 신청 직전 회차에 없던 차가 가장 늦은 회차에 다시 나타나도 이미 팔린 차로 들어온 신청이 되어, 지금 재고에 있는 차를 팔렸다고 안내하는 줄이 생깁니다. 그래서 이미 팔린 차로 들어온 신청은 가장 늦은 회차에도 그 차가 없을 때만 내고, 다시 나타난 차는 월 납입료 비교로 내려가며 notes 에 '직전 회차에는 없었다가 다시 나타남' 을 적습니다(REQ-20938). 판정 순서는 갱신 멈춤, 이미 팔린 차, 신청 뒤 팔린 차, 월 납입료 순입니다. 7. 대체 후보는 판정에 쓰지 않고 상세 패널에만 띄웁니다.