2,698건
실 응답으로 검증한 공고
50건
판정 엔진 회귀 테스트
0
판정 경로의 LLM 호출
풀어야 했던 문제
- 온통청년 API가 취업상태·학력·혼인을 한글명 없이 코드값으로만 준다 (전수 2,698건 중 한글명 0건)
- 행정구역 개편으로 법정동코드가 신·구 혼재 — 강원 42xxx→51xxx, 전북 45xxx→52xxx, 광주+전남은 12xxx로 재배정
- 자격 조건 상당수가 자유 텍스트라 규칙으로 판정할 수 없다
- 조건을 만족해도 이미 받는 제도와 중복수급 제한이 걸릴 수 있다
판정 엔진 — 틀리기보다 모른다고 말하게
- 판정 5단계: ✅자격 충족 · ❓확인 필요(기본값) · ⚠중복수급 주의 · ⬜해당 없음 · ⏹마감
- LLM을 판정 경로에서 완전히 배제 — 여기서 환각이 나면 사람이 신청 기회를 잃는다. 요약·자유텍스트 구조화에만 사용
- 빈 배열을 '제한 없음'으로 읽지 않는다 — 값이 없는 건 '조건이 없다'가 아니라 '모른다'. 이걸 통과로 처리했다가 자격 미달자에게 '자격 충족'이 뜬 적이 있다
- 모든 판정에 근거(reasons)를 남겨 사용자에게 그대로 노출 — 어떤 조건이 왜 통과·실패했는지
지역코드 정규화
- 시도 prefix만 바뀐 개편(강원·전북)은 양방향 기계 변환
- 시군구가 재배정된 개편(광주+전남 통합)은 변환식이 없다 — 목포는 46110→12110으로 뒷자리 유지, 광양은 46230→12190으로 밀림
- 확인된 매핑만 표에 명시하고, 표에 없는 구 코드는 '대상 아님'이 아니라 unknown 처리 — 모르는 걸 단정하면 받을 수 있는 제도를 조용히 놓친다
관련성 층 — 판정과 분리
- 첫 실발송에서 '자격 충족' 63건이 그대로 실렸는데, 20건 넘게가 '○○센터 운영', '△△대회 개최' 같은 기관 예산 항목이었다
- 지역으로 거를 수 없었다 — 인구유입형 사업은 오히려 해당 지역을 대상에서 빼고 있었다. 그래서 '어디 사업인가'가 아니라 '무엇을 주는 사업인가'로 분류
- 현금성 100 · 기회형 50 · 서비스형 10 가중에 마감 임박(+25)·관심사 일치(+30)를 더해 정렬, 메일당 12건 상한
- 관련성으로 판정을 건드리지 않는다 — 밀려난 항목은 대시보드에 남고 다음 주 후보로 되돌아온다
수집 · 운영
- 원본 응답(rawDetail)을 통째로 보존 — 정부 API는 예고 없이 필드명을 바꾸므로 파싱이 실패해도 원본은 남아야 한다
- contentHash로 변경분만 감지, CollectRun에 소스별 성패를 기록해 한 소스가 죽어도 나머지는 저장
- Docker Compose 배포 + 호스트 crontab(매일 수집 / 주 1회 발송) — 크론을 컨테이너 밖에 두어 실패 시 종료코드가 드러나게
- 대시보드는 127.0.0.1에만 바인딩 — 생년월일·주소·수혜이력이 담기므로 공개 인터넷에 노출하지 않는다
Stack
Next.js 16TypeScriptPrismaPostgreSQL공공데이터 APIResendDocker Composecron