← 문서 허브 · 2026-06-17 · ENGINE · 데이터 아키텍처

코퍼스·도감 유지보수 스킬 — 작동 원리

어떤 테이블JSON을 가져와, 어떻게 가공하고, 어디에 저장하는가 — 그리고 왜 이 데이터는 DB 테이블이 아니라 정적 JSON인가.

📒 DB는 읽기 전용 3테이블 🗂️ 저장은 파일·코드만 (DB 쓰기 0) 🌙 크론은 적용 · 스킬은 개선
1

한눈에 — 입력 → 가공 → 산출 → 배포 → 크론 소비

스킬은 읽기 전용으로 DB·소스를 보고, 코드와 정적 JSON만 고쳐 커밋한다. DB에는 한 줄도 쓰지 않는다. 실제로 DB 튜플이 바뀌는 건 한참 뒤 — 배포된 코드를 매일 새벽 2시 크론이 실행하면서 자동으로 분해·적재할 때뿐이다.

입력 (읽기 전용) 📒 DB 3테이블 · READ learned_menus · meal_logs user_menu_overrides 📚 레시피·표준식단 DB young-recipes 90종 · 농진청 dietary4u · NEIS 식판 (권위 정답지) 🗂️ 기존 정적 JSON 도감 풀 · food-graph 매트릭스 · 체크포인트 ⚙️ 코퍼스·도감 유지보수 스킬 (사람이 부를 때 · 큐레이션 루프) A0 증분 정독 신규 메뉴만 감사 A 사전 튜닝 룰·렉시콘·제외 B 매트릭스 재생성 궁합·사촌·통계 C 도감 확장 조사+안전스크린 산출 = 파일·코드만 (DB 쓰기 0) 💻 코드 사전 menuMapCore.ts (MENU_MAP·boost·meatFix) · lexicon.ts 🗂️ 정적 JSON 산출 menu-dict · food-graph · kit-matrix · 도감 · 체크포인트 📦 git 커밋 → Vercel 원자 배포 사전+코드가 한 커밋으로 · revert로 즉시 롤백 🌙 매일 새벽 2시 크론이 이 사전으로 소비 (여기서 처음 DB가 바뀜) 새 메뉴를 개선된 매퍼로 분해 → learned_menus 백필 · 코칭 편지 작성 (크론이 자동 WRITE)
입력은 읽기만, 스킬은 파일·코드만 고쳐 커밋, DB 변경은 배포 후 크론이 자동으로.
2

스킬의 목적 — 크론은 '적용', 스킬은 '개선'

메뉴→식재료 매핑 사전·식재료 도감·궁합 매트릭스는 전부 빌드에 박히는 정적 자산이다. 매일 도는 크론은 이 자산을 쓰기만 할 뿐 바꾸지 못한다(정적 import라 커밋+재배포가 필요하고, "이게 진짜 재료냐 오탐이냐 / 이 새 식재료가 영유아한테 안전하냐" 같은 사람 판단이 들어가야 한다). 그 자산 자체를 주기적으로 다듬어 정확도·범위를 올리는 게 이 스킬이다.

매일 자동

🌙 2시 크론

  • 이미 만든 사전·규칙대로 새 메뉴를 분해 → learned_menus 백필
  • 그 결과로 코칭 편지·질문·주간계획 작성
  • 런타임 데이터(DB)만 다룬다 — 사전 자체는 못 고침
  • 비유: 레시피북대로 매일 요리하는 요리사
사람이 부를 때

⚙️ 이 스킬

  • 사전·규칙·도감 자체를 더 똑똑하게 고쳐 쓴다
  • 빌드 산출물(정적 JSON)·코드를 재생성·개선
  • DB는 읽기 전용 — 커밋만 하고 끝
  • 비유: 가끔 와서 레시피북을 고치는 편집자
경계 한 줄: 크론이 소비하지만 스스로는 못 고치는 정적 자산(매핑·도감·매트릭스)을, 사람이 주기적으로 다듬어 정확도를 올리는 개선 루프가 이 스킬이다. 그래서 매 호출은 한 번에 끝나는 작업이 아니라 "실제 입력·코퍼스 성장을 보고 조금씩" 올린다.
3

주요 기능 — A0 → A → B → C

매 호출은 증분 정독(A0)으로 시작해, 매핑 사전(A) → 매트릭스(B) → 도감(C) 순으로 필요한 만큼만 손본다.

A0 · 증분 정독
체크포인트 이후 신규 유입 메뉴만 골라 분해 상태를 정독. 무매핑·누락(under-map)을 후보로 산출. 복합 메뉴(카레→닭고기 빠짐)의 누락 잡는 게 목적.
A · 매핑 사전 튜닝
흔한 메뉴+명확한 재료 → MENU_MAP, 표기변형 → LEXICON, 양념·물 → EXCLUDE. 오타·1회성은 사전화 금지(LLM 폴백에 맡김). 회귀검증 코퍼스 100% 유지.
B · 매트릭스 재생성
코퍼스가 충분히 컸을 때(+5% 또는 도감 변경) 궁합/사촌(food-graph)·통계(corpus-stats)를 다시 생성. 미달이면 "재생성 불필요"로 솔직히 스킵.
C · 도감 확장
새 식재료를 인터넷 조사 + 영유아 안전 스크린 → 통과하면 7파이프라인(풀·영양·💪배지·별등급·분량·제철·궁합) 자동 등재. 위험군은 보류·보고.
한 줄 원리: "실제 부모가 친 메뉴 + 부모가 고친 교정"이 가장 정확한 정답지다. 그걸 주기적으로 전역 사전·매트릭스·도감으로 승격시키는 게 이 스킬이다.
4

무엇을 읽고, 어떻게 가공하고, 어디에 저장하나

스킬의 DB 발자국은 읽기 전용 3테이블이 전부다. 가공 결과는 코드 2파일 + 정적 JSON 10종으로만 저장되며, DB INSERT/UPDATE/DELETE는 0건이다.

📥 읽는 것 (READ only)
  • learned_menus (DB) — 신규 유입 메뉴 증분 감지(menu, created_at만). ※ 스킬은 절대 쓰지 않음 — 쓰는 건 크론.
  • meal_logs (DB) — 부모가 입력한 끼니의 menus, ingredients를 보고 매핑 튜닝 후보 산출
  • user_menu_overrides (DB) — 부모가 고친 메뉴→식재료를 현재 전역 매핑과 대조(교정 충돌 = 전역 반영 후보)
  • 레시피·표준식단 소스 — young-recipes 90종, 농진청 성분, dietary4u 영유아 식단, NEIS 식판(권위 정답지)
  • 기존 정적 JSON — 도감 풀·food-graph·매트릭스를 읽어 갭·동시출현 산출
📥 DB 3 + 소스 (읽기) ⚙️ A0·A·B·C 가공 💻 코드 2🗂️ JSON 10 📦 커밋
📤 저장하는 것 (WRITE — 전부 파일·git, DB 아님)

💻 코드 사전 2

  • menuMapCore.tsMENU_MAP·EXCLUDE·boostFromName·meatFix
  • lexicon.ts — 표기변형 LEXICON

🗂️ 정적 JSON 10

  • menu-dict.json 0차 사전 · food-graph.json 궁합/사촌 · kit-dish-matrix.json
  • ingredients-light.json+enriched 도감 · must-eat·season·cooking-amounts·corpus-stats
  • foodmap-checkpoint.json 증분 기준선
그래서 "DB 튜플 영향 0". 매핑·도감을 고치는 일은 코드·JSON diff로 끝난다. DB가 바뀌는 건 배포 뒤 크론이 learned_menus를 백필하고 편지를 쓸 때이고, 그것도 크론이 자기 일로 자동 WRITE하는 것이지 스킬이 손대는 게 아니다. 과거 튜플을 소급해 다시 쓰지도 않는다(크론은 새 메뉴만).
5

결정론 매핑 파이프라인 — 정적 JSON과 코드가 LLM 앞을 막는다

메뉴 한 줄이 식재료로 분해되는 순서. 0~2차가 다 결정론(정적 JSON + 코드 사전)이라 대부분의 메뉴는 LLM 없이 즉시 풀린다. 0~2차가 전부 실패할 때만 3차 LLM이 마지막 수단으로 돈다 — 그 결과는 learned_menus에 적재돼 다음엔 무료 사전 히트가 된다.

메뉴 텍스트 입력 0차 DICT menu-dict.json 레시피 정확일치 1차 룰 MENU_MAP (코드) 정확일치 1b 부분일치 PARTIAL_KEYS 태그 흡수 2차 스캔+boost 코드 + 도감 vocab(JSON) 숨은 곡물·단백질 보정 meatFix 소고기 치환 ✓ 결과 식재료 배열 0~2차 전부 미스일 때만 ↓ 3차 LLM 폴백 (Claude Haiku · 서버) "확실치 않으면 빈배열·환각 금지" → 도감 vocab에 있는 것만 통과 learned_menus 적재 다음엔 무료 사전 히트 ※ 이 스킬이 키우는 건 0~2차 사전 — 결정론을 두껍게 해 비용·환각을 줄인다. learned_menus 적재는 크론/서버의 몫.
초록=정적 JSON · 파랑=코드 사전 · 네이비=코드 후처리 · 주황 점선=LLM(마지막 수단).
boostFromName은 독립 단계가 아니라 0·1·2차 모든 결정론 경로에 가산된다(wb() 래퍼). 그래서 카레 템플릿이 [감자,당근,양파]여도 메뉴명에 "닭살"이 있으면 닭고기가 붙고, 돼지감자·새우 같은 오탐은 가드 정규식이 막는다.
6

왜 테이블이 아니라 정적 JSON인가

핵심은 레퍼런스상태의 분리다. 매핑 사전·도감·매트릭스는 좀처럼 안 바뀌고, 빌드타임·클라에서 0ms로 읽혀야 하고, 바뀔 때 리뷰·롤백돼야 하는 레퍼런스다 → 정적 JSON. 반대로 사용자마다 매초 바뀌는 건 전부 DB 테이블이다.

정적 JSON = 레퍼런스

🗂️ 좀처럼 안 바뀜

  • 매핑 사전 · 도감 · 궁합 그래프 · 매트릭스
  • 이 스킬이 가끔 갱신하는 빌드 산출물
  • 빌드타임/엣지/클라 0ms 동기 읽기
  • git diff로 리뷰 · 원자 배포 · revert 롤백
DB 테이블 = 상태

📒 매초 바뀜

  • meal_logs 끼니 기록 · learned_menus 학습
  • user_menu_overrides · coach_letters · …
  • 사용자·날짜마다 변동 · RLS·service_role·RPC
  • 정적 사전이 못 푼 것만 런타임으로 흘림
1무네트워크·무지연 — 0ms 결정론 분해
사전은 정적 import라 빌드타임·엣지·클라 모두 동기로 즉시 읽힌다. 부모가 메뉴를 한 글자 칠 때마다 DB 왕복이 들어가면 입력 UX가 죽는데, care 기록 화면은 매퍼를 메모리에 잡고 네트워크 없이 즉석 분해한다.
menuMapCore.ts:13 — import MENU_DICT from './menu-dict.json' with {type:'json'} · app/care/page.tsx — createMapper(pool) "네트워크 없이 즉시 분해"
2클라 번들 분리 — 트리셰이킹으로 청크 제어
food-graph(156KB)·kit-matrix는 게터 안에서만 참조해 클라 번들에서 떨어져 나가고, 가벼운 menu-dict만 클라 코어에 들어간다. 정적 JSON이라 빌드 시점에 어느 청크에 실릴지 트리셰이킹으로 제어가 된다 — 런타임 DB라면 불가능.
foodGraph.ts:1-9 — "51KB 그래프를 클라 번들에 싣지 않으려는 의도" · graphSource.ts 정적 import 5종
3git 버전관리 — 리뷰·원자 배포·롤백
JSON이 전부 git-tracked라, 사전을 바꾸는 건 코드 diff로 리뷰되고, 새 사전+그걸 쓰는 코드가 한 커밋으로 원자 배포되며, 잘못되면 git revert 한 번으로 즉시 롤백된다. DB row였다면 마이그레이션·데이터 드리프트가 코드와 따로 놀아 "어느 시점 사전으로 이 편지가 나왔나"가 추적 불가.
git ls-files — menu-dict·food-graph·kit-dish-matrix·ingredients-light·corpus-stats 전부 tracked
4좀처럼 안 바뀌는 레퍼런스 — 빌드 산출물 ↔ 런타임 상태 경계
사전·그래프·도감은 사람이 검수하고 scripts/gen-*가 빌드 산출물로 한꺼번에 재생성하는 레퍼런스다. 유지보수 루프에서 가끔 갱신될 뿐 유저 요청마다 바뀌지 않는다. 빌드 산출물과 런타임 상태의 경계가 명확히 분리돼 있다.
scripts/gen-menu-dict.ts · gen-food-graph.py · gen-kit-matrix.py — 빌드 산출물 재생성(런타임 쓰기 아님)
5그래도 SQL이 필요할 때를 위한 단일 격리층이 이미 있음
graphSource.ts가 "데이터를 어디서 읽는가"만 한 겹으로 격리한다(L2 스냅샷 JSON 기본·동기 / L1 SQL opt-in COACH_GRAPH_SQL=1). 소비 함수는 byte 무변경이고 SQL이 빈약하면 JSON을 유지하는 safe-degrade. 정적 JSON 기본 + 실시간 복리가 필요한 추천만 선택적 SQL warm이라는 의도된 하이브리드 — "사전 자체는 정적이 정답"이라는 판단이 코드로 박제돼 있다.
graphSource.ts:1-21 — L2 JSON 기본 / L1 SQL opt-in · "추천 로직 그대로 · 데이터 어디서 읽는가만 격리 · safe degrade"
레퍼런스(좀처럼 안 바뀜·0ms·리뷰 가능)는 정적 JSON, 상태(매초 바뀜·사용자별)는 DB 테이블. 이 스킬은 앞쪽을 다듬고, 크론은 양쪽을 써서 뒤쪽을 채운다.
7

안전 — 도감 자동 등재의 절대 우회 금지선

도감 식재료 추가는 사람 승인 게이트를 없앴지만(2026-06-13), 영유아 안전 스크린만은 절대 우회하지 않는다. 내가 인터넷 조사로 실존·정체·영양을 확인하고, 안전 스크린을 통과한 것만 자동 등재한다.

✅ 통과 → 자동 등재

  • 안전·실존·영유아 적합한 실재료
  • 7파이프라인 전배선(풀·영양·💪배지·별등급·분량·제철·궁합)
  • 흔하고 영양 우수면 💎, 아니면 일반

⛔ 위험군 → 보류·보고

  • 질식(곤약·문어·통대추) · 보툴리누스(꿀)
  • 고나트륨·한방 부적합(인삼·함초) · 비타민A 과잉(장어)
  • "실존 식재료라도 영유아 부적합이면 절대 자동 등재 X"
매핑에서도 같은 원칙이 작동한다. 메뉴명에 한방 재료가 박혀 있어도 무시되고 안전한 베이스만 매핑된다 — 예: 인삼닭곰탕·황기닭곰탕[닭고기,무,대파](인삼·황기는 도감에도 안 들어가고 추천에도 안 뜸), 함초삼겹[돼지고기]. 제3자(아이)를 보호하는 게 안전 우회 금지의 이유다.
밀프레드 — 코퍼스·도감 유지보수 스킬 작동 원리 · 2026-06-17 · 코드 근거 검증(5에이전트) 기반 · 문서 허브