{
  "id": "95909480-b423-4435-836a-6bec07de18ff",
  "slug": "ref/khub/geocare-t-auto-inject-unified-v1-json-ld-자동-송출-통합-트랙-골격-g0-대기",
  "doc_type": "ref",
  "title": "📋 T-AUTO-INJECT-UNIFIED-v1 — JSON-LD 자동 송출 통합 트랙 (골격, G0 대기)",
  "title_en": null,
  "one_liner": "# 📋 T-AUTO-INJECT-UNIFIED-v1 — JSON-LD 자동 송출 통합 트랙 > 작성: 2026-05-08 KST | 상태: 🛑 **G0 대기 (발동 ❌)** > 양 방 공동 트랙 (GEOCARE + PREMIUM_GEO) > 짝 표준: STD-JSONLD-UNIFI",
  "summary_bullets": [],
  "body_md": "# 📋 T-AUTO-INJECT-UNIFIED-v1 — JSON-LD 자동 송출 통합 트랙\n\n> 작성: 2026-05-08 KST | 상태: 🛑 **G0 대기 (발동 ❌)**\n> 양 방 공동 트랙 (GEOCARE + PREMIUM_GEO)\n> 짝 표준: STD-JSONLD-UNIFIED v0.1 (본 문서 §6에 인라인) / 호출 표준: schema.geocare.ai 호출 v1.0 (별도 KHub 등재)\n> 정본 근거: BMP 정책 v1.0 (`866eb3de`) + Phase D DevLog (`0c006e31`) + 본 세션 분석\n\n---\n\n## 0. 한 문장 정의\n\n**3계열(sitegeo/brandgeo/ocr) JSON-LD를 단일 SSOT(`bmp_jsonld_delivery`)로 통합 + 인증·자동화·관측을 양 방 공동 트랙으로 6주+2주 안정화 완성.**\n\n---\n\n## 1. ⚠️ G0 발동 조건 (5건 모두 충족 시 진입)\n\n| # | 조건 | 현 상태 | 책임 |\n|---|---|---|---|\n| 1 | **T-RENEW-GEOCARE-BMP v1.1 보강권고 회신** | 🛑 대기 | 구자훈 대표 (Asana `1214608078467144` 코멘트 회신) |\n| 2 | **양 PO 미팅** (찰스 + 구자훈) | 미정 | 1번 회신 후 일정 합의 |\n| 3 | **두 방 책임 분담 합의** (GEOcare 영역 vs BMP 영역 라인) | 미정 | 미팅 결과 |\n| 4 | **Phase D DevLog v3.0 갱신** (PREMIUM_GEO 단독 작업) | 미정 | 3번 후 PREMIUM_GEO 측 진행 |\n| 5 | **STD-JSONLD-UNIFIED 정본 합의 (v1.0)** | v0.1 본 문서 § | 1~4 후 양 방 합의 |\n\n→ **5건 중 1건이라도 미충족 시 본 트랙 발동 ❌**.\n→ G0 미충족 상태에서 부분 작업(예: gp_geoex_inject_keys 단독 DDL) **금지** — 6주 후 합의 결과로 폐기 가능성 ↑.\n\n---\n\n## 2. 배경 — 본 트랙 신설 사유\n\n### 2.1 발견 (5/8 본 세션)\n- 3계열 JSON-LD 생성/저장 영역이 **완전 분리** 사일로:\n  - sitegeo (`gp_geoex_jsonld_log`): 701건, Schema Builder UI, 사용자 직접 입력\n  - brandgeo (`bmp_jsonld_delivery`): 16건, Phase D 어드민 수동 트리거, EEAT와 무관\n  - ocr (`gp_geoex_ocr_results`): 483건, schema 변환 미완 (raw text + jsonb만)\n- `bmp_jsonld_delivery`가 자동 송출 SSOT (`geobh-jsonld` EF v2 우선 조회)\n- 단, 자동 스케줄 미작동 (last_batch_at 모두 NULL)\n- OCR → schema 변환 파이프라인 부재\n- luvhunter PoC 시 적용할 데이터 0건\n\n### 2.2 본 트랙의 필연성\nT-RENEW-GEOCARE-BMP v1.1 보강권고가 GEOcare ↔ BMP 기능 재배치를 다루는데, **JSON-LD 영역이 정확히 그 사이의 모호 지대**. 본 트랙은 T-RENEW의 데이터 흐름 측면 정합 작업.\n\n### 2.3 5/11 luvhunter PoC와의 분리\n- 5/11 시연 자산 = Brand Hub 3중 안전망 (이미 라이브, 변경 ❌)\n- 5/11 시연 메시지 추가: \"자동 송출 정식 트랙 6주+2주 진행 — 계약 사인 시 luvhunter 우선 적용 사이트 1호 등록\"\n- **본 트랙 발동은 5/11 후 + G0 충족 시점**\n\n---\n\n## 3. 6 Phase 구조 (총 6주 + 안정화 2주)\n\n### Phase 1 — 인증 인프라 + Phase D 인증 통합 (1.5주)\n\n**GEOcare 영역**:\n- `gp_geoex_inject_keys` 신규 테이블 (인증 SSOT)\n- `verify_geoex_inject_key` RPC (3중 검증: 키·만료·Origin)\n- 메모리 캐시 정책 (60초 TTL, EF 측)\n\n**BMP 영역 (PREMIUM_GEO 작업)**:\n- `geobh-jsonld` EF v3 패치 — 인증 헤더 검증 + 3단계 fallback 유지\n- jsonld-serve `/api/jsonld-serve` 인증 통합\n- 어드민 UI 토큰 발급/관리 화면 (`bmp.ai/admin` PDP 탭 확장)\n\n**검증**: 토큰 검증 부하 + Origin 화이트리스트 + 만료/재발급/폐기 시나리오\n\n### Phase 2 — Phase D 자동화 부활 (1주)\n\n**PREMIUM_GEO 작업**:\n- PDP-SCHED (`s5JaX2zYy2RU2fkt`) 자동 스케줄 미작동 원인 추적 + 수정\n- Webhook/Schedule 트리거 패턴 재정립 (`bmp_jsonld_sites.is_pdp_enabled`)\n- 24h/12h 스케줄 실 작동 검증\n- 갱신 정책 표준 (사용자 변경 트리거 vs 정기)\n- last_batch_count·errors Telegram 알림\n\n### Phase 3 — OCR → schema 변환 파이프라인 (2주) ⭐ 핵심 차별화\n\n**GEOcare 영역**:\n- HITL 검수 후 `gp_geoex_ocr_review` 통과 row만 변환 대상\n- 신규 WF: `[Phase D-OCR] OCR-to-Schema Pipeline` 신설\n  - `lifestyle/model_wearing/product_only` → Product image[] 보강\n  - `detail_text/spec_table` → Product description + additionalProperty\n  - `care_guide/care_instruction` → HowTo 신규\n  - `infographic` → FAQPage 신규\n  - `size_chart` → PropertyValue\n- LLM 변환 비용 추적 (OCR raw → Gemini/GPT)\n\n**BMP 영역**:\n- `bmp_jsonld_delivery.source = 'ocr'` row 추가 (정책: 별도 row vs array merge — Phase 3 진입 시 결정)\n- 우선순위 merge 정책 (extracted > generated > ocr 또는 통합)\n\n### Phase 4 — sitegeo 통합 + 데이터 정합 (1주)\n\n**GEOcare 영역**:\n- `gp_geoex_jsonld_log` → `bmp_jsonld_delivery` 마이그 정책 결정\n  - 옵션 A: 모두 마이그 후 deprecated (단일 SSOT)\n  - 옵션 B: 사용자 직접 입력 이력은 영구 보존, 운영 송출만 bmp 활용 (권장)\n- `gp_geoex_jsonld_log.site_domain` 정규화 (`https://...` 제거)\n- WebSite/Organization/WebPage/BreadcrumbList → bmp 적재 시 `source='sitegeo'`\n\n**검증**: 이바나 사례 (sitegeo 8 + brandgeo 12 + ocr 216 → 통합 결과 측정)\n\n### Phase 5 — 관측·운영·알림 (1주)\n\n**BMP 영역 (어드민 UI 확장)**:\n- 호출량 dashboard 신규 탭\n- Rate Limit 실 적용 (현재 컬럼만 존재, 작동 ❌)\n- 운영 알림 표준 (delivery 갱신 실패 / 인증 실패 폭증 등)\n- A/B 테스트 인프라 활용 (`bmp_jsonld_ab_tests`)\n- 비용 추적 (Vision GPT-4o · GPT 생성 fallback · OCR 변환)\n\n### Phase 6 — 공식 표준화 + 외부 통보 (0.5주)\n\n**양 방 공동**:\n- STD-JSONLD-UNIFIED v1.0 정본 KHub 등재 (양 방 동시)\n- 11줄 PHP 코드 v1.0 정식 발표 (라이브러리화 검토)\n- 운영 매뉴얼 작성 (어드민/파트너용)\n- 학습 #17~#22 KHub 일괄 등재\n- 외부 통보 (옥경화 상무 → 러브헌터 등 적용 사이트)\n\n### 안정화 (2주)\n- 내부 dogfooding (bizspring.co.kr · growthplatform.ai 직접 적용)\n- 첫 외부 사이트 1건 적용 (luvhunter 또는 medicube)\n- 부하·장애·롤백 드릴\n- 🔍 VERIFIED → 본 트랙 종결\n\n---\n\n## 4. 영역 격벽 매트릭스\n\n| 작업 | 영역 | 책임 |\n|---|---|---|\n| `gp_geoex_inject_keys` 테이블/RPC | GEOcare 단독 | 본 방 |\n| OCR → schema 변환 파이프라인 | GEOcare 단독 | 본 방 |\n| `gp_geoex_jsonld_log` 정규화/마이그 | GEOcare 단독 | 본 방 |\n| `bmp_jsonld_delivery` source/install_method 표준 | BMP 단독 | PREMIUM_GEO 방 |\n| `geobh-jsonld` EF v3 패치 | BMP 단독 | PREMIUM_GEO 방 |\n| jsonld-serve EF 패치 | BMP 단독 | PREMIUM_GEO 방 |\n| PDP-SCHED 자동 스케줄 부활 | BMP 단독 | PREMIUM_GEO 방 |\n| 어드민 UI (PDP 탭 확장) | BMP 단독 | PREMIUM_GEO 방 |\n| OCR 변환 결과 → bmp 적재 정책 | **양 방 합의** | 공동 |\n| Phase 6 정본 표준 등재 | **양 방 공동** | 공동 |\n\n---\n\n## 5. 본 세션(2026-05-08) 산출물 — 본 트랙 자료로 보존\n\n| 자산 | 위치 | 용도 |\n|---|---|---|\n| schema.geocare.ai DNS 등록 ✅ | 후이즈 + Supabase ENABLED | 본 트랙 호출 도메인 (즉시 활용) |\n| schema.geocare.ai 호출 표준 v1.0 | 별도 KHub 문서 | 본 트랙 Phase 1 직접 활용 |\n| 3계열 schema 분석 (701/16/483건) | 본 문서 §2.1 | Phase 4 통합 근거 |\n| 4/1 이바나 12건 timestamp 시퀀스 | 본 문서 §2.1 | Phase 2 자동 스케줄 부활 근거 |\n| `gp_geoex_inject_keys` v0.1 스키마 | 본 문서 §6.1 | Phase 1 GEOcare 작업 진입점 |\n| `verify_geoex_inject_key` RPC v0.1 | 본 문서 §6.2 | Phase 1 GEOcare 작업 진입점 |\n| 11줄 PHP 코드 v1.3 (luvhunter) | 본 문서 §6.3 | Phase 6 정식 발표 직전 검토 후보 |\n\n⛔ DDL/INSERT 미실행 — G0 충족 후 Phase 1 정식 진입 시점에 양 방 합의 후 적용.\n\n---\n\n## 6. 본 세션 G1 설계 자산 (Phase 1 진입 시 검토 후보)\n\n### 6.1 `gp_geoex_inject_keys` v0.1 (Phase 1 검토)\n\n```sql\nCREATE TABLE gp_geoex_inject_keys (\n  id                    uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n  api_key               text UNIQUE NOT NULL,\n  client_code           text UNIQUE NOT NULL,\n  site_domain           text NOT NULL,\n  display_name          text,\n  permissions           text[] DEFAULT ARRAY['inject']::text[],\n  allowed_origins       text[],\n  rate_limit_per_hour   integer DEFAULT 10000,\n  is_active             boolean DEFAULT true,\n  expires_at            timestamptz,\n  last_used_at          timestamptz,\n  metadata              jsonb,\n  created_at            timestamptz NOT NULL DEFAULT now(),\n  updated_at            timestamptz NOT NULL DEFAULT now(),\n  CONSTRAINT chk_api_key_prefix CHECK (api_key ~ '^[a-z]{2,5}_[a-zA-Z0-9]{24,64}$'),\n  CONSTRAINT chk_client_code_format CHECK (client_code ~ '^[A-Z][A-Z0-9_]{2,30}$'),\n  CONSTRAINT chk_site_domain_format CHECK (site_domain ~ '^[a-z0-9.-]+\\.[a-z]{2,}$')\n);\n\nCREATE UNIQUE INDEX idx_inject_keys_api_key_active ON gp_geoex_inject_keys (api_key) WHERE is_active = true;\nCREATE INDEX idx_inject_keys_origins ON gp_geoex_inject_keys USING GIN (allowed_origins);\nCREATE INDEX idx_inject_keys_expires ON gp_geoex_inject_keys (expires_at) WHERE is_active = true AND expires_at IS NOT NULL;\nCREATE INDEX idx_inject_keys_client_code ON gp_geoex_inject_keys (client_code);\n\nALTER TABLE gp_geoex_inject_keys ENABLE ROW LEVEL SECURITY;\nCREATE POLICY no_direct_access ON gp_geoex_inject_keys FOR ALL USING (false) WITH CHECK (false);\n```\n\n→ 패턴 근거: `gp_mcp_api_keys` (GEOcare MCP 인증) + BIZDATA `de_unified_client.api_key` 합성.\n\n### 6.2 `verify_geoex_inject_key` RPC v0.1 (Phase 1 검토)\n\n```sql\nCREATE OR REPLACE FUNCTION verify_geoex_inject_key(\n  p_api_key text,\n  p_origin text DEFAULT NULL,\n  p_request_url text DEFAULT NULL\n)\nRETURNS TABLE(\n  is_valid boolean,\n  client_code text,\n  site_domain text,\n  permissions text[],\n  metadata jsonb,\n  failure_reason text\n)\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n  v_row gp_geoex_inject_keys%ROWTYPE;\nBEGIN\n  SELECT * INTO v_row FROM gp_geoex_inject_keys\n  WHERE api_key = p_api_key AND is_active = true LIMIT 1;\n  \n  IF NOT FOUND THEN\n    RETURN QUERY SELECT false, NULL::text, NULL::text, NULL::text[], NULL::jsonb, 'key_not_found_or_inactive'::text;\n    RETURN;\n  END IF;\n  \n  IF v_row.expires_at IS NOT NULL AND v_row.expires_at < now() THEN\n    RETURN QUERY SELECT false, v_row.client_code, v_row.site_domain, NULL::text[], NULL::jsonb, 'key_expired'::text;\n    RETURN;\n  END IF;\n  \n  IF v_row.allowed_origins IS NOT NULL AND array_length(v_row.allowed_origins, 1) > 0 AND p_origin IS NOT NULL THEN\n    IF NOT (p_origin = ANY(v_row.allowed_origins)) THEN\n      RETURN QUERY SELECT false, v_row.client_code, v_row.site_domain, NULL::text[], NULL::jsonb, 'origin_not_allowed'::text;\n      RETURN;\n    END IF;\n  END IF;\n  \n  UPDATE gp_geoex_inject_keys SET last_used_at = now() WHERE id = v_row.id;\n  \n  RETURN QUERY SELECT true, v_row.client_code, v_row.site_domain, v_row.permissions, v_row.metadata, NULL::text;\nEND;\n$$;\n\nGRANT EXECUTE ON FUNCTION verify_geoex_inject_key(text, text, text) TO anon, authenticated, service_role;\n```\n\n### 6.3 11줄 PHP 코드 v1.3 (Phase 6 정식 발표 직전 검토)\n\n```php\n<!-- GEOcare JSON-LD Auto-Inject (비즈스프링) -->\n<?php\n$_g_url = 'https://www.luvhunter.net' . $_SERVER['REQUEST_URI'];\n$_g_cache = sys_get_temp_dir() . '/gc_' . md5($_g_url);\nif (!file_exists($_g_cache) || time() - filemtime($_g_cache) > 3600) {\n    $_g_ctx = stream_context_create(['http' => ['timeout' => 2, 'header' => 'X-GEOcare-Key: lvh_xxxxxxxxxxxxxxxxxxxxxxxx']]);\n    $_g_res = @file_get_contents('https://schema.geocare.ai/functions/v1/geobh-jsonld?url=' . urlencode($_g_url), false, $_g_ctx);\n    if ($_g_res) @file_put_contents($_g_cache, $_g_res);\n}\nif (file_exists($_g_cache)) echo '<script type=\"application/ld+json\">' . file_get_contents($_g_cache) . '</script>';\n?>\n```\n\n→ 적용 위치: `_inc_index_header.tpl` 188~189행 사이 (`</head>` 직전).\n\n---\n\n## 7. 후속 트랙 시드 (본 트랙에서 분기 가능성)\n\n| 후속 트랙 | 시점 | 책임 |\n|---|---|---|\n| `T-PIPELINE-OCR-TO-SCHEMA-FULLAUTO` | Phase 3 종결 후 풀자동화 | GEOcare |\n| `T-MIGRATION-SITEGEO-LEGACY` | Phase 4 후속 (gp_geoex_jsonld_log 거취 결정) | GEOcare |\n| `T-OPS-AUTO-INJECT-MULTISITE` | 안정화 후 다수 사이트 적용 | 양 방 공동 |\n| `T-MARKETING-AUTO-INJECT-LAUNCH` | 안정화 후 영업 메시지 | SALES + GEOCARE |\n\n---\n\n## 8. 학습 누적 (Phase 6 일괄 등재 후보)\n\n| # | 가칭 |\n|---|---|\n| 17 | 외부 EF 활용 코드 제안 시 인증 모델 단정 금지 |\n| 18 | 가칭 자산명 자연 노출 금지 |\n| 19 | 인벤토리 미확인 상태로 신규 테이블 설계 금지 |\n| 20 | 동일 명칭 테이블 발견 시 용도 검증 필수 |\n| 21 | 신규 인프라 설계 시 인증·데이터·실행 3축 동시 확인 |\n| 22 | 외부 변수(영업 일정) 압박 시 PO에게 명시적 환기 요청 |\n\n→ 본 트랙 Phase 6 종결 시 KHub COMMON 일괄 등재.\n\n---\n\n## 9. 새 세션 진입 명령\n\n### 트리거 발화\n- **\"T-AUTO-INJECT-UNIFIED 이어서\"** → 본 문서 로드 + G0 5건 상태 점검\n- **\"T-RENEW v1.1 회신 왔어\"** → G0 #1 충족 → #2 일정 합의 진입\n- **\"양 PO 미팅 결과\"** → G0 #2~#3 진입\n- **\"Phase 1 진입\"** → G0 충족 시점 + 양 방 합의 시 발동\n- **\"본 트랙 종결\"** → 사양 폐기 또는 다른 트랙으로 흡수 시\n\n### 본 트랙 발동 전 새 세션 작업 우선순위 (높→낮)\n1. **자동 패치 사후 검토 6건** (5/7 17:00 SLA D-1)\n2. **BUG-002 G3 재검증** (PREMIUM_GEO 처리 후, SLA 5/9 EOD)\n3. **나이스페이 회신 메일** (P0-3, AP-25)\n4. **T-EEAT-LLM-FAIL** 트랙 신설 (2,959건 score=0)\n5. **5/11 미팅 준비** (KHub `d00aceea` + bmp.ai 5종 + 어드민 시연)\n6. **T-RENEW v1.1 회신 모니터링** (구자훈 대표)\n7. T-SALES-MPRD-UPSELL Phase 1 메시지 본문 컨펌\n\n---\n\n## 10. 변경 이력\n\n| 일자 | 버전 | 변경 |\n|------|------|------|\n| 2026-05-08 | v1.0 (골격) | 초판 — G0 대기 상태로 등재. Phase 1~6 + 안정화 골격. 본 세션 산출물 보존. T-RENEW v1.1 회신 후 발동. |\n",
  "related_slugs": [],
  "faq": [],
  "jsonld": null,
  "keywords": [],
  "source_id": "46fdc824-9e87-4348-ba34-737a2545e83e",
  "video_url": null,
  "duration_sec": null,
  "thumbnail_url": null,
  "image_url": null,
  "caption": null,
  "solution_slug": null,
  "captured_at": null,
  "width": null,
  "height": null,
  "created_at": "2026-08-24T11:53:44.684733+00:00",
  "updated_at": "2026-08-24T11:53:44.684733+00:00",
  "visibility": "public",
  "source_stage": "1",
  "anonymized": true,
  "source_key": "legacy-khub",
  "origin": "ingest",
  "locked": false,
  "locked_by": null,
  "locked_at": null,
  "gate_state": {
    "g1": {
      "hits": [],
      "pass": true
    },
    "g2": {
      "pass": true,
      "total": 43,
      "issues": [
        "숫자·규격 같은 검증 가능한 구체가 부족합니다",
        "핵심 요약 불릿이 3개 미만입니다",
        "Q&A 쌍이 3개 미만입니다"
      ],
      "applies": true
    },
    "g3": {
      "pass": true,
      "required": false
    },
    "stage": "1",
    "decided_at": "2026-08-24T11:53:44.334Z"
  },
  "raw_id": "74d7af9e-f388-4c21-8934-5e350c50e249",
  "search_text": "📋 T-AUTO-INJECT-UNIFIED-v1 — JSON-LD 자동 송출 통합 트랙 (골격, G0 대기)  # 📋 T-AUTO-INJECT-UNIFIED-v1 — JSON-LD 자동 송출 통합 트랙 > 작성: 2026-05-08 KST | 상태: 🛑 **G0 대기 (발동 ❌)** > 양 방 공동 트랙 (GEOCARE + PREMIUM_GEO) > 짝 표준: STD-JSONLD-UNIFI  # 📋 T-AUTO-INJECT-UNIFIED-v1 — JSON-LD 자동 송출 통합 트랙\n\n> 작성: 2026-05-08 KST | 상태: 🛑 **G0 대기 (발동 ❌)**\n> 양 방 공동 트랙 (GEOCARE + PREMIUM_GEO)\n> 짝 표준: STD-JSONLD-UNIFIED v0.1 (본 문서 §6에 인라인) / 호출 표준: schema.geocare.ai 호출 v1.0 (별도 KHub 등재)\n> 정본 근거: BMP 정책 v1.0 (`866eb3de`) + Phase D DevLog (`0c006e31`) + 본 세션 분석\n\n---\n\n## 0. 한 문장 정의\n\n**3계열(sitegeo/brandgeo/ocr) JSON-LD를 단일 SSOT(`bmp_jsonld_delivery`)로 통합 + 인증·자동화·관측을 양 방 공동 트랙으로 6주+2주 안정화 완성.**\n\n---\n\n## 1. ⚠️ G0 발동 조건 (5건 모두 충족 시 진입)\n\n| # | 조건 | 현 상태 | 책임 |\n|---|---|---|---|\n| 1 | **T-RENEW-GEOCARE-BMP v1.1 보강권고 회신** | 🛑 대기 | 구자훈 대표 (Asana `1214608078467144` 코멘트 회신) |\n| 2 | **양 PO 미팅** (찰스 + 구자훈) | 미정 | 1번 회신 후 일정 합의 |\n| 3 | **두 방 책임 분담 합의** (GEOcare 영역 vs BMP 영역 라인) | 미정 | 미팅 결과 |\n| 4 | **Phase D DevLog v3.0 갱신** (PREMIUM_GEO 단독 작업) | 미정 | 3번 후 PREMIUM_GEO 측 진행 |\n| 5 | **STD-JSONLD-UNIFIED 정본 합의 (v1.0)** | v0.1 본 문서 § | 1~4 후 양 방 합의 |\n\n→ **5건 중 1건이라도 미충족 시 본 트랙 발동 ❌**.\n→ G0 미충족 상태에서 부분 작업(예: gp_geoex_inject_keys 단독 DDL) **금지** — 6주 후 합의 결과로 폐기 가능성 ↑.\n\n---\n\n## 2. 배경 — 본 트랙 신설 사유\n\n### 2.1 발견 (5/8 본 세션)\n- 3계열 JSON-LD 생성/저장 영역이 **완전 분리** 사일로:\n  - sitegeo (`gp_geoex_jsonld_log`): 701건, Schema Builder UI, 사용자 직접 입력\n  - brandgeo (`bmp_jsonld_delivery`): 16건, Phase D 어드민 수동 트리거, EEAT와 무관\n  - ocr (`gp_geoex_ocr_results`): 483건, schema 변환 미완 (raw text + jsonb만)\n- `bmp_jsonld_delivery`가 자동 송출 SSOT (`geobh-jsonld` EF v2 우선 조회)\n- 단, 자동 스케줄 미작동 (last_batch_at 모두 NULL)\n- OCR → schema 변환 파이프라인 부재\n- luvhunter PoC 시 적용할 데이터 0건\n\n### 2.2 본 트랙의 필연성\nT-RENEW-GEOCARE-BMP v1.1 보강권고가 GEOcare ↔ BMP 기능 재배치를 다루는데, **JSON-LD 영역이 정확히 그 사이의 모호 지대**. 본 트랙은 T-RENEW의 데이터 흐름 측면 정합 작업.\n\n### 2.3 5/11 luvhunter PoC와의 분리\n- 5/11 시연 자산 = Brand Hub 3중 안전망 (이미 라이브, 변경 ❌)\n- 5/11 시연 메시지 추가: \"자동 송출 정식 트랙 6주+2주 진행 — 계약 사인 시 luvhunter 우선 적용 사이트 1호 등록\"\n- **본 트랙 발동은 5/11 후 + G0 충족 시점**\n\n---\n\n## 3. 6 Phase 구조 (총 6주 + 안정화 2주)\n\n### Phase 1 — 인증 인프라 + Phase D 인증 통합 (1.5주)\n\n**GEOcare 영역**:\n- `gp_geoex_inject_keys` 신규 테이블 (인증 SSOT)\n- `verify_geoex_inject_key` RPC (3중 검증: 키·만료·Origin)\n- 메모리 캐시 정책 (60초 TTL, EF 측)\n\n**BMP 영역 (PREMIUM_GEO 작업)**:\n- `geobh-jsonld` EF v3 패치 — 인증 헤더 검증 + 3단계 fallback 유지\n- jsonld-serve `/api/jsonld-serve` 인증 통합\n- 어드민 UI 토큰 발급/관리 화면 (`bmp.ai/admin` PDP 탭 확장)\n\n**검증**: 토큰 검증 부하 + Origin 화이트리스트 + 만료/재발급/폐기 시나리오\n\n### Phase 2 — Phase D 자동화 부활 (1주)\n\n**PREMIUM_GEO 작업**:\n- PDP-SCHED (`s5JaX2zYy2RU2fkt`) 자동 스케줄 미작동 원인 추적 + 수정\n- Webhook/Schedule 트리거 패턴 재정립 (`bmp_jsonld_sites.is_pdp_enabled`)\n- 24h/12h 스케줄 실 작동 검증\n- 갱신 정책 표준 (사용자 변경 트리거 vs 정기)\n- last_batch_count·errors Telegram 알림\n\n### Phase 3 — OCR → schema 변환 파이프라인 (2주) ⭐ 핵심 차별화\n\n**GEOcare 영역**:\n- HITL 검수 후 `gp_geoex_ocr_review` 통과 row만 변환 대상\n- 신규 WF: `[Phase D-OCR] OCR-to-Schema Pipeline` 신설\n  - `lifestyle/model_wearing/product_only` → Product image[] 보강\n  - `detail_text/spec_table` → Product description + additionalProperty\n  - `care_guide/care_instruction` → HowTo 신규\n  - `infographic` → FAQPage 신규\n  - `size_chart` → PropertyValue\n- LLM 변환 비용 추적 (OCR raw → Gemini/GPT)\n\n**BMP 영역**:\n- `bmp_jsonld_delivery.source = 'ocr'` row 추가 (정책: 별도 row vs array merge — Phase 3 진입 시 결정)\n- 우선순위 merge 정책 (extracted > generated > ocr 또는 통합)\n\n### Phase 4 — sitegeo 통합 + 데이터 정합 (1주)\n\n**GEOcare 영역**:\n- `gp_geoex_jsonld_log` → `bmp_jsonld_delivery` 마이그 정책 결정\n  - 옵션 A: 모두 마이그 후 deprecated (단일 SSOT)\n  - 옵션 B: 사용자 직접 입력 이력은 영구 보존, 운영 송출만 bmp 활용 (권장)\n- `gp_geoex_jsonld_log.site_domain` 정규화 (`https://...` 제거)\n- WebSite/Organization/WebPage/BreadcrumbList → bmp 적재 시 `source='sitegeo'`\n\n**검증**: 이바나 사례 (sitegeo 8 + brandgeo 12 + ocr 216 → 통합 결과 측정)\n\n### Phase 5 — 관측·운영·알림 (1주)\n\n**BMP 영역 (어드민 UI 확장)**:\n- 호출량 dashboard 신규 탭\n- Rate Limit 실 적용 (현재 컬럼만 존재, 작동 ❌)\n- 운영 알림 표준 (delivery 갱신 실패 / 인증 실패 폭증 등)\n- A/B 테스트 인프라 활용 (`bmp_jsonld_ab_tests`)\n- 비용 추적 (Vision GPT-4o · GPT 생성 fallback · OCR 변환)\n\n### Phase 6 — 공식 표준화 + 외부 통보 (0.5주)\n\n**양 방 공동**:\n- STD-JSONLD-UNIFIED v1.0 정본 KHub 등재 (양 방 동시)\n- 11줄 PHP 코드 v1.0 정식 발표 (라이브러리화 검토)\n- 운영 매뉴얼 작성 (어드민/파트너용)\n- 학습 #17~#22 KHub 일괄 등재\n- 외부 통보 (옥경화 상무 → 러브헌터 등 적용 사이트)\n\n### 안정화 (2주)\n- 내부 dogfooding (bizspring.co.kr · growthplatform.ai 직접 적용)\n- 첫 외부 사이트 1건 적용 (luvhunter 또는 medicube)\n- 부하·장애·롤백 드릴\n- 🔍 VERIFIED → 본 트랙 종결\n\n---\n\n## 4. 영역 격벽 매트릭스\n\n| 작업 | 영역 | 책임 |\n|---|---|---|\n| `gp_geoex_inject_keys` 테이블/RPC | GEOcare 단독 | 본 방 |\n| OCR → schema 변환 파이프라인 | GEOcare 단독 | 본 방 |\n| `gp_geoex_jsonld_log` 정규화/마이그 | GEOcare 단독 | 본 방 |\n| `bmp_jsonld_delivery` source/install_method 표준 | BMP 단독 | PREMIUM_GEO 방 |\n| `geobh-jsonld` EF v3 패치 | BMP 단독 | PREMIUM_GEO 방 |\n| jsonld-serve EF 패치 | BMP 단독 | PREMIUM_GEO 방 |\n| PDP-SCHED 자동 스케줄 부활 | BMP 단독 | PREMIUM_GEO 방 |\n| 어드민 UI (PDP 탭 확장) | BMP 단독 | PREMIUM_GEO 방 |\n| OCR 변환 결과 → bmp 적재 정책 | **양 방 합의** | 공동 |\n| Phase 6 정본 표준 등재 | **양 방 공동** | 공동 |\n\n---\n\n## 5. 본 세션(2026-05-08) 산출물 — 본 트랙 자료로 보존\n\n| 자산 | 위치 | 용도 |\n|---|---|---|\n| schema.geocare.ai DNS 등록 ✅ | 후이즈 + Supabase ENABLED | 본 트랙 호출 도메인 (즉시 활용) |\n| schema.geocare.ai 호출 표준 v1.0 | 별도 KHub 문서 | 본 트랙 Phase 1 직접 활용 |\n| 3계열 schema 분석 (701/16/483건) | 본 문서 §2.1 | Phase 4 통합 근거 |\n| 4/1 이바나 12건 timestamp 시퀀스 | 본 문서 §2.1 | Phase 2 자동 스케줄 부활 근거 |\n| `gp_geoex_inject_keys` v0.1 스키마 | 본 문서 §6.1 | Phase 1 GEOcare 작업 진입점 |\n| `verify_geoex_inject_key` RPC v0.1 | 본 문서 §6.2 | Phase 1 GEOcare 작업 진입점 |\n| 11줄 PHP 코드 v1.3 (luvhunter) | 본 문서 §6.3 | Phase 6 정식 발표 직전 검토 후보 |\n\n⛔ DDL/INSERT 미실행 — G0 충족 후 Phase 1 정식 진입 시점에 양 방 합의 후 적용.\n\n---\n\n## 6. 본 세션 G1 설계 자산 (Phase 1 진입 시 검토 후보)\n\n### 6.1 `gp_geoex_inject_keys` v0.1 (Phase 1 검토)\n\n```sql\nCREATE TABLE gp_geoex_inject_keys (\n  id                    uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n  api_key               text UNIQUE NOT NULL,\n  client_code           text UNIQUE NOT NULL,\n  site_domain           text NOT NULL,\n  display_name          text,\n  permissions           text[] DEFAULT ARRAY['inject']::text[],\n  allowed_origins       text[],\n  rate_limit_per_hour   integer DEFAULT 10000,\n  is_active             boolean DEFAULT true,\n  expires_at            timestamptz,\n  last_used_at          timestamptz,\n  metadata              jsonb,\n  created_at            timestamptz NOT NULL DEFAULT now(),\n  updated_at            timestamptz NOT NULL DEFAULT now(),\n  CONSTRAINT chk_api_key_prefix CHECK (api_key ~ '^[a-z]{2,5}_[a-zA-Z0-9]{24,64}$'),\n  CONSTRAINT chk_client_code_format CHECK (client_code ~ '^[A-Z][A-Z0-9_]{2,30}$'),\n  CONSTRAINT chk_site_domain_format CHECK (site_domain ~ '^[a-z0-9.-]+\\.[a-z]{2,}$')\n);\n\nCREATE UNIQUE INDEX idx_inject_keys_api_key_active ON gp_geoex_inject_keys (api_key) WHERE is_active = true;\nCREATE INDEX idx_inject_keys_origins ON gp_geoex_inject_keys USING GIN (allowed_origins);\nCREATE INDEX idx_inject_keys_expires ON gp_geoex_inject_keys (expires_at) WHERE is_active = true AND expires_at IS NOT NULL;\nCREATE INDEX idx_inject_keys_client_code ON gp_geoex_inject_keys (client_code);\n\nALTER TABLE gp_geoex_inject_keys ENABLE ROW LEVEL SECURITY;\nCREATE POLICY no_direct_access ON gp_geoex_inject_keys FOR ALL USING (false) WITH CHECK (false);\n```\n\n→ 패턴 근거: `gp_mcp_api_keys` (GEOcare MCP 인증) + BIZDATA `de_unified_client.api_key` 합성.\n\n### 6.2 `verify_geoex_inject_key` RPC v0.1 (Phase 1 검토)\n\n```sql\nCREATE OR REPLACE FUNCTION verify_geoex_inject_key(\n  p_api_key text,\n  p_origin text DEFAULT NULL,\n  p_request_url text DEFAULT NULL\n)\nRETURNS TABLE(\n  is_valid boolean,\n  client_code text,\n  site_domain text,\n  permissions text[],\n  metadata jsonb,\n  failure_reason text\n)\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n  v_row gp_geoex_inject_keys%ROWTYPE;\nBEGIN\n  SELECT * INTO v_row FROM gp_geoex_inject_keys\n  WHERE api_key = p_api_key AND is_active = true LIMIT 1;\n  \n  IF NOT FOUND THEN\n    RETURN QUERY SELECT false, NULL::text, NULL::text, NULL::text[], NULL::jsonb, 'key_not_found_or_inactive'::text;\n    RETURN;\n  END IF;\n  \n  IF v_row.expires_at IS NOT NULL AND v_row.expires_at < now() THEN\n    RETURN QUERY SELECT false, v_row.client_code, v_row.site_domain, NULL::text[], NULL::jsonb, 'key_expired'::text;\n    RETURN;\n  END IF;\n  \n  IF v_row.allowed_origins IS NOT NULL AND array_length(v_row.allowed_origins, 1) > 0 AND p_origin IS NOT NULL THEN\n    IF NOT (p_origin = ANY(v_row.allowed_origins)) THEN\n      RETURN QUERY SELECT false, v_row.client_code, v_row.site_domain, NULL::text[], NULL::jsonb, 'origin_not_allowed'::text;\n      RETURN;\n    END IF;\n  END IF;\n  \n  UPDATE gp_geoex_inject_keys SET last_used_at = now() WHERE id = v_row.id;\n  \n  RETURN QUERY SELECT true, v_row.client_code, v_row.site_domain, v_row.permissions, v_row.metadata, NULL::text;\nEND;\n$$;\n\nGRANT EXECUTE ON FUNCTION verify_geoex_inject_key(text, text, text) TO anon, authenticated, service_role;\n```\n\n### 6.3 11줄 PHP 코드 v1.3 (Phase 6 정식 발표 직전 검토)\n\n```php\n<!-- GEOcare JSON-LD Auto-Inject (비즈스프링) -->\n<?php\n$_g_url = 'https://www.luvhunter.net' . $_SERVER['REQUEST_URI'];\n$_g_cache = sys_get_temp_dir() . '/gc_' . md5($_g_url);\nif (!file_exists($_g_cache) || time() - filemtime($_g_cache) > 3600) {\n    $_g_ctx = stream_context_create(['http' => ['timeout' => 2, 'header' => 'X-GEOcare-Key: lvh_xxxxxxxxxxxxxxxxxxxxxxxx']]);\n    $_g_res = @file_get_contents('https://schema.geocare.ai/functions/v1/geobh-jsonld?url=' . urlencode($_g_url), false, $_g_ctx);\n    if ($_g_res) @file_put_contents($_g_cache, $_g_res);\n}\nif (file_exists($_g_cache)) echo '<script type=\"application/ld+json\">' . file_get_contents($_g_cache) . '</script>';\n?>\n```\n\n→ 적용 위치: `_inc_index_header.tpl` 188~189행 사이 (`</head>` 직전).\n\n---\n\n## 7. 후속 트랙 시드 (본 트랙에서 분기 가능성)\n\n| 후속 트랙 | 시점 | 책임 |\n|---|---|---|\n| `T-PIPELINE-OCR-TO-SCHEMA-FULLAUTO` | Phase 3 종결 후 풀자동화 | GEOcare |\n| `T-MIGRATION-SITEGEO-LEGACY` | Phase 4 후속 (gp_geoex_jsonld_log 거취 결정) | GEOcare |\n| `T-OPS-AUTO-INJECT-MULTISITE` | 안정화 후 다수 사이트 적용 | 양 방 공동 |\n| `T-MARKETING-AUTO-INJECT-LAUNCH` | 안정화 후 영업 메시지 | SALES + GEOCARE |\n\n---\n\n## 8. 학습 누적 (Phase 6 일괄 등재 후보)\n\n| # | 가칭 |\n|---|---|\n| 17 | 외부 EF 활용 코드 제안 시 인증 모델 단정 금지 |\n| 18 | 가칭 자산명 자연 노출 금지 |\n| 19 | 인벤토리 미확인 상태로 신규 테이블 설계 금지 |\n| 20 | 동일 명칭 테이블 발견 시 용도 검증 필수 |\n| 21 | 신규 인프라 설계 시 인증·데이터·실행 3축 동시 확인 |\n| 22 | 외부 변수(영업 일정) 압박 시 PO에게 명시적 환기 요청 |\n\n→ 본 트랙 Phase 6 종결 시 KHub COMMON 일괄 등재.\n\n---\n\n## 9. 새 세션 진입 명령\n\n### 트리거 발화\n- **\"T-AUTO-INJECT-UNIFIED 이어서\"** → 본 문서 로드 + G0 5건 상태 점검\n- **\"T-RENEW v1.1 회신 왔어\"** → G0 #1 충족 → #2 일정 합의 진입\n- **\"양 PO 미팅 결과\"** → G0 #2~#3 진입\n- **\"Phase 1 진입\"** → G0 충족 시점 + 양 방 합의 시 발동\n- **\"본 트랙 종결\"** → 사양 폐기 또는 다른 트랙으로 흡수 시\n\n### 본 트랙 발동 전 새 세션 작업 우선순위 (높→낮)\n1. **자동 패치 사후 검토 6건** (5/7 17:00 SLA D-1)\n2. **BUG-002 G3 재검증** (PREMIUM_GEO 처리 후, SLA 5/9 EOD)\n3. **나이스페이 회신 메일** (P0-3, AP-25)\n4. **T-EEAT-LLM-FAIL** 트랙 신설 (2,959건 score=0)\n5. **5/11 미팅 준비** (KHub `d00aceea` + bmp.ai 5종 + 어드민 시연)\n6. **T-RENEW v1.1 회신 모니터링** (구자훈 대표)\n7. T-SALES-MPRD-UPSELL Phase 1 메시지 본문 컨펌\n\n---\n\n## 10. 변경 이력\n\n| 일자 | 버전 | 변경 |\n|------|------|------|\n| 2026-05-08 | v1.0 (골격) | 초판 — G0 대기 상태로 등재. Phase 1~6 + 안정화 골격. 본 세션 산출물 보존. T-RENEW v1.1 회신 후 발동. |\n",
  "embedding": null,
  "embedded_at": null,
  "embedding_hash": null,
  "backlinks": [],
  "html_url": "https://bizspring.ai/kb/ref/khub/geocare-t-auto-inject-unified-v1-json-ld-자동-송출-통합-트랙-골격-g0-대기",
  "markdown_url": "https://bizspring.ai/kb/ref/khub/geocare-t-auto-inject-unified-v1-json-ld-자동-송출-통합-트랙-골격-g0-대기.md"
}