Files
llm-wiki/raw/branch-notes/feature-keycloak-public-domain-tunneling.md
T

24 KiB

title, source_type, status, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, branch, parent_branch, related_projects, tags, created, target_merge, status_label, contract_packet_sha256
title source_type status id kind project work_item inherits refines overrides depends_on contract_packet branch parent_branch related_projects tags created target_merge status_label contract_packet_sha256
branch / feature-keycloak-public-domain-tunneling (P3B 학습 환경 public 도메인 확보 — ngrok / Cloudflare Tunnel) branch-note raw BR-KEYCLOAK-CHILD-89A2896F branch-child keycloak-patterns-overview WI-KEYCLOAK-PATTERNS-OVERVIEW-020
DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001@1
1 feature-keycloak-public-domain-tunneling feature-keycloak-patterns
keycloak-patterns
branch
keycloak-patterns
p3b
public-domain
ngrok
cloudflare-tunnel
https
2026-05-25 in-progress 5605aa356ecefd27cabba9dff6699e3058ee39235cbb0dd012b97176fb46a417

branch: feature-keycloak-public-domain-tunneling (P3B 학습 환경 public 도메인 확보 — ngrok

Layer: raw/branch-notes/raw/branch-notes/feature-keycloak-patterns governance Work Item의 child. P3B 의미 계약은 raw/branch-notes/feature-keycloak-single-ec2-google-federation를 참조한다. Google OAuth redirect_uri 정책(HTTPS + localhost 외 IP 불가) 때문에 학습 환경에서 어떻게 public URL을 확보할지 비교. 본 sub-sub-branch는 문서까지만 — 실 ngrok 구동 / Cloudflare Tunnel 설치 / EC2 도메인 매핑은 진행하지 않음. 등급 documented-only (P3B 전체 등급에 종속). status_label: in-progress

부모 (필수)

raw/branch-notes/feature-keycloak-patterns

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: project governance hub가 AP1~AP4 taxonomy와 child progress index를 유지한다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001@1 canonical 분류축은 AP1~AP4 인증 통합 아키텍처와 cross-cutting 변형이다 single-EC2 Google federation 변형의 public-domain tunnel 경계에 적용한다 raw/project-notes/keycloak-patterns-overview

브랜치 지역 결정

기존 branch-local 결정은 아래 ## Decision Evidence Map의 D-row가 소유하며 이 packet에서 복제하지 않는다.

Decision ID Decision Relation Supporting Claims Status

선언한 예외

Override ID Overrides Reason Approval Status

없음.

목표

P3A에서는 localhost:8080으로 모든 통신이 끝났지만 P3B는 Google이 Keycloak callback URI로 redirect 해야 한다. Google OAuth 2.0 client는 redirect_uri를 HTTPS 도메인으로 제한 (localhost는 dev 한정 예외, raw IP 금지). 따라서 학습 환경에서도 public 접근 가능한 HTTPS URL을 어떻게 확보할지 결정해야 한다.

면접에서 답해야 할 질문:

  1. 학습 환경에서 왜 EC2 public IP만으론 부족한가? → Google이 IP 주소 redirect_uri 거부, HTTPS + 도메인 강제.
  2. 부모가 선택한 public URL 전략을 어떻게 실행하나? → raw/branch-notes/feature-keycloak-single-ec2-google-federation D3가 provider 우선순위를 소유하고, 본 문서는 named tunnel·managed custom domain과 임시 random URL의 운영 차이만 구체화한다.
  3. 학습 → 운영 전환 시 무엇이 바뀌나? → tunnel 제거하고 EC2 public IP + Route53 A 레코드 + ACM cert로 대체.
  • 이슈:
  • PR:

범위

포함 범위

  • ngrok / Cloudflare Tunnel / EC2 + Route53 도메인 3개 옵션의 trade-off
  • 비교표: cost / static URL / TLS 자동 / 운영 비용 / inbound port 노출
  • Google redirect_uri 정책과 각 옵션의 적합도
  • 부모 raw/branch-notes/feature-keycloak-single-ec2-google-federation D3의 채택 결정을 소비해 Cloudflare named tunnel·managed custom domain, ngrok 임시 URL, EC2 도메인 옵션의 실행 메커니즘을 정리

제외 범위

  • 실 ngrok account 생성, Cloudflare account 연동, cloudflared 데몬 설치
  • 자체 도메인 구매 / Route53 hosted zone 생성
  • 운영용 ACM cert / ALB 구성 (P3B 운영 시나리오는 부모 sub-branch의 "대안 3"로만 언급)
  • ngrok / Cloudflare Tunnel의 enterprise 기능 (custom domain on free plan 제외, IP allowlist 등)

근거 (필수, 최소 1개+)

TODO

각 항목 옆에 증거 등급 표기.

  • ngrok 무료 plan 동작 확인ngrok http 80https://<random>.ngrok-free.app 임시 URL 발급, 세션 종료 시 URL 변경 — 등급: planned
  • Cloudflare Tunnel 동작 확인cloudflared tunnel create <name> + cloudflared tunnel route dns <name> kc.example.com → named tunnel과 Cloudflare가 관리하는 custom hostname 연결. trycloudflare.com quick tunnel의 random URL은 고정 callback으로 사용하지 않음 — 등급: planned
  • EC2 public IP + Route53 도메인 옵션 정리 — Route53 hosted zone + A 레코드 + ACM cert + ALB (또는 EC2 직결 + nginx + Let's Encrypt) — 등급: planned
  • 비교표 작성 — cost / static URL / TLS 자동 / inbound port 노출 / 운영 비용 / Google Console redirect_uri exact match 적합도 — 등급: planned
  • 부모 결정 수용 확인raw/branch-notes/feature-keycloak-single-ec2-google-federation D3의 Cloudflare named tunnel + managed custom domain 기본 경로와 random URL dev-only fallback을 본 실행 절차에 반영 — 등급: planned

진행 중 메모

  • ngrok free plan은 2026-05 기준 1 세션당 random subdomain. https://<8자>.ngrok-free.app 형식. 세션 끊기면 다음 세션은 다른 subdomain.
  • Cloudflare Tunnel의 trycloudflare.com quick tunnel은 무료지만 URL이 random (ngrok와 유사). 정적 도메인 원하면 Cloudflare account + 자체 도메인 (Cloudflare DNS로 위임) + named tunnel 필요.
  • EC2 public IP는 인스턴스 stop/start 시 변경 (Elastic IP 할당하면 고정). 도메인 매핑 안 하면 Google이 redirect_uri로 IP 거부.
  • 학습 환경 핵심: Google Console에 등록한 redirect_uri와 실제 Keycloak issuer URL이 글자 단위로 일치해야 함 (Google exact match 정책). URL 변경 시마다 Console 업데이트 필요.

비교표 초안

항목 ngrok free Cloudflare Tunnel (named) EC2 + Route53 + ACM
cost 무료 무료 (Cloudflare account 필요) Route53 hosted zone $0.50/월 + ACM 무료 + EC2 비용
static URL (세션마다 변경) (영구)
TLS 자동 (ngrok edge) (Cloudflare edge) ACM + ALB (자동) 또는 Let's Encrypt (cron)
inbound port 노출 불필요 (egress only) 불필요 (egress only) 필요 (443 open)
운영 비용 매 세션 Console 갱신 도메인 1회 설정 후 무 DNS / cert / SG 관리
Google redirect_uri 적합도 낮음 (URL 변경 burden) 높음 (정적) 높음 (정적)

결정 사항 (decisions)

  • 2026-05-25 (Historical / superseded selection wording): 본 문서가 Cloudflare 1순위·ngrok 2순위를 직접 결정한다고 적었으나, provider 우선순위의 owner는 부모 raw/branch-notes/feature-keycloak-single-ec2-google-federation D3이다. 본 문서는 선택 결과의 운영 메커니즘만 소유한다.
  • 2026-07-18 (Reference-Only): 부모 D3가 Cloudflare 경로를 선택하면 named tunnel + Cloudflare 관리 custom hostname을 stable Google callback으로 사용한다. trycloudflare.com quick tunnel과 ngrok random hostname은 dev-only이며 URL이 바뀌면 Google Console 값을 함께 갱신한다.
  • 2026-05-25: 운영 환경 옵션 EC2 + Route53 + ACM + ALB. 본 sub-sub-branch에서는 비교 대상으로만 기재, 실 구성은 P3B 전체가 documented-only이므로 진행 안 함.
  • 2026-05-25: 본 sub-sub-branch 전체 등급 documented-only. P3B 부모 결정(문서까지만)에 종속. 실 tunnel 구동 / 도메인 매핑은 P3A 완료 후 선택적 확장 시점에 재검토.

결정-근거 매핑

각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시. Decision ID 는 본 branch-note 안에서 안정적으로 유지. 선택 조건 열(R2): "이 조건일 때 이 결정, 다른 조건이면 어떤 대안". 분기 없으면 N/A.

Decision ID Decision 선택 조건 (언제 이 결정 / 언제 대안) Supporting Claims Evidence Strength Open Risk
D1 Cloudflare 운영 profile(부모 D3 소비) — stable Google callback이 필요하면 named tunnel을 Cloudflare가 관리하는 custom hostname(예: kc.example.com)에 연결한다. quick tunnel random URL은 이 profile에 포함하지 않는다. 부모 raw/branch-notes/feature-keycloak-single-ec2-google-federation D3가 Cloudflare를 선택하고, 관리 도메인을 확보할 수 있을 때. provider 선택 자체는 본 문서가 재정의하지 않는다. raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C1 (cloudflared outbound), raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C2 (firewall inbound 차단 권장), raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C3 (tunnel <UUID>.cfargotunnel.com subdomain 자동 부여), raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C4 (사용자 hostname CNAME → cfargotunnel.com), raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C2 (Google redirect URI raw IP 금지 → 도메인 필요) official-vendor-doc + official-vendor-doc managed custom hostname의 Google 등록과 실제 callback 성공은 P3B 실측 필요. <UUID>.cfargotunnel.com이나 trycloudflare.com URL을 stable callback으로 간주하지 않는다.
D2 ngrok 임시 운영 profile(부모 D3 fallback 소비) — random URL은 dev-only이며 Google Console redirect_uri 갱신을 동반한다. 부모 D3가 1회성 데모 fallback을 선택한 경우. 반복 사용·stable callback이면 부모 D3의 Cloudflare named tunnel profile로 돌아간다. raw/official-docs/ngrok-http-tunnel-official.md#NGROK-C1 (ngrok http <port> 가 random HTTPS hostname 생성), raw/official-docs/ngrok-http-tunnel-official.md#NGROK-C3 (random hostname 은 기존 Domain object 와 매칭 안 됨), raw/official-docs/ngrok-http-tunnel-official.md#NGROK-C4 (고정 URL에는 별도 Domain record + DNS CNAME 필요), raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C3 (exact match) official-vendor-doc + official-vendor-doc free plan에서 재시작마다 hostname이 바뀌는지는 NGROK-C1 인용에 직접 명시되지 않아 별도 확인 필요
D3 운영 환경 옵션 EC2 + Route53 + ACM + ALB — 비교 대상으로만 기재 운영(production) 환경이거나 tunnel 의존을 제거해야 할 때. 학습 환경이면 → D1/D2. 본 branch 범위 밖(§범위 Out of scope: 운영 ACM/ALB 구성 제외 + 부모 note 의 "대안 3"과 동일 tree 관행: AWS 경로 = 명명된 비교 대안, 전용 raw 미첨부) — 비교 축으로만 존재 UNSUPPORTED_DECISION / OUT_OF_BRANCH_SCOPE (AWS Route53 / ACM / ALB 공식 raw 미수집 — 본 branch 의 Sources 인용 범위 밖이자 운영 구성 결정은 별도 branch 영역) UNSUPPORTED_DECISION 실 채택 시점에 AWS 공식 raw 인용 보강 필요 (예: ACM cert 자동 갱신 정책)
D4 본 sub-sub-branch 전체 등급 documented-only (P3B 부모 결정 종속, 실 tunnel 구동 보류) P3A 완료 전 학습·문서 단계인 동안 적용. P3A 완료 후 선택적 확장 시점이면 → 실 tunnel 구동 / 도메인 매핑 재검토 (N/A — project scope 결정) UNSUPPORTED_DECISION (project scope 결정 — 부모 branch P3B 의 documented-only 정책에 종속, 외부 raw 인용 불필요) UNSUPPORTED_DECISION scope 결정 자체는 외부 raw 가 root 가 아님

구현 가이드

본 branch 는 documented-only — 실 코드/구동 없음. 따라서 본 §는 "다음 P3B 확장 작업자가 되묻지 않고 각 옵션을 셋업할 수 있는 수준"의 사전 명세 (등급은 전부 planned/documented-only). 각 sub-section 은 본 branch 의 Decision ID + Supporting Claim ID 에서 도출된 것만 기재한다.

범위 경계: Keycloak KC_HOSTNAME / KC_PROXY_HEADERS / relative-path / TLS 종단 config 는 본 branch 결정 영역 밖(sibling feature-keycloak-reverse-proxy-headers / feature-keycloak-https-termination-caddy-nginx 소유) → 여기 재진술하지 않고 §엣지·실패·의존 에 의존 링크로만 둔다 (R3 OUT_OF_BRANCH_SCOPE).

1. Cloudflare Tunnel (D1) — 부모 D3 선택을 실행하는 named tunnel 셋업 절차

Trace: D1 + CLOUDFLARE-TUNNEL-C1(outbound-only) / C2(inbound 차단 권장) / C3(<UUID>.cfargotunnel.com 자동 부여) / C4(사용자 hostname CNAME → cfargotunnel.com) / C5(cloudflared tunnel route dns, running 아니면 트래픽 없음).

  • UNSUPPORTED_IMPL_DECISION: (1) tunnel/도메인 명명(kc.example.com, <name>)은 예시값 — 사용자가 소유·위임한 Cloudflare 관리 도메인에 종속하며 raw 근거 없음(trade-off: 구체 도메인은 실 확장 시점 확정). (2) step 4 ingress config.yml 문법(ingress: 블록 / service: 매핑)은 CLOUDFLARE-TUNNEL-C1(outbound-only)이 증명하지 않는 미근거 detail(trade-off: ingress 규칙 공식 페이지 미수집 — 실 셋업 시 Cloudflare Tunnel config.yml 문서 참조). documented-only 이므로 둘 다 실 확장 시점 확정.
단계 명령 / 설정 근거 결과
1. 전제·인증 Cloudflare account + Cloudflare DNS 로 위임한 도메인 1개 → cloudflared tunnel login (브라우저 인증 → cert.pem) (계정 전제 — raw 밖) named tunnel + 사용자 CNAME 가능 조건
2. tunnel 생성 cloudflared tunnel create <name> CLOUDFLARE-TUNNEL-C3 tunnel UUID + <UUID>.cfargotunnel.com 자동 부여
3. DNS 라우팅 cloudflared tunnel route dns <UUID-or-NAME> kc.example.com CLOUDFLARE-TUNNEL-C4, C5 사용자 hostname → cfargotunnel.com CNAME 생성 (단 tunnel running 전엔 트래픽 없음)
4. ingress config.ymlingress: 블록에 kc.example.comservice: http://localhost:8080(Keycloak) 매핑 CLOUDFLARE-TUNNEL-C1(outbound-only) + UNSUPPORTED_IMPL_DECISION(ingress 문법 미근거) origin→Cloudflare outbound, ingress 규칙으로 Keycloak 라우팅
5. 구동 cloudflared tunnel run <name> CLOUDFLARE-TUNNEL-C1, C2 EC2 SG inbound 0 개로 public HTTPS 노출, TLS 는 Cloudflare edge 종단

2. ngrok (D2) — quick tunnel 셋업 절차

Trace: D2 + NGROK-C1(ngrok http <port> random HTTPS hostname) / C3(random hostname = Domain object 미매칭) / C4(bring-your-own-domain 절차) + GOOGLE-REDIR-C3(exact match → URL 변경 시 재등록).

  • UNSUPPORTED_IMPL_DECISION: "재시작마다 hostname 변경" 은 NGROK-C1 인용 범위 밖(관행) → §검증해야 할 주장으로 이관해 별도 확인(trade-off: free plan 정책 페이지 미수집 상태에서 단정 금지).
단계 명령 / 설정 근거 결과
0. 전제 계정 가입 후 ngrok config add-authtoken <token> (authtoken 등록) (계정 전제 — raw 밖) ngrok agent 인증 완료
1. 임시 URL ngrok http 8080 NGROK-C1, C2(scheme https default) https://<random>.ngrok.app 발급
2. URL 변동성 (재시작) NGROK-C3 random hostname → reserved Domain 미매칭 → 세션마다 URL 변경 가능 → Google Console redirect_uri 재등록(GOOGLE-REDIR-C3)
3. 고정 URL(선택) Domain record 생성 + DNS CNAME + matching hostname 으로 endpoint 생성 NGROK-C4 고정 URL 확보(단 free plan 가부는 미확인 — §검증)

3. Google Cloud Console redirect URI 등록 제약 (D1·D2 공통)

Trace: GOOGLE-REDIR-C2(host = raw IP 금지, localhost 예외) + GOOGLE-REDIR-C3(등록값과 byte-level exact match, 불일치 시 redirect_uri_mismatch).

  • OUT_OF_BRANCH_SCOPE: 등록할 broker endpoint URL 의 정확한 형식(/realms/{realm}/broker/google/endpoint + KC_HTTP_RELATIVE_PATH 결합)은 sibling feature-keycloak-reverse-proxy-headers / feature-keycloak-google-redirect-uri-policy 소유 → 링크만, 재진술 금지.
  • 등록 host 는 도메인 필수(raw IP 금지, GOOGLE-REDIR-C2) → D1/D2 의 public URL 이 이 제약을 만족시키는 이유.
  • 등록값은 실제 요청 redirect_uri 와 정확히 일치(GOOGLE-REDIR-C3) → D2(ngrok random URL) 의 갱신 burden 이 여기서 발생.
  • stable callback은 <UUID>.cfargotunnel.com 또는 trycloudflare.com 주소가 아니라 Cloudflare가 관리하는 custom hostname을 사용한다. 그 hostname의 Google 등록 성공은 §검증해야 할 주장으로 남긴다.

엣지·실패·의존

정상 경로(public URL 확보 → Google redirect 통과) 외에 실 확장 시 부딪힐 실패/엣지와 다른 branch 계약 의존을 미리 열거.

  • 실패·엣지 경로:
    • ngrok URL drift — free plan 재시작 시 hostname 변경 가능 → 등록 redirect_uri 와 불일치 → redirect_uri_mismatch(GOOGLE-REDIR-C3). 기대 동작: dev-only로 제한하고 URL 변경 시 Console 갱신, stable callback은 부모 D3가 고른 D1 profile 사용.
    • Cloudflare 라우팅 ≠ 가용cloudflared 미실행 시 CNAME 은 있어도 트래픽 안 흐름(CLOUDFLARE-TUNNEL-C5). 기대: cloudflared tunnel run 데몬 상시 실행(systemd 등).
    • CNAME 전파 지연cloudflared tunnel route dns 직후 DNS 전파 지연(수초~수분)으로 등록 URL 이 일시 미해석 → Google redirect 일시 실패 가능. 기대: dig <host> 로 전파 확인 후 Google 등록/로그인 시도.
    • cfargotunnel 도메인 정책 미검증 — Google 이 <UUID>.cfargotunnel.com generic subdomain 을 거부할 가능성(GOOGLE-REDIR-C2 는 raw IP 만 금지, generic subdomain 은 미보증). 기대: 거부 시 사용자 소유 도메인 CNAME 으로 우회(CLOUDFLARE-TUNNEL-C4). → §검증.
    • outbound 443 차단 환경 — 방화벽이 outbound 를 막으면 cloudflared 미동작(CLOUDFLARE-TUNNEL-C1 "Does not prove" 단서). 기대: egress 443 허용 확인.
    • quick tunnel 혼동trycloudflare.com quick tunnel 은 random URL(ngrok 유사). 정적 도메인이 목표면 named tunnel + 계정 도메인 필요(진행 중 메모).
  • 다른 계약 의존:
    • raw/branch-notes/feature-keycloak-reverse-proxy-headers D7(KC_HOSTNAME=https://kc.example.com) + D1(KC_PROXY_HEADERS=xforwarded) + D6(KC_HTTP_ENABLED=true + KC_PROXY_TRUSTED_ADDRESSES) — 본 branch 가 고른 public host 를 그 branch 가 Keycloak issuer 로 주입. 그 계약(hostname 형식 / D3 relative path /keycloak)이 바뀌면 본 branch 의 redirect URI 등록값도 영향.
    • raw/branch-notes/feature-keycloak-google-redirect-uri-policy D1(broker endpoint URL 을 Authorized redirect URIs 에 등록) + D8(ngrok 운영 burden → Cloudflare 정적 도메인 채택 정당화) — 본 branch D2(ngrok URL 변경 burden)가 그 branch 의 갱신 운영(D8)과 결합.
    • raw/branch-notes/feature-keycloak-https-termination-caddy-nginx D1(Cloudflare edge TLS 종단) — 본 branch D1(Cloudflare Tunnel)과 짝: edge 종단이므로 EC2 내부는 HTTP forward. 본 branch D3(EC2 직결)로 가면 그 branch D2(Caddy) / D3(nginx) + Let's Encrypt 가 TLS 담당.
    • 부모 raw/branch-notes/feature-keycloak-single-ec2-google-federation D3가 provider 우선순위와 채택 조건의 owner다. 본 sub-sub-branch D1/D2는 선택된 provider의 운영 profile만 제공하는 Reference-Only 문서다.

검증해야 할 주장

공식 문서나 사례는 근거지만, 내 프로젝트에서의 동작을 자동으로 보장하지 않는다.

Claim Why uncertain How to verify Status
Cloudflare named tunnel에 연결한 managed custom hostname(예: kc.example.com)이 Google Cloud Console authorized redirect URI 등록과 실제 callback에 통과 GOOGLE-REDIR-C2는 raw IP 금지만 보증하고, Cloudflare DNS·TLS·tunnel 조합의 종단 동작을 직접 보증하지 않음 P3B에서 managed custom hostname을 등록하고 실제 broker login을 수행해 exact match와 callback 성공 확인 needs-confirmation
ngrok free plan 에서 재시작 시마다 hostname 이 변경 NGROK-C1 은 random hostname 만 보증, 재시작 시 변경 정책은 본 raw 인용에 직접 없음 ngrok pricing/free plan 페이지를 raw/official-docs/ 로 등록 → free plan 의 reserved domain 정책 verbatim 확보 planned
Cloudflare Tunnel trycloudflare.com quick tunnel 이 무료 + URL random 본 branch 의 진행 중 메모만 — cloudflare-tunnel-routing-official 인용에 직접 없음 Cloudflare quick tunnel 공식 페이지 발췌 후 raw/official-docs/ 등록 planned
Keycloak KC_HOSTNAME=<tunnel-url> 설정 시 issuer iss 가 정확히 https://<tunnel-url>/realms/{realm} 형식으로 발급 Keycloak hostname 동작은 별도 raw (keycloak-hostname-configuration) 필요 P3B 시연 시 token 발급 후 jwt.io 로 iss 디코딩 → backend issuer-uri 와 byte-level 비교 needs-confirmation

마주친 문제

  • 아직 없음 (문서 단계).

관련 sub-branch

묶음

본 branch 는 leaf — 자식 자료 없음. errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화.

오류 기록

  • (없음)

면접 준비

  • (없음)

관련 일일 노트

완료 후 정리

본 sub-sub-branch는 문서까지만. 실 tunnel 구동 / 도메인 매핑 / Google Console 등록 흐름은 P3A 완료 후 선택적 확장.

  • PR 링크:
  • 리뷰 메모:
  • 머지 결과 / 배포 환경: 해당 없음 (문서 단계, P3B 전체 documented-only)
  • wiki 추출 대상 (verified만, wiki/projects/로만 추출):
    • actually-implemented 항목: 없음
    • locally-verified 항목: 없음
    • prod-verified 항목: 없음
  • 추출하지 않을 항목 (planned / documented-only / abandoned):
    • 본 sub-sub-branch 전체가 documented-only. 추후 부모 P3B의 6 패턴 비교 매트릭스 내 "public 도메인 확보 비교표"로만 인용.