# 🎯 I-1 G1 설계 — geobh-jsonld EF 인증 헤더 통합 v1.2 (5/11 후속 정정)

> # 🎯 I-1 G1 설계 — geobh-jsonld EF 인증 헤더 통합 v1.2 (5/11 후속 정정) > 작성: 2026-05-10 KST | v1.0 > 갱신: 2026-05-11 KST | **v1.1** (5/11 GEOCARE 방 EF v5 라이브 확인 후 정정 — 본질 

## 핵심 요약


# 🎯 I-1 G1 설계 — geobh-jsonld EF 인증 헤더 통합 v1.2 (5/11 후속 정정)

> 작성: 2026-05-10 KST | v1.0
> 갱신: 2026-05-11 KST | **v1.1** (5/11 GEOCARE 방 EF v5 라이브 확인 후 정정 — 본질 변화 0, 명칭만 정정)
> 갱신: 2026-05-11 KST | **v1.2** (5/11 후속 — GEOCARE G2-1/G2-3 회신 수령 + 4개 결정 승인 반영, 본질 변화 0)
> 트랙: T-AUTO-INJECT-UNIFIED-v1 Phase 1.2 / Track I I-1
> Track I Reference: KHub `ea16e72e-e577-4ff7-a68c-8c796857f660`
> 대상 EF: bawee Supabase `geobh-jsonld` (현재 **v5 라이브**, schema.geocare.ai CNAME)
> Phase: 📋 **READY (G2 4/4 ALL PASS, PUT 진입 가능)**
> 우선순위: P0
> 예상 소요: 0.5일

---

## 0. v1.0 → v1.1 → v1.2 정정 사유 (변경 이력 §10 참조)

### v1.0 → v1.1 (5/11 KST 1차)

5/11 KST 양 방 5/10~5/11 통합 점검 매트릭스에서 발견:
- GEOCARE 방이 5/11 KST 시연 직전 T-BIZSPRING-JSONLD-FILL 완결 → **EF v3 → EF v5로 마이그 라이브**
- 5/11 schema.geocare.ai EF v5: `verify_jwt:false`, `ef_version=v5`, `rpc_version=v3`, `sources=[site_jsonld, brand_jsonld, eeat_analysis.generated_jsonld]` (3 SSOT 통합)
- 본 v1.0 설계의 "EF v3" 명칭 → 실 라이브 "EF v5" 정정 필요
- 본방 인증 입구 추가 패치 **본질 변화 0** (응답 본문 미변경 원칙 동일)
- **G2 진입 조건 #2 (T-BIZSPRING-JSONLD-FILL Step 3 PUT 여부) ✅ 충족 마킹**

### v1.1 → v1.2 (5/11 KST 후속)

5/11 KST GEOCARE → PREMIUM_GEO Cross-Room MB 13차 회신 수령 + 찰스 4개 결정 승인:
- **G2-1 ✅ 충족**: GEOCARE PO 인가 결정 — G0 5건 전수 충족 (테이블+RPC+RLS+테스트 키 5건 ALL PASS = G0 산출물)
- **G2-3 ✅ 충족**: BIZSPRING_DEV prefix = `biz_`. 정규식 `^[a-z]{3}_[A-Za-z0-9]{32}$`. client_code 매칭은 RPC 내부 로직
- G2 4건 **ALL PASS** → I-1(α) 즉시 PUT 진입 가능
- ADR-001 신설 (I-3 위치 정정: bmp.ai/admin → geocare-admin-hub)
- ADR-002 신설 (I-2 위치 정정: Vercel jsonld-serve → CF Workers + DNS 명명 체계)
- 응답 헤더 `X-GEOcare-Cache-Source` 신설 (CF Workers Phase B 진입 후 활용, 현재 PUT 시 `direct` 값 명시)
- 본질 변화 0 — 입구 추가 + 응답 본문 미변경 원칙 동일

---

## 1. 한 줄 정의

`geobh-jsonld` EF **v5**(2026-05-11 라이브)에 `X-GEOcare-Key` 헤더 검증 입구를 추가하여, 외부 사이트의 인증 호출만 응답하도록 게이트를 닫는다. **응답 본문은 미변경 (3 SSOT 통합 로직 그대로).**

---

## 2. 변경 범위 (입구 한정)

### 2.1 추가
- 헤더 검증: `X-GEOcare-Key` 누락 시 HTTP 400 + `X-GEOcare-Failure-Reason: missing_key_header`
- RPC 호출: `verify_geoex_inject_key(p_api_key, p_origin, p_request_url)` 1회
- 401 분기: `is_valid=false` → HTTP 401 + `X-GEOcare-Failure-Reason: <reason>`
- 200 분기: `is_valid=true` → 기존 v5 실측 응답 로직 그대로 진행
- 응답 헤더: `X-GEOcare-Client-Code` 추가 (관측 + Phase 5 활용)
- **(v1.2 신규)** 응답 헤더: `X-GEOcare-Cache-Source` 추가 — 현재 v6 PUT 시 `direct` 값 (CF Workers Phase B 진입 후 `cf-hit` / `cf-miss` 값 활용 예정)

### 2.2 미변경 (절대 금지)
- 응답 본문 (EF v5 3 SSOT 통합 로직: site_jsonld + brand_jsonld + eeat_analysis.generated_jsonld)
- `gp_geoex_jsonld_elements` (5/11 GEOCARE 그린필드 SSOT) — 본방 미접근
- `bmp_jsonld_delivery` (본방 Phase D SSOT) — 본방 영역 별도
- GPT 즉석 생성 분기 (EF v5 응답 본문 내부 로직)

→ 본방은 입구만 추가. GEOCARE 측 EF v6 배포 시점(T-FIX-3SSOT-PIPELINE Step 4)에서 본방 인증 입구 보존 의무 합의 필요 (Cross-Room MB 14차에서 통보).

---

## 3. 의사 코드 (현재 v5 라이브 위에 입구만 추가)

```typescript
// === Deno Edge Function: geobh-jsonld v6 (인증 통합) ===
// v5 → v6 (입구만 추가, 응답 본문 미변경)
import { serve } from "https://deno.land/std/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";

const supabase = createClient(
  Deno.env.get("SUPABASE_URL")!,
  Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
);

serve(async (req) => {
  // === [v6 신규] 인증 헤더 검증 ===
  const apiKey = req.headers.get("x-geocare-key");
  if (!apiKey) {
    return new Response(
      JSON.stringify({ error: "missing_key_header" }),
      {
        status: 400,
        headers: {
          "Content-Type": "application/json",
          "X-GEOcare-Failure-Reason": "missing_key_header"
        }
      }
    );
  }

  const origin = req.headers.get("origin") || req.headers.get("referer") || null;
  const url = new URL(req.url);
  const targetUrl = url.searchParams.get("url");

  // verify RPC 호출 (1회)
  const { data: verifyResult, error: verifyError } =
    await supabase.rpc("verify_geoex_inject_key", {
      p_api_key: apiKey,
      p_origin: origin,
      p_request_url: targetUrl
    });

  if (verifyError || !verifyResult?.[0]?.is_valid) {
    const reason = verifyResult?.[0]?.failure_reason || "verify_error";
    return new Response(
      JSON.stringify({ error: "Unauthorized", reason }),
      {
        status: 401,
        headers: {
          "Content-Type": "application/json",
          "X-GEOcare-Failure-Reason": reason
        }
      }
    );
  }

  const { client_code } = verifyResult[0];

  // === [v5 기존] 응답 본문 로직 그대로 ===
  // ... 3 SSOT 통합 로직 (site_jsonld + brand_jsonld + eeat_analysis.generated_jsonld) ...
  // ... GPT fallback 분기 ...
  //
  // 응답 헤더 추가 (관측):
  //   X-GEOcare-Client-Code: <client_code>
  //   X-GEOcare-Cache-Source: direct  ← v1.2 신규 (CF Workers Phase B 진입 후 cf-hit/cf-miss 값)
});
```

⚠️ **PUT 작업 시 GET → 기존 EF v5 코드 전체 추출 → 위 입구 부분만 prepend → PUT 패턴 (AP-07)**. 기존 응답 본문 로직(EF v5의 3 SSOT 통합) 한 줄도 변경 금지.

---

## 4. 호환성 (BIZSPRING_DEV 도그푸딩)

### 4.1 자사 비즈스프링 사이트 v2.10 PHP 코드

KHub `3f8b6f09` STD-DEPLOY-SERVERSIDE-SCRIPT v1.1 §3 v2.10 라이브 명시:
- 호출 헤더: `X-GEOcare-Key: <key>`
- 호출 URL: `https://schema.geocare.ai/functions/v1/geobh-jsonld?url=<page_url>`

### 4.2 PUT 직후 호환성 매트릭스

| 사이트 | 사용 키 prefix | A-4 발급 키 | I-1 PUT 후 |
|---|---|---|---|
| bizspring.co.kr v2.10 | **`biz_`** ✅ **(v1.2 5/11 GEOCARE 회신 확정)** | BIZSPRING_DEV `biz_qBzs...` | ✅ 즉시 통과 (prefix 일치 확정) |
| bmp.ai/admin | `adm_` | ADMIN_INTERNAL `adm_mJpe...` | ✅ I-2-Alt 시점 활용 |
| growthplatform.ai | `gpf_` | GROWTHPLATFORM_DEV `gpf_HHw2...` | ✅ 미사용 (보존) |
| luvhunter.net (PoC) | `lvh_` | TEST_LUVHUNTER (5/9 GEOCARE 발급) | ✅ 즉시 통과 |
| ivanahelsinki.co.kr | `ivn_` | TEST_IVANA (5/9 GEOCARE 발급) | ✅ 즉시 통과 |

검증 정규식 (v1.2 추가): `^[a-z]{3}_[A-Za-z0-9]{32}$`

### 4.3 5/11 luvhunter 시연과의 관계

GEOCARE Snapshot v3.37 NOW §B "luvhunter 새 모델 마이그 — STD-PARTNER-JSONLD-FILL 적용" 진행 중.
본방 I-1 PUT 시점 = GEOCARE luvhunter 마이그 후 권고 (충돌 없으나 시연 안정성 우선).

### 4.4 사전 점검 의무

✅ **(v1.2 충족 명기)** **PUT 전 GEOCARE 방에 v2.10 PHP 코드 실 사용 키 prefix 확인 = `biz_` 확정 (Cross-Room MB 13차 회신)** — G2 진입 조건 #3 ALL PASS.

---

## 5. 테스트 시나리오 (B1~B6)

| # | 시나리오 | 호출 | 기대 |
|---|---|---|---|
| B1 | 헤더 누락 | X-GEOcare-Key 없이 GET | HTTP 400 + missing_key_header |
| B2 | 잘못된 키 | X-GEOcare-Key: invalid_xxx | HTTP 401 + key_not_found_or_inactive |
| B3 | TEST_LUVHUNTER 정상 | + Origin: https://www.luvhunter.net | HTTP 200 + JSON-LD (v5 3 SSOT 통합 응답) |
| B4 | TEST_LUVHUNTER + Origin 불일치 | + Origin: https://wrong.com | HTTP 401 + origin_not_allowed |
| B5 | TEST_IVANA 정상 | ivn_ 키 + Origin 일치 | HTTP 200 + JSON-LD |
| B6 | BIZSPRING_DEV 도그푸딩 | + Origin: https://www.bizspring.co.kr | HTTP 200 + JSON-LD |

### 추가 검증
- B3/B5/B6 호출 직후 `gp_geoex_inject_keys.last_used_at` 갱신 확인
- 응답 시간 측정 (verify RPC 추가로 평균 +50~150ms 예상)
- **v5 응답 본문(3 SSOT 통합) 정확히 보존되는지 검증** ⭐ (v1.1 추가)
- **응답 헤더 `X-GEOcare-Cache-Source: direct` 명시 확인** (v1.2 추가)

---

## 6. 롤백 계획

EF 이전 버전 PUT (Supabase Management API revision 선택).
- 현재 v5 라이브 → I-1 PUT 후 v6
- 롤백 시 v5로 복귀 (verify_jwt:false 상태 + 3 SSOT 통합 로직 그대로)
- 소요: 1분 內

**유의**: A-4 발급 키 3건 + 5/9 GEOCARE 테스트 키 2건은 그대로 유지.

---

## 7. G2 진입 조건 (Self-Check) — v1.2 갱신

PUT 직전 본방 PO(찰스) 컨펌 + GEOCARE 회신 의무. 다음 4건 충족 시 G2 통과:

- [x] ✅ **G2-1**: G0 5건 충족 인지 확인 — **충족 (5/11 GEOCARE Cross-Room MB 13차 회신)**. GEOCARE PO 인가 결정 — 5/9 Phase 1.1 산출(gp_geoex_inject_keys 테이블 + verify_geoex_inject_key RPC + RLS no_direct_access + SECURITY DEFINER + 테스트 키 T1~T5 ALL PASS)이 G0 5건 전수 충족 산출물. 구자훈 5/9 발화는 별도 사안, PREMIUM_GEO Track I 진행과 분리 처리
- [x] ✅ **G2-2**: T-BIZSPRING-JSONLD-FILL Step 3 PUT 여부 — **충족** (5/11 EF v5 라이브 = Step 3 완결)
- [x] ✅ **G2-3**: v2.10 PHP 도그푸딩 실 사용 키 prefix 확인 — **충족 (5/11 GEOCARE Cross-Room MB 13차 회신)**. BIZSPRING_DEV prefix = `biz_`. 정규식 `^[a-z]{3}_[A-Za-z0-9]{32}$`. prefix는 일반 패턴, client_code 매칭은 RPC verify_geoex_inject_key 내부 로직
- [x] ✅ **G2-4**: 본 G1 v1.2 PO 컨펌 — **완료 (5/11 찰스 4개 결정 승인)**

**G2 4/4 ALL PASS → I-1 PUT 진입 가능 🟢**

---

## 8. PUT 후 Phase (v1.2 정정)

PUT → B1~B6 단위 테스트 → 결과 보고 → **다음 진입 (v1.2 정정 매트릭스 참조)**:

| 항목 | v1.0/v1.1 | v1.2 |
|---|---|---|
| I-2 | bmp.ai/api/jsonld-serve 인증 통합 (Vercel) | **폐기** → ADR-002 참조 |
| I-2-Alt | (없음) | **신설**: Cloudflare Workers + KV 캐시 (별 트랙) → ADR-002 참조 |
| I-3 | bmp.ai/admin PDP 탭 확장 | **정정**: geocare-admin-hub `/admin/inject-keys` → ADR-001 참조 |
| I-4 | Phase D DevLog v3.0 갱신 | 그대로 유지 (단, ADR-001/002 반영 갱신) |

I-2-Alt 진입 시 본 G1 v1.2 인증 입구 패턴 + KV 캐시 패턴 별도 G1로 명세 (KHub 신설 예정).
I-3 진입 시 Lovable `geocare-admin-hub` 별 G1 명세 (KHub 신설 예정).

---

## 9. 짝 자산

| 자산 | KHub ID |
|---|---|
| Track I Reference | `ea16e72e-e577-4ff7-a68c-8c796857f660` |
| 트랙 정본 v1.0 | `46fdc824` |
| 호출 표준 v1.1 | `dc3ce334` |
| 서버사이드 스크립트 v1.1 (v2.10 PHP) | `3f8b6f09` |
| Phase D DevLog v2.0 (I-4 갱신 대상) | `0c006e31` |
| **GEOCARE Snapshot v3.37 (EF v5 라이브 anchor)** | `061e5edb` (5/11 03:00 EF v5 적재 검증) |
| **T-FIX-3SSOT-PIPELINE PRD v1.4** | `a8692b7f-ab67-467b-ae62-652c900ae874` (그린필드 SSOT) |
| **STD-PARTNER-JSONLD-FILL v1.0** | `fceee150` (GEOCARE 측 새 모델 마이그 표준) |
| **(v1.2 신규)** Cross-Room MB | `36928e3f` (5/11 14차 prepend 예정 — DNS 명명 체계 + I-2-Alt 진입 통보) |
| **(v1.2 신규)** geocare-admin-hub Lovable | https://lovable.dev/projects/ab6a109b-76dc-4159-9c98-ae2708057451 |
| **(v1.2 신규)** geocare-admin-hub GitHub | https://github.com/CharlesLee1991/geocare-admin-hub |

---

## 10. 변경 이력

| 일자 | 버전 | 변경 |
|---|---|---|
| 2026-05-10 KST | v1.0 | 신설 — G1 설계 단계. 명세서 §4-1 의사코드의 "3단계 fallback" 부분 정정 (현재 v1.1 실측 동작 위에 입구만 추가). G2 진입 조건 4건 컨펌 대기. |
| 2026-05-11 KST | v1.1 | **EF v3 → EF v5 명칭 정정** (5/11 GEOCARE 방 라이브 후 발견). G2-2 ✅ 충족 마킹 (T-BIZSPRING-JSONLD-FILL 완결). 짝 자산 3건 추가 (GEOCARE Snapshot v3.37 / PRD v1.4 / STD-PARTNER-JSONLD-FILL). 본질 변화 0 — 입구 추가 + 응답 본문 미변경 원칙 동일. |
| **2026-05-11 KST 후속** | **v1.2** | **5/11 GEOCARE G2-1/G2-3 회신 수령 → G2 4/4 ALL PASS 명기**. ADR-001 신설(I-3 위치 정정: bmp.ai/admin → geocare-admin-hub). ADR-002 신설(I-2 위치 정정: Vercel jsonld-serve → CF Workers 별 트랙 + DNS 명명 체계 cf-jsonld.geocare.ai / supabase.geocare.ai / schema.geocare.ai 폐기). X-GEOcare-Cache-Source 응답 헤더 명세. 본질 변화 0 — 입구 추가 + 응답 본문 미변경 원칙 동일. |

---

## 11. ADR-001 — I-3 위치 정정 (bmp.ai/admin → geocare-admin-hub)

### 컨텍스트
v1.0/v1.1 설계 시 I-3 어드민 UI를 bmp.ai/admin PDP 탭 확장으로 가정. Phase D DevLog(`0c006e31`) 7탭 슈퍼어드민 자산이 4/1부터 실재하기 때문.

### 결정 (2026-05-11 KST 후속, 찰스)
I-3 위치를 `CharlesLee1991/geocare-admin-hub` Lovable repo의 `/admin/inject-keys` 신규 탭으로 정정.

### 근거
- **페르소나 일치**: 인증 키 = 슈퍼어드민만 영역 (찰스 + 옥상무 + 내부)
- geocare-admin-hub = 슈퍼어드민 전용 Lovable 자산 (페르소나 명확)
- bmp.ai/admin은 다목적 7탭 (파트너/고객/계정/BrandHub/PDP/분석)
- Lovable Edit → main push 패턴 검증 완료 (Track A PR-S5-1/2)

### 결과 (자산)
- Lovable: https://lovable.dev/projects/ab6a109b-76dc-4159-9c98-ae2708057451
- GitHub: https://github.com/CharlesLee1991/geocare-admin-hub
- I-3 G1 별 KHub 신설 예정

### 영향
- bmp.ai/admin의 PDP 탭 그대로 (Phase D 자산 보존)
- geocare-admin-hub에 신규 탭 추가
- admin RPC 4종 SECURITY DEFINER (직접 INSERT/UPDATE 노출 금지) — 위치 무관 동일

---

## 12. ADR-002 — I-2 위치 정정 (Vercel jsonld-serve → CF Workers + DNS 체계)

### 컨텍스트
v1.0/v1.1 설계 시 I-2 인증 통합을 bmp.ai/api/jsonld-serve (Vercel)에 적용 예정. Phase D 자산 3단계 fallback 위에 인증 입구 추가 모델.

### 결정 (2026-05-11 KST 후속, 찰스)
1) I-2 (Vercel jsonld-serve)는 폐기 (Phase D 자산 deprecated 일정과 정합)
2) I-2-Alt 신설: Cloudflare Workers 인증 게이트 + KV 캐시
3) 별 트랙 분리 — 본 Phase 1.2 SLA(5/19) 보존, GEOCARE DNS 협의 후 진입
4) DNS 명명 체계 신설 (운영자 인지 부담 0)

### 근거
- 본방 CF 자산 보유 (Account `2458e1cce049da407fb497c419b6a2a6` + API Token `gp_admin_secrets.CF_API_TOKEN` + Workers 운영 경험)
- 글로벌 latency: Supabase ~200ms → CF Workers ~5ms (HIT) (10배 개선)
- 비용: 1000만 req/월 Supabase ~$50 → CF ~$5 (10배 절감)
- GEOCARE 5/11 새 SSOT(`gp_geoex_jsonld_elements`) + EF v6 일정과 정합
- Phase D 자산(`bmp_jsonld_delivery`)은 Step 5 archive 일정과 정합

### 결과 (DNS 명명 체계 신설)

| 도메인 | 인프라 | 역할 | 노출 |
|---|---|---|---|
| **`cf-jsonld.geocare.ai`** | CF Workers | JSON-LD 송출 게이트웨이 (인증 + KV 캐시) | 🌐 외부 |
| **`supabase.geocare.ai`** | Supabase EF | 원본 EF(`geobh-jsonld`) origin | 🔒 internal-only |
| ~~`schema.geocare.ai`~~ | (deprecated) | 추상 alias, 운영자 기억 부담 | ❌ 폐기 (30일 호환 alias → DNS 제거) |

### 마이그 시나리오 (Phase A~D, 1주 내)

| Phase | 내용 | 시점 |
|---|---|---|
| A | 신 도메인 신설 (`supabase.geocare.ai` + `cf-jsonld.geocare.ai`). schema.geocare.ai 그대로 유지 (호환성) | 5/12~5/13 |
| B | 외부 사이트 점진 마이그 (luvhunter, ivanahelsinki, bizspring v2.10 PHP — 환경변수 1개 교체) | 5/13~5/19 |
| C | schema.geocare.ai 폐기 (30일 호환 alias → DNS 제거) | 5/20~6/20 |
| D | 새 가입 사이트는 처음부터 cf-jsonld.geocare.ai만 사용 (표준 문서 갱신) | 6/20~ |

### 영향
- 외부 사이트 입장: URL 변경 0 (schema.geocare.ai 호환 유지) → Phase B에서 점진 마이그 → Phase C 이전에 100% 마이그 완료
- 응답 latency: 글로벌 ~200ms → ~5ms (95%+ HIT)
- 비용: 월 ~$45 절감 (1000만 req 기준)
- 보안 강화: supabase.geocare.ai internal-only 키 검증 (외부 직접 호출 차단)

### Cross-Room MB 14차 발신 항목
- DNS 명명 체계 통보
- GEOCARE에 `cf-jsonld.geocare.ai` + `supabase.geocare.ai` CNAME 2건 발급 요청
- schema.geocare.ai 30일 호환 alias 유지 안내
- I-2-Alt 별 트랙 진입 의지 통보 (G1 별 KHub 신설 예정)


## FAQ


---
출처: https://bizspring.ai/kb/ref/khub/premium-geo-i-1-g1-설계-geobh-jsonld-ef-인증-헤더-통합-v1-2-5-11-후속-정정 · 최종 갱신 2026-08-24T11:53:44.684733+00:00
