코칭엔진은 graphSource.ts 한 모듈로 JSON import을 격리한다 → 소비 함수(strongPairsOf·scoreCombo·rankIngredients)는 byte 무변경. 데이터 세션이 그 뒤를 JSON→SQL로 바꿔도 엔진은 그대로 돌고, 추천이 매일 누적된 사촌 그래프로 실시간 복리된다.
왜 — 빌드 lag 제거 + 복리
지금 추천 네트워크는 빌드 JSON이라 "빌드 돌려야만" 갱신된다. SQL로 옮겨 부모 입력이 매일 동시출현으로 누적되게(복리) + 비도감 식재료(아귀 등)도 사촌 다리가 되게 한다.
추천 '알고리즘'은 안 바뀐다 — '데이터 출처'만 바뀐다. 식재료↔식재료 사촌/궁합(ingredient_edges)·음식×식재료(dish_ingredient_stats)가 SQL에서 매일 누적되면, 푸드체이닝(잘 먹는 것 → 닮은 새 식재료)이 빌드 없이 저절로 촘촘해진다. 예: 감자·돈까스 좋아하는 아이 → 단호박(감자 사촌·비타민A) 크로켓 + 생선까스(튀김 전이·생선 갭) 도출이 매일 정밀해짐.
7테이블 모델 (데이터 세션이 DDL·이관·스냅샷 담당)
ingredients가 허브(원천 registry) — 나머지가 전부 이걸 참조. 영양은 ingredients.nong_code → nong_foods JOIN(중복 X).
관계: ingredients = 허브. dogam·ingredient_edges·dish_ingredient_stats·learned_menus 전부 ingredients 참조. 추천 노드 자격 = ingredients(전체) · 치료 타깃 = dogam(부분집합) — 푸드체이닝은 ingredients 위에서.
⭐ 캐시 아키텍처 — 3층
엔진엔 동기 경로(클라/SSG: 도감 페이지 PersonalBridge)와 비동기 경로(크론 편지)가 둘 다 있다. 순수 라이브 SQL은 동기 경로를 깨므로 3층으로 간다.
SQL
원천 (매일 누적)
ingredient_edges·dish_ingredient_stats·ingredients·dogam. 부모 입력 → 동시출현 누적 = 복리.
스냅샷
야간 스냅샷 JSON (현 JSON과 '동일 shape')
SQL → public/food-graph.json·kit-dish-matrix.json export. 파일이 'gen 스크립트 산출'에서 'SQL export'로 바뀔 뿐 경로·shape 동일 → 클라/SSG/동기 import는 무변경.
인메모리
서버 인메모리 캐시 + 폴백
크론/API는 모듈 로드 시 1회 적재(현 foodGraph ADJ Map 패턴 그대로) + 선택적 SQL 직접 read(라이브). + affinity_cache(이미 SQL) = 스냅샷에 없는 조합 런타임 폴백.
graphSource 계약 (코칭엔진 세션의 핵심 작업)
JSON import을 직접 하지 말고 데이터 액세스 모듈 한 겹 뒤로 숨겨라. 그러면 SQL 전환 시 이 모듈 내부만 바뀌고 엔진 전체 무변경(1파일 격리).
// 신규 lib/graphSource.ts — 반환 shape = 현 JSON shape (이게 두 세션의 접점 계약) export function getEdges(): RawEdge[] // food-graph.json 동일 shape (스냅샷 or SQL) export function getDishMatrix(): KitMatrix // kit-dish-matrix.json 동일 shape export function getIngredient(nm): { nong, nutri, grade, ... } // 그러면 소비 모듈은 'import json' → 'graphSource.getX()' 한 줄만 교체: // foodGraph.ts / comboMatrix.ts / kitGuide.ts / nutrition.ts // 소비 함수(strongPairsOf·scoreCombo·rankIngredients)는 byte 무변경. 추천 로직 안 건드림. // graphSource 내부(스냅샷 JSON ↔ SQL ↔ 캐시 TTL)는 데이터 세션과 함께 확정.
너가 '지금' 준비할 것 (SQL 생기기 전 선제)
- (a) 아래 5개 JSON import을
graphSource.ts한 모듈로 모아 추상화(지금은 그 안에서 기존 JSON 그대로 import) → 전환 시 1파일만 바뀜. - (b)
selectDailyMaterials가meal_logs의 아이별 선호 강도(ate_well 빈도·거부)를 랭킹에 직접 쓰도록 입력 계약 정리 — 전환 후 ingredient_edges(전역) × meal_logs(개인선호) × nong_foods(갭) 결합이 핵심. - (c) freqMap(
ingredient-recipes.json)도 graphSource 경유로 통일(크론 fetch도 여기로).
현재 읽기 경로 (실측 — 정확히 이걸 graphSource로 격리)
import './food-graph.json' — edges(a,b,kind,lift,grade,strength,count,src,verified,tray) · 동기import './kit-dish-matrix.json' — dishes,cells,scores · 동기import './kit-dish-matrix.json' · 동기import './nutrient-map.generated.json' · 동기import '@/public/ingredients-light.json' · 동기fetch('/ingredients-light.json') · 런타임fetch('/ingredient-recipes.json') (freqMap) · 런타임소비 함수 계약(★시그니처·반환 shape 불변): neighborsOf·strongPairsOf·verifiedCousinsOf·scoreCombo·isComboOk·dishesForIngredient·popularDishesFor·pickFoodReco·buildRecoFacts·selectDailyMaterials.
분담 — 접점은 graphSource 반환 shape
🟠 데이터/SQL 세션 (나)
- DDL 4종(
ingredients·dogam·ingredient_edges·dish_ingredient_stats) - 기존 JSON → SQL 이관 스크립트
- 야간 스냅샷 export job(SQL → 동일 shape JSON)
- 분해 검증을
CANON_VOCAB(도감) →nong_foods(유니버스)로 확장 - 크론 신규 식재료 자동 INSERT into ingredients
🟣 코칭엔진 세션 (너)
graphSource.ts추상화 신설- foodGraph/comboMatrix/kitGuide/nutrition의 import → graphSource 교체
selectDailyMaterials의 meal_logs 개인선호 결합- 소비측 테스트 green 유지(835)
접점 = graphSource.ts의 반환 shape(= 현 JSON shape). 이걸 계약으로 고정하고 각자 양쪽을 맞춘다.
불변 계약 · 하지 말 것
✅ 절대 불변
소비 함수 시그니처·반환 shape · RawEdge 필드명(a,b,kind,strength,lift,grade,count,src,verified,tray) · PAIR_MIN_STRENGTH=2 · CELLS_MIN=8 · lift 임계(strong 1.2/med 1.0)·grade 의미 · 괴식/환각 가드(strongPairsOf만 추천·validatedCombos≥1·미역국+당근 차단·떡+달걀 weak) · 835 테스트 green · '재료=결정론·문장=LLM 자유'.
- 추천 알고리즘/임계/가드를 'SQL 전환 김에' 바꾸지 마라 — 데이터 출처만 바꾼다. 로직 변경은 별건.
- JSON import을 여기저기서 직접 하지 마라 — 반드시 graphSource 경유(전환 시 누락 방지).
- dogam과 ingredients를 혼동 마라 — 노드 자격=ingredients(전체), 치료 타깃=dogam(부분집합). 푸드체이닝은 ingredients 위.
- 스냅샷 shape을 현 JSON과 다르게 만들지 마라 — 테스트·동기경로 다 깨짐. 필드 추가는 OK, 기존 필드명/구조 변경 금지.
- 영양을 dogam에 중복 저장 마라 — ingredients.nong_code → nong_foods JOIN.
작업 순서
- graphSource.ts 추상화(현 JSON 그대로 감싸기) 코칭세션 — 즉시 가능, SQL 무관
- DDL 4종 작성 → 이사님이 Supabase에서 실행 데이터세션이사님 실행
- JSON → SQL 이관 스크립트(ingredients 먼저 → dogam FK → edges/stats) 데이터세션
- 야간 스냅샷 export job(SQL → 동일 shape JSON) + graphSource를 스냅샷/SQL로 스위치 데이터세션코칭세션
- 분해 검증 nong_foods로 확장 + 크론 자동 INSERT into ingredients 데이터세션
- selectDailyMaterials 개인선호 결합 + 835 테스트 green 확인 → 컷오버 코칭세션
스냅샷이 현 JSON과 동일 shape이면 — 컷오버는 "JSON 생성 주체가 gen 스크립트 → SQL export로 바뀌는 것"뿐이라 엔진·테스트 무영향. 동기 경로는 스냅샷, 비동기(크론)는 SQL 직접, 누락은 affinity_cache 폴백. 단계별로 롤백 가능(스냅샷을 옛 gen 산출로 되돌리면 즉시 원복).