fix: 하네스 제거 및 keycloak 문서 보강
This commit is contained in:
@@ -1 +0,0 @@
|
||||
../../vault/10-projects/ca-skeleton-frontend-operational-contract/project-notes/ca-skeleton-frontend-operational-contract.md
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
../../vault/10-projects/ca-skeleton-operational-contract/project-notes/ca-skeleton-operational-contract.md
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
../../vault/10-projects/invest-money-flow-system/project-notes/invest-money-flow-system.md
|
||||
@@ -0,0 +1,251 @@
|
||||
---
|
||||
title: 자금흐름 관측 시스템 (Money-Flow Observation System)
|
||||
source_type: project-note
|
||||
status: draft
|
||||
confidence: low
|
||||
tags: [project-note, invest, personal-invest, finance]
|
||||
related_projects: []
|
||||
last_reviewed: 2026-06-08
|
||||
diagrams: []
|
||||
architecture_review: 2026-06-08
|
||||
status_label: active
|
||||
project_revision: 1
|
||||
semantic_surface_exclusions:
|
||||
- artifact-registry|legacy hub has no project-local Artifact Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
- contract-gate-registry|legacy hub has no project-local Contract/Gate Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
- flow-stage-registry|legacy hub has no project-local Flow/Stage Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
---
|
||||
|
||||
# 자금흐름 관측 시스템 (Money-Flow Observation System)
|
||||
|
||||
> Layer: `raw/project-notes/` (primary, hub) → 검증된 사실은 `wiki/invest-concepts/`·`wiki/invest-strategy/` 로 추출.
|
||||
> 본 문서는 **개인 투자 "눈 기르기" 프로젝트의 최상위 hub**. 전체 돈의 흐름을 *분야 → 대장주 → 추종주 → 분야간 연관* 으로 체계적으로 관측하기 위한 마스터 설계. 모든 조사(research)·전략·계획·개념 카드가 본 문서로 upward link.
|
||||
> ⚠️ 면허 자문 아님 — [[wiki/invest-strategy/strategy]] §고지.
|
||||
|
||||
## 1. 프로젝트 개요
|
||||
|
||||
- **한 줄 요약**: 전체 주식시장의 *돈의 흐름*을 **거시 자산군 → 산업 섹터/테마 → 대장주 → 추종주** 4층으로 쪼개고, *분야끼리의 상승·하락 연관관계*까지 매일 관측해, "어디서 돈이 빠져 어디로 가는지" 읽는 눈을 데이터로 기른다.
|
||||
- **기간**: 2026-06-08 ~ in-progress (장기 운영형)
|
||||
- **현재 상태**: `active`
|
||||
- **나의 역할 / Role**: 운영자 겸 학습자 (개인 투자 + 시장 관측 훈련)
|
||||
- **저장소 / Repo**: 해당 없음 (이 wiki 자체가 시스템)
|
||||
|
||||
## 2. 문제 정의
|
||||
|
||||
### 2.1 현재 상태의 문제
|
||||
|
||||
- 문제 1: **분야별로 하나씩 카드를 만드는 piecemeal 방식**이라, 전체 그림(어떤 큰 분야들이 있고 어떻게 엮이는지)이 한눈에 안 보인다.
|
||||
- 문제 2: **대장주 → 추종주 서열**이 체계로 없다. "엔비디아 뜨면 하이닉스·소부장이 따라오나?"를 매일 채점할 틀이 없다.
|
||||
- 문제 3: **분야간 연관(로테이션)**이 없다. "달러↑면 어디서 돈이 빠지고 어디로 가나", "금리↑면 성장주 빠지고 가치/방산으로 가나" 같은 *상승·하락 연쇄*를 추적할 구조가 없다.
|
||||
- 문제 4: 무엇이 *검증된 사실*이고 무엇이 *뇌피셜(가설)*인지 섞여서, 근거 없는 단정에 휘둘릴 위험.
|
||||
|
||||
### 2.2 왜 지금 해결해야 하는가
|
||||
|
||||
- 트리거: 100만원 실제 투자 시작([[wiki/invest-plan/active-plan]]) → 시장을 읽는 눈이 실전에서 필요.
|
||||
- 비용: 눈 없이 매매하면 뉴스·테마에 휘둘려 패닉셀/FOMO (전략 ③ 위반).
|
||||
- 기회: 매일 관측이 쌓이면 *어떤 연결이 진짜고 어떤 게 헛소문인지* 데이터로 분별 → 장기 의사결정 품질↑.
|
||||
|
||||
### 2.3 성공 기준
|
||||
|
||||
- 기준 1: **분야 지도(field-map)에 거시 자산군 + 한국 주요 섹터/테마가 카드로 등재**되고, 각 산업 섹터 카드가 *대장주 1~3 + 추종주 2~5* 를 가진다 (현재 13카드, 목표 20+).
|
||||
- 기준 2: 각 카드의 모든 관계 행에 `[검증]/[가설]` 라벨이 있고, **`[검증]` 비율이 시간이 지나며 증가**한다 (관측→research 승급 추적).
|
||||
- 기준 3: **매일 `/invest-daily` 가 "분야 관찰"로 대장주↔추종주 동조 + 분야간 연관을 실측 대조**한다 (예측 vs 실측 채점 누적).
|
||||
- 기준 4: 분야간 연관(로테이션) 가설이 **별도 카드/섹션으로 명시**되고 검증 대상이 된다.
|
||||
|
||||
<!-- section-id: architecture-components -->
|
||||
## 3. 시스템 아키텍처
|
||||
|
||||
> 소프트웨어 컴포넌트가 아니라 *문서 레이어 + 관측 루프*가 아키텍처다. 4층 관측 모델 + 검증 파이프라인.
|
||||
|
||||
### 3.1 4층 관측 모델 + 검증 루프 (Mermaid)
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
subgraph L0["거시 자산군 (Macro)"]
|
||||
DOL[달러] ; RATE[미 10Y 금리] ; OIL[원유] ; GOLD[금] ; USEQ[미국주식] ; BTC[비트코인]
|
||||
end
|
||||
subgraph L1["산업 섹터/테마 (Sector)"]
|
||||
SEMI[반도체] ; BAT[2차전지] ; DEF[방산] ; SHIP[조선] ; BIO[바이오] ; NET[인터넷]
|
||||
end
|
||||
subgraph L2["대장주 (Leader)"]
|
||||
LD["섹터별 선행 종목<br/>예: 엔비디아·SK하이닉스"]
|
||||
end
|
||||
subgraph L3["추종주 (Follower)"]
|
||||
FL["대장주 따라가는 소형주<br/>예: 한미반도체·HPSP"]
|
||||
end
|
||||
|
||||
L0 -->|"인과/상관 (엣지)"| L1
|
||||
L1 -->|대장주 견인| L2
|
||||
L2 -->|동조 낙수| L3
|
||||
L0 -. "분야간 로테이션<br/>(돈이 빠져 옮겨감)" .-> L0
|
||||
|
||||
OBS["매일 /invest-daily<br/>예측 vs 실측 채점"] --> VER["반복 패턴<br/>/invest-research 검증"]
|
||||
VER --> ING["/invest-ingest<br/>[가설]→[검증] 승급"]
|
||||
ING -.->|카드 강화| L1
|
||||
```
|
||||
|
||||
> 핵심: 위 4층(L0~L3)이 *지식*이고, 아래 OBS→VER→ING 가 *그걸 매일 단련하는 루프*. 카드의 연결은 처음엔 `[가설]`, 관측·검증으로 `[검증]` 승급.
|
||||
|
||||
### 3.2 컴포넌트(문서 레이어) 책임 분담
|
||||
|
||||
| 레이어 | 문서 | 역할 |
|
||||
|---|---|---|
|
||||
| 지도 허브 | [[wiki/invest-concepts/field-map]] | 전체 분야(노드) 목차 + 2층 분류 |
|
||||
| 거시 카드 (L0) | [[wiki/invest-concepts/field-dollar]] 등 6장 | 자산군별 drivers·연결·관찰지표 |
|
||||
| 섹터 카드 (L1+대장주/추종주 L2·L3) | [[wiki/invest-concepts/field-semiconductors]] 등 7장 | 섹터 drivers·연결 + **대장주/추종주 표** |
|
||||
| 일일 관측 | `raw/invest-daily/` (`/invest-daily`) | 매일 예측 vs 실측 채점 (루프 엔진) |
|
||||
| 심층 검증 | `raw/invest-research/` (`/invest-research`) | 의심 관계 3표 적대적 검증 |
|
||||
| 승급 | `/invest-ingest` | 검증된 관계를 카드에 `[검증]` 반영 |
|
||||
| 전략/계획 | [[wiki/invest-strategy/strategy]] · [[wiki/invest-plan/active-plan]] | 매매 규칙 + 활성 계획 |
|
||||
| 원장 | [[raw/invest-ledger/ledger]] | 실제 매매 사실 기록 |
|
||||
|
||||
### 3.3 외부 의존성
|
||||
|
||||
| 외부 | 용도 | 장애 시 |
|
||||
|---|---|---|
|
||||
| deep-research(WebSearch/Fetch) | 수치·관계 검증 | 검증 보류 → `[가설]` 유지 |
|
||||
| 시장 데이터(증권사·지수) | 일일 관측 입력 | 수동 입력 / 비움(추측 금지) |
|
||||
|
||||
<!-- section-id: runtime-flow -->
|
||||
## 4. 핵심 시퀀스
|
||||
|
||||
<!-- section-id: sequence -->
|
||||
### 4.1 일일 관측 루프 (대장주↔추종주 + 분야간 연관 채점)
|
||||
|
||||
**시나리오**: 매일 아침 `/invest-daily` 실행 시 카드 예측을 실측과 대조.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor Me as 나
|
||||
participant CMD as /invest-daily
|
||||
participant CARD as 분야 카드(field-map)
|
||||
participant MKT as 시장 데이터
|
||||
participant NOTE as raw/invest-daily/오늘.md
|
||||
|
||||
Me->>CMD: 실행
|
||||
CMD->>MKT: 거시·섹터·대장주 시세 조사(출처+시점)
|
||||
CMD->>CARD: 오늘 움직인 카드의 "연결"·"대장주/추종주" 예측 읽기
|
||||
CMD->>NOTE: 분야 관찰 표 채움
|
||||
alt 예측대로 (확인)
|
||||
CMD->>NOTE: "달러↑→금↓ 맞음 ✓ / 엔비디아↑→하이닉스 따라옴 ✓"
|
||||
else 어긋남 (반증)
|
||||
CMD->>NOTE: "예측과 다름 ✗ + 왜인지 가설 메모"
|
||||
end
|
||||
CMD-->>Me: 경로 + "반복 패턴은 /invest-research 로 검증"
|
||||
Note over Me,CARD: 같은 패턴 반복 확인 → /invest-research → /invest-ingest → 카드 [가설]→[검증]
|
||||
```
|
||||
|
||||
## 5. 데이터 모델
|
||||
|
||||
> 엔터티 5개 미만 — 글로만. 노드(분야 카드) ─wikilink엣지─ 노드. 카드 안에 대장주/추종주 행(종목). Obsidian 그래프 = 데이터 모델 시각화.
|
||||
|
||||
## 6. 기술 결정
|
||||
|
||||
> **Legacy reference (v1).** 아래 비교표는 rationale을 보존한다. project-wide 결정의 stable owner와 branch 상속 기준은 §6.1 registry다.
|
||||
|
||||
| 결정 영역 | 선택 | 검토한 대안 | 채택 이유 | 트레이드오프 | 근거 |
|
||||
|---|---|---|---|---|---|
|
||||
| 지식 구조 | 분야 카드(노드)+wikilink(엣지) | 단일 거대 문서 / 관계카드 | Obsidian 그래프=지도, 분야별 근거 추적 | 카드 수 관리 부담 | [[docs/superpowers/specs/2026-06-08-invest-field-map-design]] |
|
||||
| 근거 규율 | 모든 관계 `[검증]/[가설]` 라벨 | 라벨 없음 | 뇌피셜·환각 차단(출처 없는 단정 금지) | 작성 번거로움 | [[wiki/invest-strategy/strategy]] §고지 |
|
||||
| 종목 서열 | 대장주/추종주 표(섹터 카드) | 종목별 개별 카드 | 유지 부담↓, 동조 관측에 충분 | 종목 단위 깊이↓ | (본 노트 §2.2) |
|
||||
| 검증 방식 | deep-research 3표 적대적 | 단일 패스 | 금융 수치 환각 방어 | 무거움(분당) | [[raw/invest-research/2026-06-08-broad-equity-etf-100man-candidates]] |
|
||||
|
||||
<!-- section-id: project-decisions -->
|
||||
## 6.1 안정 결정 레지스트리
|
||||
|
||||
| Decision ID | Revision | Domain | Decision Summary | Status | Owner | Evidence |
|
||||
|---|---:|---|---|---|---|---|
|
||||
| `DEC-INVEST-MONEY-FLOW-SYSTEM-KNOWLEDGE-GRAPH-001` | 1 | `knowledge-graph` | 분야 카드를 node, wikilink를 edge로 사용한다 | `active` | [[raw/project-notes/invest-money-flow-system]] | §6 `지식 구조`; [[docs/superpowers/specs/2026-06-08-invest-field-map-design]] |
|
||||
| `DEC-INVEST-MONEY-FLOW-SYSTEM-EVIDENCE-LABEL-001` | 1 | `evidence-label` | 모든 관계를 검증 또는 가설로 명시한다 | `active` | [[raw/project-notes/invest-money-flow-system]] | §6 `근거 규율`; [[wiki/invest-strategy/strategy]] §고지 |
|
||||
| `DEC-INVEST-MONEY-FLOW-SYSTEM-EQUITY-HIERARCHY-001` | 1 | `equity-hierarchy` | 섹터 카드 안에 대장주·추종주 표를 둔다 | `active` | [[raw/project-notes/invest-money-flow-system]] | §6 `종목 서열`; §2.2 |
|
||||
| `DEC-INVEST-MONEY-FLOW-SYSTEM-RESEARCH-VALIDATION-001` | 1 | `research-validation` | 관계 승급 검증은 deep-research 3표 적대적 절차를 사용한다 | `active` | [[raw/project-notes/invest-money-flow-system]] | §6 `검증 방식`; [[raw/invest-research/2026-06-08-broad-equity-etf-100man-candidates]] |
|
||||
|
||||
<!-- section-id: implementation-boundaries -->
|
||||
## 7. 비기능 요구사항
|
||||
|
||||
- **지속가능성(가장 중요)**: 매일 *전 분야*가 아니라 *그날 움직인 분야*만 관측 → 부담 분산. 분야는 배치로 천천히 확장.
|
||||
- **정확성**: 모든 수치 출처+조사시점. 미검증은 `[가설]` 명시.
|
||||
- 성능/가용성/보안/DR: 해당 없음(개인 문서 시스템).
|
||||
|
||||
<!-- section-id: project-work-items -->
|
||||
## 8.0 실행계획
|
||||
|
||||
| Work Item ID | branch slug | 완료 조건 (측정가능) | Applies Decisions | Dependencies | Status |
|
||||
|---|---|---|---|---|---|
|
||||
| `WI-INVEST-MONEY-FLOW-SYSTEM-001` | `feature-macro-asset-cards` | 거시 자산군 카드 6개가 생성되고 상호 link된다 | `DEC-INVEST-MONEY-FLOW-SYSTEM-KNOWLEDGE-GRAPH-001@1`, `DEC-INVEST-MONEY-FLOW-SYSTEM-EVIDENCE-LABEL-001@1` | - | `documented-only` |
|
||||
| `WI-INVEST-MONEY-FLOW-SYSTEM-002` | `feature-kr-sector-leader-follower` | 한국 섹터 카드 6개가 각각 대장주·추종주 표를 가진다 | `DEC-INVEST-MONEY-FLOW-SYSTEM-EQUITY-HIERARCHY-001@1`, `DEC-INVEST-MONEY-FLOW-SYSTEM-EVIDENCE-LABEL-001@1` | `WI-INVEST-MONEY-FLOW-SYSTEM-001` | `documented-only` |
|
||||
| `WI-INVEST-MONEY-FLOW-SYSTEM-003` | `feature-cross-field-rotation-map` | 분야간 상승·하락 연쇄가 최소 1개 관계로 명시되고 검증 대상화된다 | `DEC-INVEST-MONEY-FLOW-SYSTEM-KNOWLEDGE-GRAPH-001@1`, `DEC-INVEST-MONEY-FLOW-SYSTEM-EVIDENCE-LABEL-001@1` | `WI-INVEST-MONEY-FLOW-SYSTEM-002` | `planned` |
|
||||
| `WI-INVEST-MONEY-FLOW-SYSTEM-004` | `feature-leader-follower-verification` | 섹터별 가설 중 최소 1개가 research evidence로 검증 승급된다 | `DEC-INVEST-MONEY-FLOW-SYSTEM-RESEARCH-VALIDATION-001@1`, `DEC-INVEST-MONEY-FLOW-SYSTEM-EQUITY-HIERARCHY-001@1` | `WI-INVEST-MONEY-FLOW-SYSTEM-002` | `planned` |
|
||||
| `WI-INVEST-MONEY-FLOW-SYSTEM-005` | `feature-additional-kr-themes` | 원자력·자동차·엔터·로봇 후보가 card와 link 구조로 추가된다 | `DEC-INVEST-MONEY-FLOW-SYSTEM-KNOWLEDGE-GRAPH-001@1`, `DEC-INVEST-MONEY-FLOW-SYSTEM-EQUITY-HIERARCHY-001@1` | `WI-INVEST-MONEY-FLOW-SYSTEM-002` | `planned` |
|
||||
| `WI-INVEST-MONEY-FLOW-SYSTEM-006` | `feature-accumulation-signal-rules` | 검증된 분야 최소 1개에 전략 연동 매수신호 규칙이 기록된다 | `DEC-INVEST-MONEY-FLOW-SYSTEM-RESEARCH-VALIDATION-001@1`, `DEC-INVEST-MONEY-FLOW-SYSTEM-EVIDENCE-LABEL-001@1` | `WI-INVEST-MONEY-FLOW-SYSTEM-004` | `planned` |
|
||||
|
||||
## 8.1 Legacy Branch 로드맵
|
||||
|
||||
> **Legacy reference (v1).** 기존 priority 표는 navigation용으로 보존하며 stable ID·decision pin·dependency의 SSOT는 위 Work Item Registry다.
|
||||
|
||||
> 소프트웨어 branch 대신 *분야 배치*로 분해. 각 배치가 "끝났다"의 측정가능 조건.
|
||||
|
||||
| 배치 slug | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|
||||
|---|---|---|---|
|
||||
| `feature-macro-asset-cards` | 거시 자산군 6카드 + 상호 연결 | P1 ✅ done | - |
|
||||
| `feature-kr-sector-leader-follower` | 한국 섹터 6카드 + 각 대장주/추종주 표 | P2 ✅ done(가설) | macro |
|
||||
| `feature-cross-field-rotation-map` | **분야간 연관(로테이션) 카드/섹션** — "달러↑→어디 빠지고 어디로" 같은 상승/하락 연쇄를 명시·검증 대상화 | P3 ⏳ | sector |
|
||||
| `feature-leader-follower-verification` | 섹터별 `/invest-research`로 대장주/추종주 동조를 `[가설]`→`[검증]` 1개+ 승급 | P4 | sector |
|
||||
| `feature-additional-kr-themes` | 원자력·자동차·엔터·로봇 등 추가 테마 카드 배치 | P5 | sector |
|
||||
| `feature-accumulation-signal-rules` | 검증된 분야부터 "언제 모으기 시작" 매수신호 규칙(전략 연동) | P6 | verification |
|
||||
|
||||
> ⚠️ **다음 핵심 = P3 분야간 연관(로테이션)**. 지금 카드들은 *분야 안*(대장주↔추종주)과 *일부 분야간*(달러↔금) 만 있고, "돈이 A에서 빠져 B로 간다"는 *로테이션 지도*가 아직 약함. 이게 당신이 말한 "각 분야별 상승·하락 연관"의 핵심.
|
||||
|
||||
## 8. 묶음
|
||||
|
||||
<!-- GENERATED: branches:start -->
|
||||
<!-- GENERATED: branches:end -->
|
||||
|
||||
> generated reverse view는 child branch의 v2 contract migration 후 채운다. 기존 수기 Cluster는 그 전까지 보존한다.
|
||||
|
||||
### 8.6 Derived/연결 문서
|
||||
|
||||
- 전략: [[wiki/invest-strategy/strategy]]
|
||||
- 활성 계획: [[wiki/invest-plan/active-plan]]
|
||||
- 분야 지도 허브: [[wiki/invest-concepts/field-map]]
|
||||
- 거시 카드: [[wiki/invest-concepts/field-dollar]] · [[wiki/invest-concepts/field-us-rates]] · [[wiki/invest-concepts/field-oil]] · [[wiki/invest-concepts/field-gold]] · [[wiki/invest-concepts/field-us-equity]] · [[wiki/invest-concepts/field-bitcoin]]
|
||||
- 섹터 카드: [[wiki/invest-concepts/field-semiconductors]] · [[wiki/invest-concepts/field-bigtech-ai]] · [[wiki/invest-concepts/field-secondary-battery]] · [[wiki/invest-concepts/field-defense]] · [[wiki/invest-concepts/field-shipbuilding]] · [[wiki/invest-concepts/field-bio-pharma]] · [[wiki/invest-concepts/field-internet-platform]]
|
||||
- cluster 색인: [[wiki/invest/invest-hub]]
|
||||
- 원장: [[raw/invest-ledger/ledger]]
|
||||
|
||||
### 8.2 근거 자료 (조사 증거)
|
||||
|
||||
- [[raw/invest-research/2026-06-08-broad-equity-etf-100man-candidates]] — 광범위 ETF 후보·MDD
|
||||
- [[raw/invest-research/2026-06-08-isa-vs-general-account-no-income]] — 무소득 ISA vs 일반계좌
|
||||
- [[raw/invest-research/2026-06-08-korean-broad-etf-ticker-comparison]] — 국내상장 ETF 종목 비교
|
||||
- [[raw/invest-research/2026-06-05-passive-diversification-behavior]] — 패시브·분산·행동격차
|
||||
- [[raw/invest-research/2026-06-05-stoploss-takeprofit-tax-accounts]] — 손절·익절·절세계좌
|
||||
- 설계: [[docs/superpowers/specs/2026-06-08-invest-field-map-design]]
|
||||
|
||||
## 9. 검증 등급
|
||||
|
||||
| 영역 | 등급 | 근거 |
|
||||
|---|---|---|
|
||||
| 4층 관측 모델·카드 구조 | `documented-only` | 본 설계 + 카드 13장 생성 |
|
||||
| 대장주/추종주 종목·동조 | `planned`(전부 `[가설]`) | 미검증 — research 필요 |
|
||||
| 분야간 로테이션 | `planned` | P3 미착수 |
|
||||
| ETF·세금·계좌 결정 | `locally-verified` | research 3표 검증 |
|
||||
|
||||
## 10. 면접·외부 공개 답변 경계
|
||||
|
||||
- 외부 공개 대상 아님 (개인 투자 관리). `[가설]` 종목 관계는 어디에도 사실로 인용 금지.
|
||||
|
||||
## 13. 관련 개념
|
||||
|
||||
- [[wiki/invest-concepts/field-map]] · [[wiki/invest-strategy/strategy]] · [[wiki/invest-plan/active-plan]]
|
||||
|
||||
## 14. 다음 단계
|
||||
|
||||
> 📋 **완성까지의 상세 마스터 플랜**: [[docs/superpowers/plans/2026-06-08-invest-system-buildout]] — 완성 정의 + 전체 분야 목표표(거시 8 + 한국 섹터 17) + 로테이션 설계 + Phase 0~6 로드맵. *이 플랜을 완수하면 목표 구조가 완성된다.*
|
||||
|
||||
- [ ] **Phase 1 — 분야 분류 완성**: 거시 2 + 한국 섹터 10 카드 `[가설]` 스캐폴드 (자동차·금융·철강·화학·원자력·로봇·게임·엔터·화장품·통신유틸).
|
||||
- [ ] **Phase 2 — 분야간 로테이션 지도** (`field-rotation`) — "달러/금리↑ → 어디서 빠져 어디로" 상승·하락 연쇄 (당신이 원한 핵심).
|
||||
- [ ] 섹터별 `/invest-research`로 대장주/추종주 동조 검증 → `[가설]`→`[검증]`.
|
||||
- [ ] 추가 한국 테마(원자력·자동차·엔터·로봇) 배치.
|
||||
- [ ] `/project-spec` 로 본 노트를 더 깊게(조사 기반) 보강 + readiness 게이트.
|
||||
@@ -1 +0,0 @@
|
||||
../../vault/10-projects/keycloak-patterns-overview/project-notes/keycloak-patterns-overview.md
|
||||
@@ -0,0 +1,936 @@
|
||||
---
|
||||
title: keycloak-patterns Overview (canonical SSOT)
|
||||
source_type: project-note
|
||||
status: raw
|
||||
confidence: medium
|
||||
tags: [project-note, keycloak-patterns, oauth2, oidc, auth]
|
||||
related_projects: [keycloak-patterns]
|
||||
last_reviewed: 2026-07-14
|
||||
diagrams: [keycloak-patterns/architecture-p1a-edge-no-google-2026-05-26, keycloak-patterns/architecture-p1b-edge-google-2026-05-26, keycloak-patterns/architecture-p2a-cluster-internal-no-google-2026-05-26, keycloak-patterns/architecture-p2b-cluster-internal-google-2026-05-26, keycloak-patterns/architecture-p3a-single-ec2-no-google-2026-05-26, keycloak-patterns/architecture-p3b-single-ec2-google-2026-05-26]
|
||||
architecture_review: 2026-05-26
|
||||
status_label: active
|
||||
project_revision: 1
|
||||
url:
|
||||
semantic_surface_exclusions:
|
||||
- artifact-registry|legacy hub has no project-local Artifact Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
- contract-gate-registry|legacy hub has no project-local Contract/Gate Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
- flow-stage-registry|legacy hub has no project-local Flow/Stage Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
---
|
||||
|
||||
# keycloak-patterns Overview
|
||||
|
||||
> 본 문서는 keycloak-patterns 프로젝트의 **canonical SSOT** (Single Source of Truth)입니다.
|
||||
> 모든 branch-note는 본 문서를 기준으로 작업하며, 본 문서가 정의하지 않은 결정은 sub-branch 내부에서 자체 결정.
|
||||
>
|
||||
> **위계 (CLAUDE.md §2/§15)**:
|
||||
> - 본 문서: 프로젝트 전반 정의 (canonical SSOT)
|
||||
> - `raw/branch-notes/feature-keycloak-patterns.md`: 작업 root (전체 진행 인덱스)
|
||||
> - `raw/branch-notes/feature-keycloak-<pattern-name>.md`: 6 패턴별 sub-branch (예: `feature-keycloak-edge-forwardauth-no-google`)
|
||||
> - `raw/branch-notes/feature-keycloak-<implementation-topic>.md`: 패턴별 세부 단계 sub-sub-branch (예: `feature-keycloak-oauth2-proxy-oidc-flow`)
|
||||
> - 계층 정보는 frontmatter `parent_branch:` + 각 파일의 `## Parent` 섹션에서 추적
|
||||
> - 구현 코드: `/home/donghyeon/workspace/keycloak-patterns/` (별도 git repo, LLM Wiki 외부)
|
||||
|
||||
## 1. 프로젝트 정의
|
||||
|
||||
### 한 줄 설명
|
||||
|
||||
vanilla JS 클라이언트 + Keycloak Authorization Server + Spring Boot 연동의 **4가지 인증 통합 아키텍처 패턴(AP1~AP4)** 을 비교·이해·구현하는 학습 + 구현 프로젝트. (분류축 교정 2026-07-14 — 기존 "6가지 배치×federation" 은 §2 로 재편; 배포 토폴로지·Google federation 은 각 패턴에 얹는 cross-cutting 변형.)
|
||||
|
||||
### 본인 역할
|
||||
|
||||
- 개인 프로젝트
|
||||
- 본인이 맡은 영역: 전 영역 (인프라 + 백엔드 + 프론트 + Keycloak 운영 학습)
|
||||
- 기간: 2026-05-25 ~ 미정
|
||||
|
||||
### 목표 (WHY)
|
||||
|
||||
면접에서 "왜 이 배치를 택했나" / "Google 로그인이 붙으면 흐름이 어떻게 바뀌나" / "BFF vs SPA Direct OIDC trade-off는?"에 자신 있게 답할 수 있는 수준의 이해 + **4 인증-아키텍처 패턴 실 구현**.
|
||||
|
||||
> **분류축 교정 (2026-07-14)**: 기존 목표는 "배치×federation 6패턴 이해 + P3A 한정 실 구현" 이었으나, 그 6축은 *배포 토폴로지 × Google* 이라 keycloak 인증 아키텍처를 2종만 exercise 하고 AP2·AP3 는 누락돼 있었다. §2 에서 primary 축을 **인증 통합 아키텍처 4패턴** 으로 교정하고, 이 4패턴 실 구현을 새 목표로 삼는다. 상세 근거·매핑은 §2.
|
||||
|
||||
### 성공 기준 (측정가능, R1)
|
||||
|
||||
> "잘 이해했다" 류 정성 표현 금지. 각 패턴이 "끝났다"고 말할 검증 가능한 결과로 정의한다. done-bar = **E2E 검증 + 그 패턴의 signature 함정 의도 재현 → 해결** (2026-07-14 사용자 확정).
|
||||
|
||||
**패턴 공통 done (4 패턴 각각 + Google cross-cutting 1회):**
|
||||
|
||||
1. **E2E**: 브라우저 로그인 → 토큰 발급 → 보호 API `200 OK` 를 로컬(`docker compose up`)에서 관찰 — curl 로그 또는 스크린샷 증거 첨부. 등급 `locally-verified`.
|
||||
2. **Signature 함정 재현 → 해결**: 그 패턴의 대표 실패를 의도적으로 재현(4xx / 토큰 누출)한 뒤 고치고, before/after 를 기록.
|
||||
|
||||
| 패턴 | E2E 성공 신호 | 재현 → 해결할 signature 함정 |
|
||||
|---|---|---|
|
||||
| **AP1** SPA-direct + Resource Server | SPA 가 받은 access_token 으로 `/api` 200 | (a) `aud` 미검증 → 타 client 토큰 통과 재현 → audience validator 로 401 (b) `KC_HOSTNAME` 미설정 → `iss` mismatch 401 재현 → 설정으로 해결 |
|
||||
| **AP2** Token-Mediating Backend | 백엔드(confidential client)가 발급받은 access_token 을 브라우저에 전달, 브라우저가 RS 직접 호출 200 | refresh token 이 브라우저에 **노출 안 됨**(백엔드만 보유) 을 네트워크 탭 / 응답 바디로 확인 |
|
||||
| **AP3** BFF | 브라우저에 토큰 0개(session cookie 만) 확인, BFF proxy 경유 API 200 | CSRF surface(cookie 자동첨부) 재현 → SameSite / CSRF token 으로 차단 |
|
||||
| **AP4** Edge forward-auth | 미인증 요청 → Keycloak redirect, 인증 후 backend 가 `X-Forwarded-User` 수신 200 | `X-Forwarded-User` 위조로 우회 재현 → NetworkPolicy / SG 로 차단 |
|
||||
| (cross) **Google brokering** | Google 계정 로그인 → Keycloak 사용자 매핑 → 위 패턴 흐름 재개 200 | `email_verified=false` auto-linking 계정탈취 재현 → Confirm Link Existing Account 로 차단 |
|
||||
|
||||
**프로젝트 완료 신호**: 위 표의 4 패턴 + Google cross-cutting 이 모두 `locally-verified` + 트레이드오프 매트릭스 branch 가 4패턴의 {토큰 위치 · 검증 주체 · XSS/CSRF surface · 선택 기준 · keycloak 설정} 을 한 표로 답할 수 있음.
|
||||
|
||||
## 2. 인증 아키텍처 분류 (canonical 분류 축 — 2026-07-14 교정)
|
||||
|
||||
> **분류축 교정 (2026-07-14).** 기존 분류축은 *배치 위치 3 × Google federation 2 = 6 패턴* 이었으나, 이는 **배포 토폴로지 × federation** 축이라 keycloak *인증 아키텍처* 는 2종(edge-forward-auth, SPA-direct)만 exercise 하고 나머지는 변형이었다(P2≡P3 는 auth 동일, B=A+realm 설정). 멘토가 말한 "4 패턴" 은 **인증 통합 아키텍처**(누가 토큰을 쥐고, 누가 인증을 강제하나) 축이며, 이것이 keycloak client 통합의 canonical 축이다. 아래로 primary 축을 교체하고, 기존 6 축은 §2.2 cross-cutting 변형으로 강등한다.
|
||||
>
|
||||
> 근거: [[raw/official-docs/oauth2-browser-based-apps-ietf-draft]] (IETF — 브라우저앱 아키텍처 3종 BFF / Token-Mediating Backend / Browser-based OAuth Client 을 *보안강도 내림차순* 으로 정의), [[raw/company-tech-blogs/curity-bff-pattern-spa]].
|
||||
|
||||
### 2.1 Primary 축 — 인증 통합 아키텍처 4 패턴
|
||||
|
||||
축: **누가 access/refresh token 을 보관하고, 누가 인증을 강제하는가.** IETF `draft-ietf-oauth-browser-based-apps` 의 3 패턴 + 별도 인프라 프록시 강제(oauth2-proxy) = 4.
|
||||
|
||||
| ID | 패턴 | 토큰 위치 | 인증 강제 주체 | 백엔드 keycloak 역할 | 보안강도 (IETF) |
|
||||
|----|------|----------|---------------|---------------------|-----------------|
|
||||
| **AP1** | Browser-based OAuth Client (SPA-direct + Resource Server) | 브라우저(JS) | SPA 자신 (public client + PKCE) | Resource Server — JWKS 로 JWT 검증 | 낮음 (토큰 브라우저 노출) |
|
||||
| **AP2** | Token-Mediating Backend | access → 브라우저, refresh → 백엔드 | 백엔드 (confidential client) 가 토큰 획득 후 access token 만 전달 | confidential client + RS | 중 |
|
||||
| **AP3** | Backend-for-Frontend (BFF) | 백엔드 (session) | 백엔드 (confidential client), 모든 API proxy | confidential client + session holder | 높음 (토큰 브라우저 미노출) |
|
||||
| **AP4** | Edge / Gateway forward-auth | 프록시 (session) | 별도 reverse proxy (oauth2-proxy / Traefik) | 프록시가 OIDC, 백엔드는 헤더 신뢰 (인증코드 0줄) | 프록시 network 격리에 의존 |
|
||||
|
||||
> IETF 보안강도 내림차순 = BFF(AP3) > Token-Mediating(AP2) > Browser-client(AP1). AP4 는 IETF 3종 밖(별도 인프라 프록시)이나 실무의 4번째 패턴.
|
||||
|
||||
### 2.2 Cross-cutting 변형 (별도 패턴 아님 — 각 AP 에 얹음)
|
||||
|
||||
- **배포 토폴로지**: single-EC2(학습·실 구현) / cluster-internal / edge. 인증 아키텍처를 바꾸지 않고 hostname·issuer·network 경계만 바꿈. signature 함정: `KC_HOSTNAME` iss mismatch, reverse-proxy 헤더.
|
||||
- **Google IdP brokering (federation)**: realm 에 Google 을 외부 IdP 로 등록. 노트 실측대로 SPA/Backend **코드 0줄 변경** — 어느 AP 에도 동일하게 얹힘. signature 함정: First Broker Login email auto-linking.
|
||||
|
||||
### 2.3 기존 6 패턴 → 신 4 패턴 매핑 (기존 작업 재배치, 폐기 아님)
|
||||
|
||||
> 기존 34 branch-note 는 폐기하지 않고 아래로 re-map. 실제 rename/re-parent 은 `wiki-doc-author mode=migrate` 로 점진 수행(자동 mv 금지 — wikilink 영향 검토).
|
||||
|
||||
| 기존 (배치×federation) | 신 primary (auth 축) | 신 cross-cutting | 기존 sub-branch |
|
||||
|---|---|---|---|
|
||||
| P1A Edge no-google | **AP4** Edge forward-auth | 배포=edge | [[raw/branch-notes/feature-keycloak-edge-forwardauth-no-google]] |
|
||||
| P1B Edge + Google | **AP4** | +Google brokering | [[raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation]] |
|
||||
| P2A Internal SPA-direct no-google | **AP1** SPA-direct + RS | 배포=internal | [[raw/branch-notes/feature-keycloak-internal-spa-direct-no-google]] |
|
||||
| P2B Internal + Google | **AP1** | 배포=internal, +Google | [[raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation]] |
|
||||
| P3A Single-EC2 no-google | **AP1** SPA-direct + RS | 배포=single-EC2 (실 구현 base) | [[raw/branch-notes/feature-keycloak-single-ec2-no-google]] |
|
||||
| P3B Single-EC2 + Google | **AP1** | 배포=single-EC2, +Google | [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] |
|
||||
| (없음) | **AP2** Token-Mediating Backend | — | 신규 — 기존 6 에 없던 패턴 |
|
||||
| (bff-vs-spa-direct, out-of-scope 비교문서) | **AP3** BFF | — | [[raw/branch-notes/feature-keycloak-bff-vs-spa-direct]] → AP3 비교 근거(FOLD-IN); 실 구현은 신규 `feature-keycloak-bff-oauth2login-session`·`-bff-csrf-samesite-defense` |
|
||||
|
||||
**핵심**: 기존 "6 구현" 은 실제로 auth 아키텍처 2종(AP1, AP4)의 배포·federation 변형이었고 AP2·AP3 는 누락돼 있었다. 신 축은 중복(P2≡P3, B=A+federation)을 제거하고 누락(AP2, AP3)을 채운다 → "6 이 맞나 4 가 맞나" 의 답: **둘은 다른 축이었고, keycloak 을 다 배우려면 auth 축 4패턴이 맞다.**
|
||||
|
||||
## 3. 공통 컴포넌트 & 용어
|
||||
|
||||
- **Keycloak**: OIDC/OAuth2 Authorization Server. Realm / Client / User / Identity Provider 구성.
|
||||
- **Client (vanilla JS / SPA)**: Authorization Code Flow + **PKCE**. client 유형은 패턴별로 다름 — **AP1 은 public client**(토큰 브라우저 보유), **AP2·AP3 은 백엔드가 confidential client**(client secret 보유, 토큰을 백엔드가 획득). AP4 는 SPA 가 아니라 프록시가 OIDC client.
|
||||
- **Backend (API)**: Spring Boot. 패턴별 역할 상이 — AP1/AP4 는 Resource Server(JWT signature + `iss`/`aud`/`exp` 검증), AP2/AP3 는 confidential OAuth client(+ AP3 은 session holder + proxy).
|
||||
- **Edge Proxy** (P1만): oauth2-proxy 또는 Traefik ForwardAuth — 인증 안 된 요청을 Keycloak으로 redirect, 인증 완료 시 backend로 통과.
|
||||
- **IdP Brokering** (B 변형): Keycloak이 Google을 외부 IdP로 등록. 사용자 Google 계정으로 로그인 → Google → Keycloak 사용자 매핑 (First Broker Login Flow) → Keycloak token 발급.
|
||||
- **Token 종류**:
|
||||
- `authorization code`: 1회용 코드 (브라우저 redirect 매개)
|
||||
- `access token` (JWT): API 호출용. 짧은 만료 (5–15분)
|
||||
- `refresh token`: access token 갱신용. 긴 만료 (1–30일)
|
||||
- `ID token` (JWT): 사용자 식별 정보. 백엔드는 보통 사용 안 함, 클라이언트가 사용자 표시용으로 사용.
|
||||
|
||||
<!-- section-id: architecture-components -->
|
||||
## 3-1. 시스템 아키텍처 (System Architecture)
|
||||
|
||||
> 6개 패턴 각각의 컴포넌트 구성도. **`templates/diagram-standards.md` v2 (minimalist) 준수** — 5초/30초 룰, 정점 ≤ 10, 간선 ≤ 8, callout ≤ 1, 80% 회색/흰색 + 강조 색 1~2 정도.
|
||||
>
|
||||
> 작성 도구: **draw.io** (`.drawio` 파일, 저장 경로 `raw/diagrams/keycloak-patterns/`). Mermaid `graph TD` 는 시스템 아키텍처용으로 사용 금지 — Mermaid 는 시퀀스/ER 다이어그램 전용.
|
||||
>
|
||||
> **공통 시각 어휘** (모든 6 패턴 공통):
|
||||
> - **주황 box + 주황 굵은 화살** = 그 패턴의 주인공 (Edge proxy, tunnel, brokering 등)
|
||||
> - **파란 box + 파란 굵은 화살** = SPA-direct OIDC 또는 Keycloak brokering 핵심 경로
|
||||
> - **흰색 box + 회색 가는 화살** = 보조 컴포넌트 / 부차 경로
|
||||
> - **회색 점선 box** = External system (Google OIDC 등)
|
||||
> - **빨간 callout** = 그 패턴의 가장 큰 보안/운영 함정 (정확히 1개)
|
||||
> - **③, ④ 같은 번호** = 시각적 흐름 순서. 본문이 같은 번호로 받아 설명함.
|
||||
|
||||
### 3-1-1. P1A — Edge ForwardAuth (no Google)
|
||||
|
||||
![[raw/diagrams/keycloak-patterns/architecture-p1a-edge-no-google-2026-05-26.drawio]]
|
||||
|
||||
**다이어그램이 답하는 질문**: edge proxy가 인증 게이트일 때, 백엔드는 어떻게 인증 코드 0줄로 동작하는가?
|
||||
|
||||
**4단계 흐름** (다이어그램 ①~④):
|
||||
|
||||
1. `① HTTPS` (강조 — 진입 경로) — User browser 가 Edge zone 의 oauth2-proxy 에 요청
|
||||
2. `② OIDC redirect` — proxy 가 미인증 요청을 Keycloak 으로 redirect (Authorization Code + PKCE)
|
||||
3. `③ 로그인 + token` — Keycloak 로그인 UI 후 token 발급 (점선 = 사용자 매개 redirect)
|
||||
4. `④ X-Forwarded-User` (강조 — 핵심 위탁) — proxy 가 인증 사용자명을 헤더로 backend 에 전달
|
||||
|
||||
**핵심 함정** (헤더 spoofing):
|
||||
- backend 가 `X-Forwarded-User` 헤더만으로 사용자 식별 → ingress 우회 경로 존재 시 위조 가능
|
||||
- 해결: NetworkPolicy (k8s) 또는 SG (AWS) 로 proxy → backend 만 통과시키고, 가능하면 mTLS 추가
|
||||
|
||||
**컴포넌트 책임 (P1A)**:
|
||||
|
||||
| 컴포넌트 | 역할 | 스택 |
|
||||
|---|---|---|
|
||||
| Edge Proxy | OIDC 인증 게이트 — 인증 안 된 요청을 Keycloak으로 redirect | oauth2-proxy 또는 Traefik ForwardAuth |
|
||||
| Backend API | 비즈니스 로직만. 인증 검증은 proxy에 위임. 헤더로 사용자 식별 | Spring Boot 3.x (Spring Security 미사용) |
|
||||
| Keycloak | Authorization Server. 사용자 DB + OIDC discovery | Keycloak 25.x + PostgreSQL 16 |
|
||||
|
||||
**P1A 트레이드오프**:
|
||||
- 장점: backend 가 인증 코드 0줄. 다국적 polyglot 백엔드에 균일하게 인증 적용 용이.
|
||||
- 단점: backend 가 헤더 신뢰 모델 → 네트워크 격리 실패 시 전면 우회.
|
||||
|
||||
**출처 (Sources)**:
|
||||
- oauth2-proxy ForwardAuth — [[raw/branch-notes/feature-keycloak-edge-forwardauth-no-google]]
|
||||
- Traefik ForwardAuth — [[raw/branch-notes/feature-keycloak-edge-forwardauth-no-google]]
|
||||
|
||||
### 3-1-2. P1B — Edge ForwardAuth + Google federation
|
||||
|
||||
![[raw/diagrams/keycloak-patterns/architecture-p1b-edge-google-2026-05-26.drawio]]
|
||||
|
||||
**다이어그램이 답하는 질문**: P1A 에 Google 로그인을 붙이면 Keycloak IdP brokering 만으로 SPA/Backend 변경 없이 가능한가?
|
||||
|
||||
**5단계 흐름** (다이어그램 ①~⑤):
|
||||
|
||||
1. `① HTTPS` — User → oauth2-proxy
|
||||
2. `② OIDC redirect` — proxy → Keycloak (OIDC AS)
|
||||
3. `③ Google 로그인` (강조 — 외부 IdP 위탁 핵심) — Keycloak → Google OIDC
|
||||
4. `④ id_token (email_verified)` (점선 = 외부 호출) — Google → Keycloak, First Broker Login Flow 진입
|
||||
5. `⑤ X-Forwarded-User` — proxy → backend (P1A 와 동일)
|
||||
|
||||
**핵심 함정** (First Broker Login Flow — email-match auto-linking):
|
||||
- Keycloak 기본 옵션이 email 기반 자동 linking 제공
|
||||
- Google 이 `email_verified=false` 인 사용자도 통과시키면 본인 외 사용자의 기존 계정 탈취 가능
|
||||
- 해결: First Broker Login Flow 에서 `Confirm Link Existing Account` 강제 + `email_verified=true` 필수
|
||||
|
||||
**P1A 대비 추가/변화**:
|
||||
- Keycloak ← Google IdP brokering 설정 추가
|
||||
- Backend / proxy 코드는 변경 0줄 — Keycloak Realm 설정만 추가
|
||||
|
||||
**P1B 트레이드오프**:
|
||||
- 장점: SPA/Backend 코드 변경 0줄로 Google SSO 추가
|
||||
- 단점: First Broker Login Flow 설정 실수 시 계정 탈취 위험. Google API 의존성 운영 부담.
|
||||
|
||||
**출처 (Sources)**:
|
||||
- Keycloak IdP brokering — [[raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation]]
|
||||
- First Broker Login Flow 보안 — [[raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation]]
|
||||
|
||||
### 3-1-3. P2A — Cluster-internal SPA-direct (no Google)
|
||||
|
||||
![[raw/diagrams/keycloak-patterns/architecture-p2a-cluster-internal-no-google-2026-05-26.drawio]]
|
||||
|
||||
**다이어그램이 답하는 질문**: Edge proxy 없이 SPA 가 직접 OIDC 할 때, Backend 는 어떻게 JWT 신뢰를 닫는가?
|
||||
|
||||
**4단계 흐름** (다이어그램 ①~④):
|
||||
|
||||
1. `① HTTPS GET (SPA)` — User → nginx 가 호스팅하는 vanilla JS SPA 자원 수령
|
||||
2. `② OIDC + PKCE` (강조 — SPA 가 토큰 보유) — SPA → Keycloak, 직접 token 흐름 (P1 과의 결정적 차이)
|
||||
3. `③ Bearer access_token` (강조 — API 호출) — SPA → Backend, `Authorization: Bearer ...`
|
||||
4. `④ JWKS` (강조 — 신뢰 닫기) — Backend → Keycloak 에서 검증 공개키 조회
|
||||
|
||||
**핵심 함정** (XSS surface):
|
||||
- SPA 가 access/refresh token 을 브라우저 메모리/스토리지에 보유 → XSS 1건 = 세션 전체 탈취
|
||||
- 해결: refresh token 보호가 필요하면 BFF(P1) 로 전환, 또는 httpOnly cookie 전략 검토
|
||||
|
||||
**P1A 대비 차이**:
|
||||
- SPA 가 토큰 직접 보유 → XSS surface ↑, BFF 패턴 검토 가치 있음
|
||||
- Backend 가 JWT validator 코드 보유 (`iss`, `aud`, `exp`, signature) — Spring Security 6.x Resource Server
|
||||
|
||||
**P2A 트레이드오프**:
|
||||
- 장점: 컴포넌트 단순 (proxy 1개 제거). frontend 가 OIDC 흐름 완전 제어 가능.
|
||||
- 단점: XSS surface 확대 + backend 가 JWT 검증 코드 보유 → polyglot 백엔드 마다 구현 필요.
|
||||
|
||||
**출처 (Sources)**:
|
||||
- Spring Security Resource Server — [[raw/branch-notes/feature-keycloak-internal-spa-direct-no-google]]
|
||||
- PKCE 흐름 (RFC 7636) — [[raw/branch-notes/feature-keycloak-internal-spa-direct-no-google]]
|
||||
|
||||
### 3-1-4. P2B — Cluster-internal + Google federation
|
||||
|
||||
![[raw/diagrams/keycloak-patterns/architecture-p2b-cluster-internal-google-2026-05-26.drawio]]
|
||||
|
||||
**다이어그램이 답하는 질문**: P2A 에 Google brokering 을 추가할 때, SPA/Backend 코드는 그대로 둘 수 있는가?
|
||||
|
||||
**5단계 흐름** (다이어그램 ①~⑤):
|
||||
|
||||
1. `① HTTPS GET` — User → nginx SPA
|
||||
2. `② OIDC + PKCE` — SPA → Keycloak (P2A 와 동일)
|
||||
3. `③ Google 로그인` (강조 — 외부 IdP 위탁) — Keycloak → Google
|
||||
4. `④ id_token` (점선 = 외부 호출) — Google → Keycloak, First Broker Login Flow
|
||||
5. `⑤ Bearer + JWKS` — SPA → Backend (Bearer), Backend → Keycloak (JWKS)
|
||||
|
||||
**핵심 함정** (P1B + P2A 중첩):
|
||||
- P1B 의 email-match auto-linking + P2A 의 SPA XSS surface 가 모두 적용됨
|
||||
- 해결: `Confirm Link Existing Account` 강제 + `email_verified=true` + 클라이언트 CSP / sanitize 강화 / 필요 시 BFF(P1) 로 이주
|
||||
|
||||
**P2A 대비 추가/변화**:
|
||||
- Keycloak Realm 에 Google IdP 등록만 추가 (SPA/Backend 변경 0줄)
|
||||
- First Broker Login Flow 보안 옵션 추가 검토 필요
|
||||
|
||||
**P2B 트레이드오프**:
|
||||
- 장점: SPA/Backend 코드 0줄 변경으로 Google SSO 추가
|
||||
- 단점: 두 함정 (auto-linking + XSS) 가 중첩되어 보안 운영 부담 ↑
|
||||
|
||||
**출처 (Sources)**:
|
||||
- Keycloak IdP brokering — [[raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation]]
|
||||
- First Broker Login Flow 보안 — [[raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation]]
|
||||
|
||||
### 3-1-5. P3A — Single EC2 (no Google) — **실 구현 대상**
|
||||
|
||||
![[raw/diagrams/keycloak-patterns/architecture-p3a-single-ec2-no-google-2026-05-26.drawio]]
|
||||
|
||||
**다이어그램이 답하는 질문**: 사용자 요청이 어떤 컴포넌트를 어떤 순서로 거치며 인증되는가?
|
||||
|
||||
**5단계 흐름** (다이어그램 ①~⑤):
|
||||
|
||||
1. `① HTTPS GET /` — User browser 가 nginx 에서 SPA 정적 자원 받음
|
||||
2. `② OIDC + PKCE` (강조 — 핵심 경로) — Browser 가 Keycloak 으로 직접 redirect, Authorization Code + PKCE 흐름
|
||||
3. `③ Bearer token + /api` — SPA 가 받은 access_token 으로 API 호출
|
||||
4. `④ proxy_pass` — nginx 가 Spring Boot 로 reverse proxy
|
||||
5. `⑤ JWKS` (강조 — 검증 경로) — Spring Boot 가 Keycloak 에서 JWT 검증 키 조회
|
||||
|
||||
**핵심 함정** (`KC_HOSTNAME`):
|
||||
- Browser 는 EC2 public hostname 으로 Keycloak 호출 → JWT 의 `iss` claim = public host
|
||||
- Backend 는 `localhost:8180` 로 JWKS 조회 → `iss` 비교 시 mismatch → 401
|
||||
- 해결: docker-compose 에 `KC_HOSTNAME=<public-host>` + `KC_HTTP_ENABLED=true` 명시
|
||||
|
||||
**부차 함정** (`redirect_uri`):
|
||||
- Keycloak client 의 Valid Redirect URIs 등록 시 `localhost` 만 등록 / browser 가 `127.0.0.1` 접근 → mismatch
|
||||
- 해결: 등록과 접근 hostname 1:1 일치 또는 둘 다 등록
|
||||
|
||||
**P3A 트레이드오프**:
|
||||
- 장점: 학습 / 개발 환경 최단 셋업. 단일 docker-compose 로 끝남.
|
||||
- 단점: SPoF — EC2 1대 다운 = 전체 정지. 운영급은 P2A + Keycloak HA cluster.
|
||||
|
||||
**출처 (Sources)**:
|
||||
- KC_HOSTNAME 함정 — [[raw/branch-notes/feature-keycloak-iss-claim-hostname-mismatch]]
|
||||
- redirect_uri 함정 — [[raw/branch-notes/feature-keycloak-docker-compose-stack]]
|
||||
- OIDC PKCE — [[raw/official-docs/oauth2-pkce-rfc-7636]] (또는 해당 official-doc)
|
||||
|
||||
**다이어그램 편집**: Obsidian draw.io 플러그인으로 위 임베드 더블클릭. 또는 [draw.io 데스크탑 앱](https://www.drawio.com/) 사용.
|
||||
|
||||
### 3-1-6. P3B — Single EC2 + Google federation
|
||||
|
||||
![[raw/diagrams/keycloak-patterns/architecture-p3b-single-ec2-google-2026-05-26.drawio]]
|
||||
|
||||
**다이어그램이 답하는 질문**: P3A 에 Google 을 붙이려면 왜 외부 HTTPS endpoint(tunnel/RP) 가 강제되는가?
|
||||
|
||||
**6단계 흐름** (다이어그램 ①~⑥):
|
||||
|
||||
1. `① HTTPS` (강조 — 공개 진입) — User → HTTPS tunnel (cloudflared / ngrok / Caddy)
|
||||
2. `② localhost (HTTP)` (강조 — tunnel 가 localhost 위탁) — tunnel → nginx
|
||||
3. `③ proxy_pass /api` — nginx → Spring Boot Backend
|
||||
4. `④ JWKS` — Backend → Keycloak 검증 키 조회
|
||||
5. `⑤ Google 로그인 (공개 HTTPS)` (강조 — 외부 IdP) — Keycloak → Google
|
||||
6. `⑥ id_token` (점선 = 외부 호출) — Google → Keycloak
|
||||
|
||||
**핵심 함정** (`KC_HOSTNAME` 공개 hostname 강제):
|
||||
- Google 이 검증하는 `redirect_uri` 와 Keycloak issuer 가 모두 공개 HTTPS host 여야 함
|
||||
- P3A 처럼 `localhost` 로 설정 시 Google 흐름 실패 또는 issuer 불일치 401
|
||||
- 해결: `KC_HOSTNAME=<public-host>` + Keycloak Realm Client 의 `Valid Redirect URIs` 를 public URL 로
|
||||
|
||||
**P3A 대비 추가 요구사항**: EC2 를 외부 HTTPS 로 노출 (Google 이 redirect_uri 검증). cloudflared / ngrok / 정식 도메인 + Caddy 중 택일.
|
||||
|
||||
**P3B 트레이드오프**:
|
||||
- 장점: P3A 단순성을 유지하면서 Google SSO 추가 가능
|
||||
- 단점: tunnel/RP 운영 부담 + KC_HOSTNAME 설정 함정 (P3A 의 함정이 hostname 만 바뀌어 재발)
|
||||
|
||||
**출처 (Sources)**:
|
||||
- KC_HOSTNAME 함정 — [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]]
|
||||
- cloudflared / ngrok 비교 — [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]]
|
||||
|
||||
### 3-1-7. AP2 (Token-Mediating) · AP3 (BFF) — needs-diagram
|
||||
|
||||
> 신 primary 축의 AP2·AP3 은 기존 6 `.drawio`(P1A~P3B = AP1 배포 변형 + AP4)에 대응 아키텍처 다이어그램이 없다. **needs-diagram** — 사용자가 draw.io 로 작성 후 아래 백틱을 풀어 활성 임베드로 전환한다. (미작성 파일을 활성 임베드로 두면 9a 린터가 `BROKEN_LINK` 로 잡으므로 placeholder 는 백틱 코드로 비활성.)
|
||||
|
||||
- AP2 Token-Mediating Backend: `![[raw/diagrams/keycloak-patterns/architecture-ap2-token-mediating-2026-07-14.drawio.svg]]`
|
||||
- AP3 Backend-for-Frontend: `![[raw/diagrams/keycloak-patterns/architecture-ap3-bff-2026-07-14.drawio.svg]]`
|
||||
|
||||
작성 시 `rules/diagram-standards.md` v2 (minimalist) 준수 + `wiki-diagram-reviewer` ≥95 별도 확인(게이트는 존재만 판정, 품질 ≥95 는 사용자가 별도 실행).
|
||||
|
||||
<!-- section-id: sequence -->
|
||||
## 3-2. 핵심 시퀀스 (Key Sequences — Mermaid)
|
||||
|
||||
> 토큰 교환 흐름은 패턴마다 다름. happy path + 주요 error path 함께. `templates/project-template.md` §4 표준 준수 — `autonumber`, `actor` vs `participant` 구분, alt/opt/loop 블록, `Note over` 비자명한 동작.
|
||||
|
||||
<!-- section-id: runtime-flow -->
|
||||
### P3A: vanilla JS + PKCE + Keycloak (단일 EC2, no Google)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor User
|
||||
participant SPA as vanilla JS SPA (nginx)
|
||||
participant KC as Keycloak (Authorization Server)
|
||||
participant API as Spring Boot Resource Server
|
||||
|
||||
User->>SPA: 로그인 클릭
|
||||
SPA->>SPA: PKCE code_verifier 생성, code_challenge=SHA256(verifier)
|
||||
SPA->>KC: GET /realms/<realm>/protocol/openid-connect/auth?client_id=<spa>&response_type=code&code_challenge=...&redirect_uri=...
|
||||
KC-->>User: 로그인 폼 redirect
|
||||
User->>KC: id/password 입력
|
||||
alt 자격 증명 유효
|
||||
KC-->>SPA: 302 redirect with authorization code
|
||||
SPA->>KC: POST /token (code + code_verifier)
|
||||
KC-->>SPA: 200 OK {access_token, id_token, refresh_token}
|
||||
SPA->>API: GET /api/v1/<resource> + Authorization: Bearer <access_token>
|
||||
API->>API: JWT 검증 (iss, aud, exp, signature with JWKS)
|
||||
alt JWT 유효
|
||||
API-->>SPA: 200 OK {resource}
|
||||
SPA-->>User: 화면 표시
|
||||
else aud claim mismatch
|
||||
API-->>SPA: 401 Unauthorized {error: invalid_token}
|
||||
SPA-->>User: 에러 + 재로그인 유도
|
||||
end
|
||||
else 자격 증명 무효
|
||||
KC-->>SPA: 302 redirect with error=access_denied
|
||||
SPA-->>User: 에러 표시
|
||||
end
|
||||
```
|
||||
|
||||
> 위 P3A 시퀀스 = **AP1**(SPA-direct + Resource Server)의 single-EC2 배포. 아래는 나머지 3 패턴의 핵심 시퀀스(happy + error path).
|
||||
|
||||
### AP2: Token-Mediating Backend (백엔드 confidential client, access token 만 브라우저 전달)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor User
|
||||
participant B as Browser (SPA)
|
||||
participant BE as Backend (confidential client)
|
||||
participant KC as Keycloak
|
||||
participant API as Resource API
|
||||
|
||||
User->>B: 로그인 클릭
|
||||
B->>BE: GET /login
|
||||
BE->>KC: Authorization Code (confidential client + secret)
|
||||
KC-->>User: 로그인 폼
|
||||
User->>KC: 자격 증명
|
||||
alt 로그인 성공
|
||||
KC-->>BE: access_token + refresh_token
|
||||
Note over BE: refresh_token 은 백엔드만 보유 (브라우저 미전달)
|
||||
BE-->>B: access_token 만 전달
|
||||
B->>API: GET /resource + Bearer access_token
|
||||
API-->>B: 200 OK
|
||||
else access_token 만료 (재발급은 백엔드 경유)
|
||||
API-->>B: 401 invalid_token
|
||||
B->>BE: POST /token/refresh
|
||||
BE->>KC: refresh_grant (백엔드 보유 refresh_token)
|
||||
KC-->>BE: 새 access_token
|
||||
BE-->>B: 새 access_token
|
||||
end
|
||||
```
|
||||
|
||||
### AP3: Backend-for-Frontend (BFF) — 토큰 0개, session cookie 만
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor User
|
||||
participant B as Browser (SPA)
|
||||
participant BFF as BFF (Spring oauth2Login)
|
||||
participant KC as Keycloak
|
||||
participant API as Resource API
|
||||
|
||||
User->>B: 로그인 클릭
|
||||
B->>BFF: GET /oauth2/authorization/keycloak
|
||||
BFF->>KC: Authorization Code (confidential client)
|
||||
KC-->>User: 로그인 폼
|
||||
User->>KC: 자격 증명
|
||||
alt 로그인 성공
|
||||
KC-->>BFF: 302 + authorization code
|
||||
BFF->>KC: POST /token (code + client_secret)
|
||||
KC-->>BFF: access/refresh token (BFF session 에 저장)
|
||||
BFF-->>B: Set-Cookie: SESSION (httpOnly) — 브라우저에 토큰 없음
|
||||
B->>BFF: GET /api/resource (cookie 자동 첨부)
|
||||
BFF->>API: GET /resource + Bearer (BFF 가 토큰 부착)
|
||||
API-->>BFF: 200 OK
|
||||
BFF-->>B: 200 OK
|
||||
else CSRF (cookie 자동첨부 악용)
|
||||
Note over B,BFF: 외부 사이트가 cookie 실린 상태변경 요청 위조
|
||||
BFF-->>B: 403 (SameSite=Lax + CSRF token 검증 실패로 차단)
|
||||
end
|
||||
```
|
||||
|
||||
### Gateway forward-auth (oauth2-proxy, 백엔드 인증코드 0줄)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor User
|
||||
participant Proxy as oauth2-proxy (ForwardAuth)
|
||||
participant KC as Keycloak
|
||||
participant API as Backend API
|
||||
|
||||
User->>Proxy: GET /app (미인증)
|
||||
Proxy->>KC: OIDC redirect (Authorization Code + PKCE)
|
||||
KC-->>User: 로그인 폼
|
||||
User->>KC: 자격 증명
|
||||
alt 인증 성공
|
||||
KC-->>Proxy: token (proxy session 보관)
|
||||
Proxy->>API: GET /app + X-Forwarded-User: <sub>
|
||||
API-->>Proxy: 200 OK (헤더만으로 사용자 식별)
|
||||
Proxy-->>User: 200 OK
|
||||
else 헤더 위조 우회 시도 (signature 함정)
|
||||
Note over API: ingress 우회 경로로 X-Forwarded-User 직접 주입
|
||||
API-->>User: 200 (❌ network 격리 실패 시 위조 성공)
|
||||
Note over API: 방어 = NetworkPolicy/SG 로 proxy→API 만 통과 (+ mTLS)
|
||||
end
|
||||
```
|
||||
|
||||
### P2B → AP4/AP1 + Google: Google IdP federation 추가 흐름 (sub-branch에 상세)
|
||||
|
||||
(Google brokering 은 AP1~AP4 어디에도 코드 0줄로 얹히는 cross-cutting. 상세 다이어그램은 각 sub-branch — [[raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation]], [[raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation]] — 에서.)
|
||||
|
||||
## 4. 인프라 / 기술 스택
|
||||
|
||||
| 영역 | 선택 |
|
||||
|------|------|
|
||||
| 언어 | Java 21 (Backend), JavaScript ES2022+ (vanilla, no framework) |
|
||||
| 프레임워크 | Spring Boot 3.x + Spring Security 6.x (Resource Server) |
|
||||
| Authorization Server | Keycloak 25.x (latest stable as of 2026-05) |
|
||||
| DB (Keycloak) | PostgreSQL 16 |
|
||||
| Web Server (SPA) | nginx (static file serving) |
|
||||
| 컨테이너 | Docker + Docker Compose |
|
||||
| 배포 환경 (P3A 한정) | 단일 EC2 (학습용) — HTTPS termination 선택적 |
|
||||
| OIDC client library | 직접 PKCE 구현 또는 `oidc-client-ts` |
|
||||
|
||||
<!-- section-id: implementation-boundaries -->
|
||||
## 5. 작업 범위 (Project-level Scope)
|
||||
|
||||
### 포함 범위 (2026-07-14 교정 — 4 인증-아키텍처 패턴 실 구현)
|
||||
|
||||
- **4 인증-아키텍처 패턴(AP1~AP4) 실 구현** — 모두 single-EC2 로컬 스택 위에서 E2E(`locally-verified`) + signature 함정 재현→해결 (§1 성공기준, §8.0 branch 분해).
|
||||
- **Google IdP brokering** 을 cross-cutting 변형으로 1회 실 구현(어느 패턴에 얹어도 SPA/Backend 코드 0줄 변경 검증 포함).
|
||||
- 4 패턴 통합 trade-off 매트릭스 (토큰 위치 / 검증 주체 / XSS·CSRF surface / 선택 기준 / keycloak 설정).
|
||||
- 각 패턴의 공식 문서 · 기술블로그 출처 raw 보존 + 채택/대안/비교 구조 명시.
|
||||
- 각 패턴에서 토큰 종류의 교환 시점 · 저장 위치 · 만료 정책 정리.
|
||||
|
||||
### 제외 범위
|
||||
|
||||
- **배포 토폴로지 별도 구현**: 인증 아키텍처는 single-EC2 로 실 구현하고, cluster-internal / edge 는 hostname·issuer·network 차이만 문서화(별도 k8s/Traefik 환경 구축 안 함 — §2.2 cross-cutting).
|
||||
- 다른 OIDC Provider(GitHub / Auth0 / Cognito) federation. Google만.
|
||||
- React/Vue 등 SPA 프레임워크 (vanilla JS 유지).
|
||||
- 모바일 / 네이티브 앱 흐름 (PKCE for native).
|
||||
- mTLS, FAPI(Financial-grade API), DPoP 등 고급 보안 옵션.
|
||||
|
||||
### Deferred — keycloak SERVER-side 심화 트랙 (2026-07-14 명시, 지금 안 함)
|
||||
|
||||
> 사용자 확정: 4 client-integration 패턴 E2E 를 먼저 끝낸 뒤 별도 학습 트랙으로 착수. "keycloak 다 알기" 의 나머지 절반(server/운영 측면)이며, **본 프로젝트 현 phase 의 out-of-scope 이되 폐기가 아니라 후속 트랙으로 예약**한다.
|
||||
|
||||
- **SPI (Service Provider Interface)** — custom authenticator / mapper / event listener 작성.
|
||||
- **HA cluster** — Infinispan 분산 캐시, active-active Keycloak 다중 노드.
|
||||
- **multi-realm / 멀티테넌시** — realm-per-tenant vs client-per-tenant.
|
||||
- **Admin REST API 자동화** — realm/client export·import 를 코드로 (`feature-keycloak-realm-client-export` 씨앗 존재).
|
||||
- **LDAP / user federation** — 외부 사용자 저장소 연동.
|
||||
- **token revocation 심화** — JWT stateless 한계 + blacklist / introspection endpoint.
|
||||
|
||||
**인접 관심사 커버리지 note (9-coverage — silent 누락 방지):**
|
||||
|
||||
- **인가(Authorization) — keycloak roles → Spring `@PreAuthorize`**: 본 4 패턴은 authN(인증) 토큰 흐름에 집중한다. RBAC 인가는 별개 관심사이며 기존 씨앗 `feature-keycloak-idp-mappers-claim-to-role` 존재 — 4 패턴 E2E 후 각 패턴에 얹음(현 phase 명시적 out-of-scope, 폐기 아님).
|
||||
- **Logout / session termination (front/back-channel)**: AP3 BFF session 종료 · AP1 토큰 만료로 부분 커버. refresh rotation + logout 후 session·token 무효화는 `WI-KEYCLOAK-PATTERNS-OVERVIEW-007`(`feature-keycloak-refresh-rotation-and-logout`, §8.0 registry)이 **현 phase** 로 커버한다. **통합 front/back-channel logout 흐름 심화**만 deferred (2026-07-23 경계 명확화 — §8.0 WI-007 과의 이중 서술 해소).
|
||||
|
||||
## 기술 결정
|
||||
|
||||
> **Legacy reference (v1).** 아래 비교표는 rationale과 대안을 보존한다. stable decision owner와 branch 상속 기준은 §6.1 registry다.
|
||||
|
||||
> 프로젝트 차원 기술 결정. 각 결정은 검토한 대안 + 외부근거 wikilink 필수 (근거 없으면 `UNSUPPORTED_DECISION`). 결정별 *깊은* 대안 비교는 branch 단계(`/branch-spec` + `wiki-decision-researcher`)로 위임 — 본 표는 hub 차원 stack/축 결정의 근거 소싱까지.
|
||||
|
||||
| 결정 영역 | 선택 | 검토한 대안 | 채택 이유 | 트레이드오프 | 근거 자료 |
|
||||
|---|---|---|---|---|---|
|
||||
| **분류 primary 축** | 인증 통합 아키텍처 4패턴 (AP1~AP4) | (a) 배포×federation 6패턴(기존) (b) IETF 3패턴만 (c) 멘토 "4패턴" | 6축은 auth 아키텍처 2종만 exercise + AP2/AP3 누락. IETF 3 + edge-proxy = 4 가 keycloak client 통합 canonical 축이며 중복(P2≡P3, B=A+federation) 제거 + 누락(AP2·AP3) 채움 | edge-proxy(AP4)는 IETF 3종 밖 실무 확장 — 표준 인용은 IETF 3까지만 유효 | [[raw/official-docs/oauth2-browser-based-apps-ietf-draft]], [[raw/company-tech-blogs/curity-bff-pattern-spa]] |
|
||||
| **AP1 SPA client 유형** | public client + Authorization Code + PKCE | implicit flow / password grant | implicit·password 는 OAuth 2.1 에서 사실상 배제. PKCE 가 public client 표준 | 토큰이 브라우저에 노출(XSS surface) — AP2/AP3 로 완화 가능 | [[raw/official-docs/oauth2-pkce-rfc-7636]], [[raw/official-docs/oauth-v2-1-draft-ietf]] |
|
||||
| **AP3 BFF 토큰 위치** | 백엔드 session (브라우저 = cookie 만) | 브라우저 저장 (localStorage / memory) | "토큰을 브라우저 밖에 두는 것이 XSS 로부터 보호하는 유일한 방법"(Curity) — 최고 보안강도 | stateful(session store 필요), 모바일 별도 흐름, CSRF surface 증가 | [[raw/company-tech-blogs/curity-bff-pattern-spa]], [[raw/official-docs/oauth2-browser-based-apps-ietf-draft]] |
|
||||
| **AP2 Token-Mediating Backend** | 백엔드 confidential client 가 토큰 획득, access token 만 브라우저 전달 | AP1(전부 브라우저) / AP3(전부 백엔드) | BFF 보다 경량(모든 요청 proxy 불필요) + AP1 보다 refresh token 보호 | access token 은 여전히 브라우저 노출 | [[raw/official-docs/oauth2-browser-based-apps-ietf-draft]] |
|
||||
| **AP4 Edge forward-auth** | oauth2-proxy ForwardAuth | Traefik ForwardAuth / nginx `auth_request` / Spring Cloud Gateway TokenRelay | 백엔드 인증코드 0줄, polyglot 균일 적용 | 헤더 신뢰 모델 → network 격리 실패 시 전면 우회 | [[raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official]], [[raw/official-docs/oauth2-proxy-nginx-integration-official]] |
|
||||
| **Google federation** | Keycloak IdP brokering + First Broker Login hardening | SPA/Backend 가 직접 Google OIDC 호출 | keycloak 이 brokering 흡수 → 앱 코드 0줄. First Broker Login 으로 account linking 제어 | email auto-linking 계정탈취 위험 → Confirm Link Existing Account 필수 | [[raw/official-docs/keycloak-identity-brokering-overview-official]], [[raw/official-docs/keycloak-first-broker-login-flow]] |
|
||||
|
||||
> 소싱 bound(회당 6): 위 6개로 마감. 추가 결정(HTTPS termination D2~D5 등)은 §13 에 기존 근거 보존, deferred server-side 트랙 결정은 후속 `/project-spec` 회차로 이월(`deferred`).
|
||||
|
||||
## 프로젝트 레벨 고정 결정 (Fixed Decisions — branch 간 충돌 방지)
|
||||
|
||||
> **Legacy reference (v1).** F1~F5의 현재 stable owner는 아래 §6.1 registry다. F1은 taxonomy decision에 병합하며 중복 owner row를 만들지 않는다.
|
||||
|
||||
> 여러 branch 가 공유하므로 hub 가 1회 고정. branch 는 재정의 금지, 본 절을 참조만 (SSOT).
|
||||
|
||||
| # | 고정 결정 | SSOT 위치 | 이유 / 충돌 방지 |
|
||||
|---|---|---|---|
|
||||
| F1 | **인증 패턴 taxonomy = §2 (AP1~AP4 + cross-cutting)** | §2 (본 노트) | 모든 branch 는 §2 의 AP-ID 를 인용. 패턴을 branch 에서 재정의하면 6-vs-4 혼선 재발 |
|
||||
| F2 | **done-bar = E2E + signature 함정 재현→해결** | §1 성공기준 | 4 패턴 branch 가 동일 완료 기준 상속. 등급은 `src/` 검증 후 `locally-verified` |
|
||||
| F3 | **단일 공유 realm `keycloak-patterns`, 패턴당 client 1개** (spa-public / token-mediating-confidential / bff-confidential / edge-proxy) | §4 스택 + baseline branch | client 분리로 `aud` claim 충돌 방지. AP1 audience validator 가 client별 aud 검증 가능 |
|
||||
| F4 | **confidential client secret = env var, 미커밋** | baseline branch | AP2·AP3 는 client secret 보유. `.env`/`KC_*` 로 주입, realm export JSON 에 평문 금지 |
|
||||
| F5 | **E2E 실 구현 배포 = single-EC2 docker-compose** (cluster-internal/edge 는 문서만) | §2.2, §5 | 배포 토폴로지는 cross-cutting 이라 auth 아키텍처를 바꾸지 않음 — 실 구현 1벌로 4 패턴 모두 검증 |
|
||||
|
||||
<!-- section-id: project-decisions -->
|
||||
## 6.1 안정 결정 레지스트리
|
||||
|
||||
| Decision ID | Revision | Domain | Decision Summary | Status | Owner | Evidence |
|
||||
|---|---:|---|---|---|---|---|
|
||||
| `DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001` | 1 | `auth-taxonomy` | canonical 분류축은 AP1~AP4 인증 통합 아키텍처와 cross-cutting 변형이다 | `active` | [[raw/project-notes/keycloak-patterns-overview]] | §2; §기술 결정 `분류 primary 축`; F1 |
|
||||
| `DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001` | 1 | `spa-client` | AP1은 public client와 Authorization Code + PKCE를 사용한다 | `active` | [[raw/project-notes/keycloak-patterns-overview]] | §기술 결정 `AP1 SPA client 유형`; [[raw/official-docs/oauth2-pkce-rfc-7636]] |
|
||||
| `DEC-KEYCLOAK-PATTERNS-OVERVIEW-BFF-SESSION-001` | 1 | `bff-session` | AP3는 token을 backend session에 두고 browser에는 cookie만 둔다 | `active` | [[raw/project-notes/keycloak-patterns-overview]] | §기술 결정 `AP3 BFF 토큰 위치`; [[raw/official-docs/oauth2-browser-based-apps-ietf-draft]] |
|
||||
| `DEC-KEYCLOAK-PATTERNS-OVERVIEW-TOKEN-MEDIATING-001` | 1 | `token-mediating` | AP2 backend가 token을 획득하고 access token만 browser에 전달한다 | `active` | [[raw/project-notes/keycloak-patterns-overview]] | §기술 결정 `AP2 Token-Mediating Backend`; [[raw/official-docs/oauth2-browser-based-apps-ietf-draft]] |
|
||||
| `DEC-KEYCLOAK-PATTERNS-OVERVIEW-EDGE-FORWARDAUTH-001` | 1 | `edge-forwardauth` | AP4는 oauth2-proxy ForwardAuth를 사용한다 | `active` | [[raw/project-notes/keycloak-patterns-overview]] | §기술 결정 `AP4 Edge forward-auth`; [[raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official]] |
|
||||
| `DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001` | 1 | `idp-brokering` | Google federation은 Keycloak IdP brokering과 hardened First Broker Login을 사용한다 | `active` | [[raw/project-notes/keycloak-patterns-overview]] | §기술 결정 `Google federation`; [[raw/official-docs/keycloak-first-broker-login-flow]] |
|
||||
| `DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001` | 1 | `acceptance` | done-bar는 E2E success와 signature security failure 재현·해결 evidence다 | `documented-only` | [[raw/project-notes/keycloak-patterns-overview]] | F2; §1 성공 기준 |
|
||||
| `DEC-KEYCLOAK-PATTERNS-OVERVIEW-REALM-CLIENT-001` | 1 | `realm-client` | 단일 realm keycloak-patterns에서 인증 패턴별 client를 분리한다 | `documented-only` | [[raw/project-notes/keycloak-patterns-overview]] | F3; §4 stack |
|
||||
| `DEC-KEYCLOAK-PATTERNS-OVERVIEW-SECRET-BOUNDARY-001` | 1 | `secret-boundary` | confidential client secret은 env var로 주입하고 commit·realm export 평문을 금지한다 | `documented-only` | [[raw/project-notes/keycloak-patterns-overview]] | F4 |
|
||||
| `DEC-KEYCLOAK-PATTERNS-OVERVIEW-DEPLOYMENT-001` | 1 | `deployment` | AP1~AP4 E2E 구현 topology는 single-EC2 docker-compose다 | `documented-only` | [[raw/project-notes/keycloak-patterns-overview]] | F5; §2.2; §5 |
|
||||
|
||||
<!-- section-id: project-work-items -->
|
||||
## 8.0 실행계획
|
||||
|
||||
| Work Item ID | branch slug | 완료 조건 (측정가능) | Applies Decisions | Dependencies | Status |
|
||||
|---|---|---|---|---|---|
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-001` | `feature-keycloak-docker-compose-stack` | Keycloak·PostgreSQL·nginx·Spring 4 containers가 healthy이고 admin console에 접속된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-DEPLOYMENT-001@1` | - | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-002` | `feature-keycloak-realm-client-export` | realm import와 client 4개 등록 후 unauthenticated protected endpoint가 401이고 export가 재현된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-REALM-CLIENT-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-SECRET-BOUNDARY-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-001` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-003` | `feature-keycloak-vanilla-js-spa-pkce` | vanilla JS PKCE login·token 수령·protected API 200이 재현된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-002` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-004` | `feature-keycloak-spring-rs-audience-validator` | foreign audience token 수용 실패를 재현하고 validator 적용 후 401을 검증한다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-003` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-005` | `feature-keycloak-iss-claim-hostname-mismatch` | hostname 미설정 iss mismatch 401과 설정 후 복구 log가 존재한다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-003` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-006` | `feature-keycloak-spa-token-storage-tradeoff` | 저장 위치별 browser token read/XSS surface가 재현되고 선택이 기록된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-003` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-007` | `feature-keycloak-refresh-rotation-and-logout` | refresh rotation과 logout 후 session·token 무효화가 검증된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-004` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-008` | `feature-keycloak-token-mediating-confidential-client` | confidential backend의 code-token 교환과 server-side refresh 보관이 검증된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-TOKEN-MEDIATING-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-SECRET-BOUNDARY-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-002` | `in-progress` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-009` | `feature-keycloak-token-mediating-access-handoff` | browser가 access token으로 API 200을 받고 refresh token은 network response에 존재하지 않는다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-TOKEN-MEDIATING-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-008` | `in-progress` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-010` | `feature-keycloak-bff-oauth2login-session` | browser token 0개와 SESSION cookie만으로 BFF proxy API 200이 재현된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-BFF-SESSION-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-SECRET-BOUNDARY-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-002` | `in-progress` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-011` | `feature-keycloak-bff-csrf-samesite-defense` | CSRF를 재현하고 SameSite와 CSRF token 적용 후 403을 검증한다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-BFF-SESSION-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-010` | `in-progress` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-012` | `feature-keycloak-oauth2-proxy-oidc-flow` | unauthenticated redirect와 login 후 X-Forwarded-User backend 200이 재현된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-EDGE-FORWARDAUTH-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-002` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-013` | `feature-keycloak-nginx-auth-request-integration` | nginx auth_request 통합과 4KB cookie split case가 검증된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-EDGE-FORWARDAUTH-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-012` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-014` | `feature-keycloak-header-spoofing-defense` | forwarded-user spoofing 우회를 재현하고 network isolation 후 차단한다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-EDGE-FORWARDAUTH-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-012` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-015` | `feature-keycloak-idp-brokering-google-client` | Google login·Keycloak user mapping 200과 application diff 0줄이 검증된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-003` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-016` | `feature-keycloak-first-broker-login-flow` | unsafe auto-linking을 재현하고 Confirm Link Existing Account로 차단한다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-015` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-017` | `feature-keycloak-google-claim-attribute-mapping` | Google email·name claim이 Keycloak attribute로 매핑된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-015` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-018` | `feature-keycloak-account-linking-sub-vs-email` | sub와 email linking key의 security comparison과 선택이 기록된다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-016` | `planned` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-019` | `feature-keycloak-four-pattern-tradeoff-matrix` | 4패턴 비교표의 모든 cell이 구현 WI evidence를 가리킨다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001@1`, `DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1` | `WI-KEYCLOAK-PATTERNS-OVERVIEW-003`, `WI-KEYCLOAK-PATTERNS-OVERVIEW-008`, `WI-KEYCLOAK-PATTERNS-OVERVIEW-010`, `WI-KEYCLOAK-PATTERNS-OVERVIEW-012` | `in-progress` |
|
||||
| `WI-KEYCLOAK-PATTERNS-OVERVIEW-020` | `feature-keycloak-patterns` | project governance hub가 AP1~AP4 taxonomy와 child progress index를 유지한다 | `DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001@1` | - | `in-progress` |
|
||||
|
||||
## 실행계획 (Branch decomposition, R4)
|
||||
|
||||
> **Legacy reference (v1).** 아래 2-tier grouping과 priority 설명은 보존한다. Tier-1은 파일이 아닌 group label이며 stable branch ID·decision pin·dependency의 SSOT는 위 Work Item Registry다.
|
||||
|
||||
> **`/project-spec` 핸드오프 섹션.** 2-tier — **Tier-1 = 패턴 parent**(project 직접 자식, `parent_branch:` 비어있음), **Tier-2 = 실제 "1 branch = 1 PR" 단위**(각 Tier-2 가 "1개로 끝낼 양"). 각 branch 의 *네이밍 + 측정가능 목표조건 + 우선순위 + 의존*만 적는다 — 결정 내용·메커니즘은 `/branch <slug>` 생성 후 `/branch-spec` 가 깊게 채운다. slug 는 `rules/naming-conventions.md` §2.1 준수(`feature-` + content-descriptive, numbered hierarchy 없음). 규모: **7 Tier-1 / 19 Tier-2 ≈ 19 PR** — "바로 끝낼 양" 아님(수 주 분량). 기존 27 sub-sub-branch 를 4-패턴으로 re-map + AP2 만 신규.
|
||||
|
||||
### Tier-1 개요 (7 parent)
|
||||
|
||||
| Tier-1 parent slug | 역할 | Tier-2 수 | 우선순위 |
|
||||
|---|---|---|---|
|
||||
| `feature-keycloak-local-stack-baseline` | 4 패턴 공유 로컬 스택 | 2 | P1 |
|
||||
| `feature-keycloak-spa-direct-resource-server` | AP1 | 5 | P2 |
|
||||
| `feature-keycloak-token-mediating-backend` | AP2 (신규) | 2 | P3 |
|
||||
| `feature-keycloak-bff-session-proxy` | AP3 | 2 | P3 |
|
||||
| `feature-keycloak-edge-forwardauth-proxy` | AP4 | 3 | P3 |
|
||||
| `feature-keycloak-google-idp-brokering` | Google cross-cutting | 4 | P4 |
|
||||
| `feature-keycloak-four-pattern-tradeoff-matrix` | 종합 매트릭스 | 1 | P5 |
|
||||
|
||||
> **명명 정합 (2026-07-14 감사 — 파일 ↔ hub 매칭 검증)**:
|
||||
> - **Tier-2 실 구현 19개**: **14개 = 기존 branch-note 파일과 슬러그 정확히 일치 ✓**. 5개 = 신규 예정(`token-mediating-confidential-client`·`-access-handoff`, `bff-oauth2login-session`·`-csrf-samesite-defense`, `four-pattern-tradeoff-matrix`) → `/branch` 로 생성.
|
||||
> - **Tier-1 그룹명 7개는 파일이 아니라 그룹 라벨**이다(파일로 만들면 기존 pattern 노트 §12.1 와 중복되므로 만들지 않음). 각 Tier-2 의 물리적 `parent_branch:` 는 현재 옛 pattern 노트(§12.1)를 가리키고, AP 그룹 소속은 **본 분해표가 SSOT**. 링크 깨짐 0.
|
||||
> - **재-parent 매핑**(각 그룹 실 작업 착수 시 `wiki-doc-author mode=migrate` 로 반영 — 지금은 cosmetic 이라 미실행): Google Tier-2 4개(현 parent P1B `edge-forwardauth-google-federation`) → Google 그룹, `spring-rs-audience-validator`·`spa-token-storage-tradeoff`(현 parent P2A `internal-spa-direct-no-google`) → AP1 그룹. 나머지는 현 parent 가 이미 AP anchor(single-ec2/edge)와 정합.
|
||||
|
||||
### 그룹 0 — 공유 baseline (parent `feature-keycloak-local-stack-baseline`)
|
||||
|
||||
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|
||||
|---|---|---|---|
|
||||
| `feature-keycloak-docker-compose-stack` | `docker compose up` → Keycloak+PostgreSQL+nginx+Spring 4 컨테이너 healthy + KC admin 콘솔 접속 | P1 | - |
|
||||
| `feature-keycloak-realm-client-export` | realm `keycloak-patterns` import + client 4개(spa-public / token-mediating-confidential / bff-confidential / edge-proxy) 등록 + 보호 endpoint 토큰없이 `401` + JSON export 재현 | P1 | `feature-keycloak-docker-compose-stack` |
|
||||
|
||||
### 그룹 1 — AP1 SPA-direct + Resource Server (parent `feature-keycloak-spa-direct-resource-server`)
|
||||
|
||||
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|
||||
|---|---|---|---|
|
||||
| `feature-keycloak-vanilla-js-spa-pkce` | vanilla JS 가 PKCE(code_verifier/challenge)로 로그인 → access_token 수령 → `/api` `200` | P2 | baseline |
|
||||
| `feature-keycloak-spring-rs-audience-validator` | Spring RS 가 JWKS 검증 + `aud` 미검증 → 타 client 토큰 통과 재현 → audience validator 로 `401` | P2 | `feature-keycloak-vanilla-js-spa-pkce` |
|
||||
| `feature-keycloak-iss-claim-hostname-mismatch` | `KC_HOSTNAME` 미설정 → `iss` mismatch `401` 재현 → 설정으로 해결(로그 before/after) | P2 | `feature-keycloak-vanilla-js-spa-pkce` |
|
||||
| `feature-keycloak-spa-token-storage-tradeoff` | 저장위치별 XSS surface 시연(JS 에서 토큰 read 가능 재현) + 저장 전략 결정 기록 | P3 | `feature-keycloak-vanilla-js-spa-pkce` |
|
||||
| `feature-keycloak-refresh-rotation-and-logout` | refresh rotation 동작 + 로그아웃 시 세션/토큰 무효화 확인 | P3 | `feature-keycloak-spring-rs-audience-validator` |
|
||||
|
||||
### 그룹 2 — AP2 Token-Mediating Backend (parent `feature-keycloak-token-mediating-backend`) — 신규
|
||||
|
||||
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|
||||
|---|---|---|---|
|
||||
| `feature-keycloak-token-mediating-confidential-client` | 백엔드(confidential client)가 code→token 교환 성공(client_secret) + refresh 를 서버 세션 보관 | P3 | baseline |
|
||||
| `feature-keycloak-token-mediating-access-handoff` | access_token 만 브라우저 전달 → 브라우저가 RS 직접 호출 `200` + refresh 가 네트워크탭/응답 바디에 **부재** 확인 | P3 | `feature-keycloak-token-mediating-confidential-client` |
|
||||
|
||||
### 그룹 3 — AP3 BFF (parent `feature-keycloak-bff-session-proxy`)
|
||||
|
||||
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|
||||
|---|---|---|---|
|
||||
| `feature-keycloak-bff-oauth2login-session` | Spring `oauth2Login` 로그인 → 브라우저 토큰 0개(SESSION cookie 만) + BFF proxy 경유 API `200` | P3 | baseline |
|
||||
| `feature-keycloak-bff-csrf-samesite-defense` | cookie 자동첨부 CSRF 재현 → SameSite + CSRF token 으로 `403` 차단 | P3 | `feature-keycloak-bff-oauth2login-session` |
|
||||
|
||||
### 그룹 4 — AP4 Edge forward-auth (parent `feature-keycloak-edge-forwardauth-proxy`)
|
||||
|
||||
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|
||||
|---|---|---|---|
|
||||
| `feature-keycloak-oauth2-proxy-oidc-flow` | oauth2-proxy 앞단 → 미인증 redirect → 인증 후 backend `X-Forwarded-User` `200` | P3 | baseline |
|
||||
| `feature-keycloak-nginx-auth-request-integration` | nginx `auth_request` 통합 동작 + 4kb cookie 분할 함정 확인 | P3 | `feature-keycloak-oauth2-proxy-oidc-flow` |
|
||||
| `feature-keycloak-header-spoofing-defense` | `X-Forwarded-User` 위조 우회 재현 → network 격리(SG/NetworkPolicy)로 차단 | P3 | `feature-keycloak-oauth2-proxy-oidc-flow` |
|
||||
|
||||
> (감사 정정 2026-07-14) `feature-keycloak-traefik-forwardauth-alternative` 은 impl branch 아님 — 본문이 스스로 "선택 기준 정리까지만" 이고 P3A 는 nginx+oauth2-proxy 채택. **FOLD-IN**(비교 근거)으로 강등, 아래 fold-in 목록 참조.
|
||||
|
||||
### 그룹 5 — Google IdP brokering cross-cutting (parent `feature-keycloak-google-idp-brokering`)
|
||||
|
||||
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|
||||
|---|---|---|---|
|
||||
| `feature-keycloak-idp-brokering-google-client` | realm 에 Google IdP 등록 → Google 계정 로그인 → Keycloak 사용자 매핑 `200` + SPA/Backend diff 0줄 검증 | P4 | AP1 group |
|
||||
| `feature-keycloak-first-broker-login-flow` | `email_verified=false` auto-linking 계정탈취 재현 → Confirm Link Existing Account 로 차단 | P4 | `feature-keycloak-idp-brokering-google-client` |
|
||||
| `feature-keycloak-google-claim-attribute-mapping` | Google claim → Keycloak attribute 매핑(email/name) 확인 | P4 | `feature-keycloak-idp-brokering-google-client` |
|
||||
| `feature-keycloak-account-linking-sub-vs-email` | 계정 linking 키 `sub` vs `email` 보안 비교 → 결정 기록 | P4 | `feature-keycloak-first-broker-login-flow` |
|
||||
|
||||
### 그룹 6 — 종합 (parent 없음, 최종)
|
||||
|
||||
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|
||||
|---|---|---|---|
|
||||
| `feature-keycloak-four-pattern-tradeoff-matrix` | 4 패턴을 {토큰 위치 · 검증 주체 · XSS/CSRF surface · 선택 기준 · keycloak 설정} 열로 한 표에 정리 + 각 셀이 구현 branch 검증 증거 link | P5 | AP1~AP4 4개 group |
|
||||
|
||||
> **기존 sub-branch 흡수/승격**: 위 Tier-2 대부분은 기존 27 sub-sub-branch(§12.1 legacy)의 실 구현 승격이다. 예외 — 학습노트로 fold-in(별도 impl branch 아님): `feature-keycloak-pkce-flow-stages`·`feature-keycloak-spring-rs-role-mapping`·`feature-keycloak-refresh-token-rotation`(→ AP1 그룹 근거), `feature-keycloak-bff-vs-spa-direct`(→ AP3 비교 근거), `feature-keycloak-traefik-forwardauth-alternative`(→ AP4 비교 근거, P3A 는 nginx+oauth2-proxy 채택), `feature-keycloak-federation-spa-zero-change`·`feature-keycloak-three-leg-trust-chain`·`feature-keycloak-account-linking-spa-ux`(→ Google 그룹 근거). **AP2 그룹 2개(신규)만 완전 신규 파일.** 실제 파일 rename/re-parent 는 `wiki-doc-author mode=migrate` 로 점진(자동 mv 금지).
|
||||
>
|
||||
> **배포 토폴로지 sub-branch 는 documentation-only**(F5): `feature-keycloak-public-domain-tunneling`·`feature-keycloak-reverse-proxy-headers`·`feature-keycloak-https-termination-caddy-nginx`·`feature-keycloak-google-redirect-uri-policy` 는 single-EC2 실 구현 밖 배포 변형이라 §13 HTTPS termination 근거로 문서만 유지(별도 impl branch 아님). **인가(RBAC)** `feature-keycloak-idp-mappers-claim-to-role` 는 §5 deferred(authZ)로 이월.
|
||||
>
|
||||
> **중복 정합 완료 (2026-07-14 감사 — 각 파일에 정합 노트 삽입)**: (1) `spring-rs-role-mapping` ↔ `spring-rs-audience-validator` — Spring RS 셋업·`aud` 검증은 **audience-validator 가 owner**, role-mapping 의 role→RBAC 부분만 deferred authZ. (2) `idp-mappers-claim-to-role` ↔ `google-claim-attribute-mapping` — attribute-mapping 은 **google-claim-attribute-mapping 이 owner**, idp-mappers 의 claim→role 부분만 deferred authZ. (확인된 비-중복: account-linking sub-vs-email↔spa-ux, federation-spa-zero-change↔three-leg-trust-chain, refresh 2개 — 상호보완이라 유지.)
|
||||
|
||||
## 6. 본인이 한 작업 (사실만)
|
||||
|
||||
각 항목 옆에 증거 등급 표기:
|
||||
가능한 등급: `actually-implemented` | `locally-verified` | `prod-verified` | `documented-only` | `planned` | `needs-confirmation`
|
||||
|
||||
- 6 패턴 분류 축 정의 (배치 × federation) — 등급: `documented-only` *(2026-07-14 인증 아키텍처 4패턴으로 축 교정됨 — 아래 참조)*
|
||||
- 6 sub-branch 작성 (목표 / 다이어그램 / 토큰 sequence / 장단점) — 등급: `documented-only`
|
||||
- 28 raw 외부 자료 보존 (공식 문서 + 기술블로그) — 등급: `documented-only`
|
||||
- **분류축 교정 + hub §2 재편** (2026-07-14): 배치×federation 6패턴 → 인증 아키텍처 4패턴(AP1~AP4) primary + cross-cutting. 측정가능 성공기준(§1)·기술결정 소싱표(6/6)·Branch 분해표(7 branch) 추가. IETF browser-based-apps raw 보존 — 등급: `documented-only`
|
||||
- AP1~AP4 실 구현 (코드) — 등급: `planned` (Branch 분해표 Phase 2~3)
|
||||
|
||||
## 7. 마주친 문제 / 트러블슈팅
|
||||
|
||||
> Phase 1(문서화) 단계에서 발견한 함정. Phase 2(P3A 실 구현) 시 마주칠 가능성 높음.
|
||||
|
||||
- **iss claim mismatch (단일 EC2)**:
|
||||
- 원인: Keycloak `KC_HOSTNAME` 미설정 시 browser와 backend가 다른 hostname을 보고, JWT `iss` claim이 mismatch → backend JWT validation 실패.
|
||||
- 해결: `KC_HOSTNAME=<hostname>` + `KC_HTTP_ENABLED=true` 명시. browser/backend 모두 같은 issuer 사용.
|
||||
|
||||
- **Spring Security `aud` claim 미검증 (default)**:
|
||||
- 원인: Spring Security 기본 JWT validator는 `iss`, `exp`만 검증, `aud` 검증 안 함. 다른 client용 토큰이 본 backend로 흘러들 위험.
|
||||
- 해결: custom `OAuth2TokenValidator<Jwt>`로 `aud=<expected-client-id>` 검증 추가.
|
||||
|
||||
- **redirect_uri mismatch (localhost vs 127.0.0.1)**:
|
||||
- 원인: Keycloak client 설정의 `Valid Redirect URIs`에 `localhost`만 등록했는데 browser가 `127.0.0.1`로 접근 (또는 반대).
|
||||
- 해결: 등록과 사용 hostname을 1:1 일치시키거나 둘 다 등록.
|
||||
|
||||
- **Google First Broker Login Flow의 email-match auto-linking 보안 위험**:
|
||||
- 원인: 기본 First Broker Login Flow가 email 기반 자동 linking 옵션 제공. 그러나 Google이 email_verified=false 인 사용자 통과 가능 → 본인 외 사용자의 기존 계정 탈취 가능.
|
||||
- 해결: First Broker Login Flow에 "Confirm Link Existing Account" + email_verified=true 강제 + manual confirm.
|
||||
|
||||
## 8. 자신 없는 부분
|
||||
|
||||
> 면접에서 받을 가능성이 있지만 본인이 확실히 답할 수 없는 영역. P3A 구현 + Phase 3 sub-sub-branch 학습 후 보강 예정.
|
||||
|
||||
- BFF (Backend-for-Frontend) 패턴 실 구현 경험 부재 — 문서만 봤음
|
||||
- Keycloak SPI (Service Provider Interface)로 custom IdP 작성
|
||||
- 운영 환경에서 token revocation 처리 (JWT 자체는 stateless, blacklist 필요 시)
|
||||
- Keycloak multi-realm 운영 (테넌트별 realm 분리 vs 단일 realm + client별 분리)
|
||||
- HTTPS termination 위치 (nginx vs Caddy vs ALB) trade-off
|
||||
- Keycloak 자체의 HA 구성 (Infinispan + cluster)
|
||||
|
||||
## 9. 관련 자료
|
||||
|
||||
- 저장소 URL: `/home/donghyeon/workspace/keycloak-patterns/` (별도 git repo, **아직 비어 있음** — Phase 2 진입 시 생성)
|
||||
- 관련 PR / 커밋: 없음
|
||||
- canonical SSOT (본 문서): [[raw/project-notes/keycloak-patterns-overview]]
|
||||
|
||||
## 10. 진행 단계 (Phase)
|
||||
|
||||
| Phase | 내용 | 상태 |
|
||||
|-------|------|------|
|
||||
| **Phase 0** | 배치×federation 6패턴 정의 + 34 branch-note + 6 `.drawio` + 외부자료 보존 | ✅ 2026-05-27 완료 |
|
||||
| **Phase 1** | **분류축 교정**: 인증 아키텍처 4패턴(AP1~AP4) 재편 + 측정가능 성공기준(§1) + 기술결정 소싱(6/6) + Branch 분해표(7 branch) | ✅ 2026-07-14 완료 |
|
||||
| **Phase 2** | `feature-keycloak-local-stack-baseline` + AP1~AP4 E2E + signature 함정 재현 (Branch 분해표 P1~P3) | ⏳ Pending |
|
||||
| **Phase 3** | Google IdP brokering cross-cutting + 4패턴 trade-off 매트릭스 (Branch 분해표 P4~P5) | ⏳ Pending |
|
||||
| **Phase 4** | AP1~AP4 `locally-verified` 승급 + `wiki/projects/keycloak-patterns/` 추출 | ⏳ Pending |
|
||||
| **Phase 5** (deferred) | keycloak server-side 심화 트랙 (SPI / HA / multi-realm / LDAP — §5 Deferred) | ⏳ Deferred |
|
||||
|
||||
## 11. wiki 추출 정책
|
||||
|
||||
- **Phase 4 완료 시점에 추출**: P3A의 `actually-implemented` / `locally-verified` 항목만 `wiki/projects/keycloak-patterns/`로 추출.
|
||||
- **추출하지 않음**: P1A/P1B/P2A/P2B/P3B는 `documented-only` 유지, wiki/projects 승급 안 함. 단, 학습 노트 가치가 있으면 별도 `wiki/concepts/keycloak-deployment-patterns.md`로 합성 검토 (Phase 4 이후).
|
||||
|
||||
## 12. 묶음 (이 프로젝트에 묶이는 모든 raw 자료)
|
||||
|
||||
<!-- GENERATED: sources:start -->
|
||||
- [[raw/company-tech-blogs/curity-bff-pattern-spa]]
|
||||
- [[raw/company-tech-blogs/keycloak-google-login-codemancers]]
|
||||
- [[raw/company-tech-blogs/keycloak-jwt-role-extraction-betweendata]]
|
||||
- [[raw/official-docs/aws-alb-target-security-group-restriction-official]]
|
||||
- [[raw/official-docs/aws-cloudfront-origin-shared-secret-header-official]]
|
||||
- [[raw/official-docs/aws-security-group-referencing-official]]
|
||||
- [[raw/official-docs/chrome-third-party-cookie-policy-google-official]]
|
||||
- [[raw/official-docs/cloudflare-tunnel-routing-official]]
|
||||
- [[raw/official-docs/docker-compose-depends-on-healthcheck]]
|
||||
- [[raw/official-docs/docker-compose-networking-extra-hosts-official]]
|
||||
- [[raw/official-docs/docker-engine-20-10-release-notes-official]]
|
||||
- [[raw/official-docs/docker-host-network-driver-official]]
|
||||
- [[raw/official-docs/docker-port-publishing-loopback-bind-official]]
|
||||
- [[raw/official-docs/google-oauth-app-verification-state-overview-official]]
|
||||
- [[raw/official-docs/google-oauth-manage-app-audience-official]]
|
||||
- [[raw/official-docs/google-oauth2-client-application-types-official]]
|
||||
- [[raw/official-docs/google-oauth2-policies-environment-separation-official]]
|
||||
- [[raw/official-docs/google-oauth2-redirect-uri-validation-official]]
|
||||
- [[raw/official-docs/google-oauth2-web-server-flow-official]]
|
||||
- [[raw/official-docs/google-oidc-discovery-spec]]
|
||||
- [[raw/official-docs/google-openid-connect-oidc]]
|
||||
- [[raw/official-docs/istio-mtls-cert-rotation-official]]
|
||||
- [[raw/official-docs/k8s-network-policy-official]]
|
||||
- [[raw/official-docs/keycloak-2500-hostname-v2-release-official]]
|
||||
- [[raw/official-docs/keycloak-2600-hostname-v1-removed-official]]
|
||||
- [[raw/official-docs/keycloak-account-console-unlink-lockout-guard-official]]
|
||||
- [[raw/official-docs/keycloak-client-initiated-account-linking]]
|
||||
- [[raw/official-docs/keycloak-client-pkce-method-enforcement-official]]
|
||||
- [[raw/official-docs/keycloak-configuring-database]]
|
||||
- [[raw/official-docs/keycloak-first-broker-login-flow]]
|
||||
- [[raw/official-docs/keycloak-first-broker-login-verify-authenticators-official]]
|
||||
- [[raw/official-docs/keycloak-first-login-flow]]
|
||||
- [[raw/official-docs/keycloak-getting-started-docker]]
|
||||
- [[raw/official-docs/keycloak-google-idp-setup]]
|
||||
- [[raw/official-docs/keycloak-health-checks]]
|
||||
- [[raw/official-docs/keycloak-hostname-configuration]]
|
||||
- [[raw/official-docs/keycloak-identity-broker-spi]]
|
||||
- [[raw/official-docs/keycloak-identity-brokering-overview-official]]
|
||||
- [[raw/official-docs/keycloak-identity-provider-mappers]]
|
||||
- [[raw/official-docs/keycloak-identity-provider-redirector-default-idp-official]]
|
||||
- [[raw/official-docs/keycloak-identity-provider-sync-mode-official]]
|
||||
- [[raw/official-docs/keycloak-identity-provider-trust-email-official]]
|
||||
- [[raw/official-docs/keycloak-idp-hide-on-login-page-toggle-official]]
|
||||
- [[raw/official-docs/keycloak-idp-hint-client-suggested-official]]
|
||||
- [[raw/official-docs/keycloak-import-export-realms]]
|
||||
- [[raw/official-docs/keycloak-oidc-logout-endpoint-official]]
|
||||
- [[raw/official-docs/keycloak-refresh-token-rotation-reuse-admin-official]]
|
||||
- [[raw/official-docs/keycloak-refresh-token-rotation-sessions-official]]
|
||||
- [[raw/official-docs/keycloak-reverseproxy-official]]
|
||||
- [[raw/official-docs/keycloak-securing-apps-overview-official]]
|
||||
- [[raw/official-docs/keycloak-server-containers-docker]]
|
||||
- [[raw/official-docs/nginx-auth-request-module-official]]
|
||||
- [[raw/official-docs/nginx-core-module-location-internal-official]]
|
||||
- [[raw/official-docs/ngrok-http-tunnel-official]]
|
||||
- [[raw/official-docs/oauth-v2-1-draft-ietf]]
|
||||
- [[raw/official-docs/oauth2-browser-based-apps-ietf-draft]]
|
||||
- [[raw/official-docs/oauth2-pkce-rfc-7636]]
|
||||
- [[raw/official-docs/oauth2-proxy-behaviour-cookie-vs-bearer-official]]
|
||||
- [[raw/official-docs/oauth2-proxy-cookie-redirect-flags-official]]
|
||||
- [[raw/official-docs/oauth2-proxy-endpoints-official]]
|
||||
- [[raw/official-docs/oauth2-proxy-endpoints-signout-official]]
|
||||
- [[raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official]]
|
||||
- [[raw/official-docs/oauth2-proxy-nginx-integration-official]]
|
||||
- [[raw/official-docs/oauth2-proxy-overview-config-official]]
|
||||
- [[raw/official-docs/oauth2-proxy-session-storage-official]]
|
||||
- [[raw/official-docs/oauth2-token-revocation-rfc-7009]]
|
||||
- [[raw/official-docs/oidc-client-ts-library]]
|
||||
- [[raw/official-docs/openid-connect-core-id-token-validation]]
|
||||
- [[raw/official-docs/owasp-html5-storage-xss-spa]]
|
||||
- [[raw/official-docs/proxy-pass-request-body-nginx-official]]
|
||||
- [[raw/official-docs/security-jwt-rfc-7519-validation]]
|
||||
- [[raw/official-docs/silent-check-sso-third-party-cookies-keycloak-official]]
|
||||
- [[raw/official-docs/spring-security-authorization-defense-in-depth]]
|
||||
- [[raw/official-docs/spring-security-authorize-http-requests]]
|
||||
- [[raw/official-docs/spring-security-method-security]]
|
||||
- [[raw/official-docs/spring-security-nested-authorities-claim-issue-15201]]
|
||||
- [[raw/official-docs/spring-security-resource-server-jwt]]
|
||||
- [[raw/official-docs/third-party-cookie-blocking-safari-webkit-official]]
|
||||
- [[raw/official-docs/traefik-forwardauth-middleware-official]]
|
||||
- [[raw/official-docs/traefik-hub-oidc-middleware-official]]
|
||||
- [[raw/official-docs/traefik-oidc-community-plugin-lukaszraczylo-official]]
|
||||
<!-- GENERATED: sources:end -->
|
||||
|
||||
> 본 project-note는 cluster의 entry point. 모든 branch / sources / errors / interviews / lectures 가 여기로 upward link. hub 측에서도 카테고리별 명시.
|
||||
|
||||
### 12.1 브랜치
|
||||
|
||||
<!-- GENERATED: branches:start -->
|
||||
- [[raw/branch-notes/feature-keycloak-account-linking-sub-vs-email]]
|
||||
- [[raw/branch-notes/feature-keycloak-bff-csrf-samesite-defense]]
|
||||
- [[raw/branch-notes/feature-keycloak-bff-oauth2login-session]]
|
||||
- [[raw/branch-notes/feature-keycloak-docker-compose-stack]]
|
||||
- [[raw/branch-notes/feature-keycloak-first-broker-login-flow]]
|
||||
- [[raw/branch-notes/feature-keycloak-four-pattern-tradeoff-matrix]]
|
||||
- [[raw/branch-notes/feature-keycloak-google-claim-attribute-mapping]]
|
||||
- [[raw/branch-notes/feature-keycloak-header-spoofing-defense]]
|
||||
- [[raw/branch-notes/feature-keycloak-idp-brokering-google-client]]
|
||||
- [[raw/branch-notes/feature-keycloak-iss-claim-hostname-mismatch]]
|
||||
- [[raw/branch-notes/feature-keycloak-nginx-auth-request-integration]]
|
||||
- [[raw/branch-notes/feature-keycloak-oauth2-proxy-oidc-flow]]
|
||||
- [[raw/branch-notes/feature-keycloak-patterns]]
|
||||
- [[raw/branch-notes/feature-keycloak-realm-client-export]]
|
||||
- [[raw/branch-notes/feature-keycloak-refresh-rotation-and-logout]]
|
||||
- [[raw/branch-notes/feature-keycloak-spa-token-storage-tradeoff]]
|
||||
- [[raw/branch-notes/feature-keycloak-spring-rs-audience-validator]]
|
||||
- [[raw/branch-notes/feature-keycloak-token-mediating-access-handoff]]
|
||||
- [[raw/branch-notes/feature-keycloak-token-mediating-confidential-client]]
|
||||
- [[raw/branch-notes/feature-keycloak-vanilla-js-spa-pkce]]
|
||||
<!-- GENERATED: branches:end -->
|
||||
|
||||
> generated reverse view는 child branch의 v2 contract migration 후 채운다. 아래 수기 legacy inventory는 그 전까지 navigation으로 보존한다.
|
||||
|
||||
> ⚠️ **Legacy inventory (구 6패턴 축).** 아래 목록은 Phase 0 의 배치×federation 구조다. **현 실행계획은 "Branch 분해 / 실행계획 (R4)" 표** — 아래 branch 들은 §2.3 매핑대로 AP1~AP4 로 re-map/승격 대상(실제 rename 은 `wiki-doc-author mode=migrate`). 신규 작업 진입점은 분해표를 따른다.
|
||||
> Root branch + 6개 Tier-2 sub-branches + 27개 Tier-3 sub-sub-branches.
|
||||
|
||||
- **Root**: [[raw/branch-notes/feature-keycloak-patterns]] — 전체 진행 인덱스 hub
|
||||
- **Tier-2 sub-branches** (구 6 패턴 → §2.3 매핑: P1x→AP4, P2x/P3x→AP1):
|
||||
- [[raw/branch-notes/feature-keycloak-edge-forwardauth-no-google]] — P1A Edge / Ingress (no Google)
|
||||
- [[raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation]] — P1B Edge / Ingress + Google federation
|
||||
- [[raw/branch-notes/feature-keycloak-internal-spa-direct-no-google]] — P2A Cluster-internal SPA-direct (no Google)
|
||||
- [[raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation]] — P2B Cluster-internal + Google federation
|
||||
- [[raw/branch-notes/feature-keycloak-single-ec2-no-google]] — P3A Single EC2 (no Google) — **실 구현 대상**
|
||||
- [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] — P3B Single EC2 + Google federation
|
||||
- **Tier-3 sub-sub-branches** (각 패턴 4~6개): root branch [[raw/branch-notes/feature-keycloak-patterns]] 의 Cluster 섹션 참조.
|
||||
|
||||
### 12.2 근거 자료 (프로젝트 전체 차원 foundational 조사)
|
||||
|
||||
- 개별 official-doc / company-tech-blog 들은 각 sub-branch 의 Sources 표에서 cited.
|
||||
- [[raw/official-docs/oauth2-browser-based-apps-ietf-draft]] — IETF draft-ietf-oauth-browser-based-apps-27. **4-패턴 인증 아키텍처 taxonomy(§2.1)** 가 준거로 삼는 업계 표준 3대 아키텍처(BFF / Token-Mediating Backend / Browser-based OAuth Client, decreasing order of security) 정의의 foundational 근거. AP4(edge forward-auth)만 IETF 3종 밖 실무 확장.
|
||||
|
||||
### 12.3 오류 기록 (branch 외 발생한 환경·운영 이슈)
|
||||
|
||||
- (없음 — Phase 3 P3A 구현 진입 시 발생 예상)
|
||||
|
||||
### 12.4 면접 준비
|
||||
|
||||
- (없음 — sub-branch 별로 면접 후보 누적 후 별도 raw/interviews/ 신설 예정)
|
||||
|
||||
### 12.5 강의
|
||||
|
||||
- (없음 — 필요 시 Keycloak Summit / OIDC 강의 추가)
|
||||
|
||||
### 12.6 파생 wiki 문서
|
||||
|
||||
- canonical 검증 사실: (없음 — Phase 4 시 `wiki/projects/keycloak-patterns/` 신설)
|
||||
- 관련 일반 개념: (없음 — Phase 4 이후 `wiki/concepts/keycloak-deployment-patterns.md` 검토)
|
||||
- 포트폴리오: (없음)
|
||||
- 블로그 글: (없음)
|
||||
|
||||
## 13. Phase 5 Additional Evidence Raws (2026-05-27)
|
||||
|
||||
> Phase 5B 외부 근거 추가 보강. HTTPS termination 결정 (P3B 의 tunnel/RP 선택, §3-1-6 의 cloudflared / ngrok / Caddy 비교) 영역에 5개 신규 raw 파일 (`raw/official-docs/` 하위) 추가. 각 raw 는 frontmatter `related_projects: [keycloak-patterns]` 보유.
|
||||
>
|
||||
> **출처 신뢰도 (CLAUDE.md §5 정합)**: 모두 `source_type: official-doc` (IETF RFC, OWASP cheat sheet, vendor 공식 reference). company-tech-blog 없음.
|
||||
>
|
||||
> **사용 경계**: 본 섹션은 raw evidence 의 cluster-level index. 각 raw 의 정확한 Claim ID / Usage Boundary 는 raw 파일 자체의 `## Claims Extracted` 섹션 참조. 본 project-note 는 owning sub-branch 에 매핑할 뿐, raw 의 verbatim claim 을 그대로 keycloak best practice 로 단정하지 않음.
|
||||
|
||||
### 13.1 HTTPS Termination / TLS Policy (5 raw)
|
||||
|
||||
P3B (Single EC2 + Google federation) 의 HTTPS termination 결정 — Google IdP 가 검증하는 `redirect_uri` 와 Keycloak issuer 가 모두 공개 HTTPS host 여야 함 (§3-1-6 핵심 함정 `KC_HOSTNAME`). 아래 5개 raw 가 termination 전략 선택지 (D2~D5) 의 외부 근거.
|
||||
|
||||
| raw | 채택 위치 (decision / sub-branch) | 사용 근거 |
|
||||
| --- | --- | --- |
|
||||
| [[raw/official-docs/rfc8996-tls10-tls11-deprecation]] | https-termination D5 (TLS 버전 policy), [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] | RFC 8996 (TLS 1.0/1.1 Deprecation, IETF 2021) 이 P3B 의 HTTPS termination (tunnel/RP 어느 쪽이든) 이 최소 TLS 1.2+ 강제 해야 하는 baseline. Google OIDC discovery endpoint 도 TLS 1.2+ 요구. |
|
||||
| [[raw/official-docs/owasp-hsts-cheat-sheet]] | https-termination D5 (HSTS header policy), [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] | OWASP HSTS Cheat Sheet 가 `Strict-Transport-Security` header 의 baseline (`max-age`, `includeSubDomains`, `preload`). Caddy / Certbot+nginx / Cloudflare tunnel 어느 termination 도 HSTS 활성화 해야 함. preload 진입 결정은 branch-note 에서 별도 trade-off. |
|
||||
| [[raw/official-docs/caddy-automatic-https-docs]] | https-termination D2 (Caddy option), [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] | Caddy 공식 "Automatic HTTPS" doc. P3B termination 선택지 중 정식 도메인 + Caddy 옵션 — Caddy 가 ACME (Let's Encrypt / ZeroSSL) 자동 발급·갱신·OCSP stapling 을 기본 제공. 트레이드오프: 단일 binary, config 간결성 vs nginx 운영 표준성. |
|
||||
| [[raw/official-docs/certbot-user-guide]] | https-termination D3 (Certbot + nginx option), [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] | Certbot 공식 user guide. P3B termination 선택지 중 정식 도메인 + nginx + Certbot 옵션 — Certbot 이 Let's Encrypt ACME 클라이언트의 reference 구현. cron/systemd timer 기반 갱신, nginx plugin 의 in-place reload. 트레이드오프: 운영 표준성 (nginx) vs config 분리도 (Caddy 대비). |
|
||||
| [[raw/official-docs/aws-acm-managed-renewal]] | https-termination D4 (AWS ALB/CloudFront option), [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] | AWS ACM Managed Renewal 공식 reference. P3B termination 선택지 중 AWS ALB / CloudFront 앞단 옵션 — ACM 이 publicly trusted cert 의 13개월 자동 갱신을 platform-side 에서 책임. EC2 내부 (Keycloak) 는 HTTP 또는 self-signed 로 충분. 트레이드오프: AWS lock-in vs 운영 부담 zero. |
|
||||
|
||||
**비교 매트릭스** (4개 termination option):
|
||||
|
||||
| 옵션 | cert 발급 자동화 | 인프라 위치 | lock-in | P3B 적합도 |
|
||||
|---|---|---|---|---|
|
||||
| cloudflared tunnel | Cloudflare 측 | 외부 (no inbound) | Cloudflare | 학습/dev 최적 (가장 가벼움) |
|
||||
| Caddy + 도메인 | Caddy 자체 (ACME) | EC2 내 | none (open source) | 단일 binary, prod 가능 |
|
||||
| nginx + Certbot + 도메인 | Certbot (cron) | EC2 내 | none | 운영 표준 (가장 친숙) |
|
||||
| AWS ALB/CloudFront + ACM | ACM 자동 | AWS platform | AWS | prod 권장 (운영 부담 최소) |
|
||||
|
||||
**Out of scope** (P3B termination 선택 후 별도 분기): mTLS termination, FAPI 준수 termination, EV cert, multi-domain SAN, custom CA. ngrok 은 학습용 short-lived tunnel 로 cloudflared 대안 (별도 raw 미수집).
|
||||
|
||||
---
|
||||
|
||||
## 14. 아키텍처 검토 체크리스트 (작성/갱신 시 self-check)
|
||||
|
||||
- [x] 한 줄 요약 + 현재 상태 + 나의 역할 채워짐 (§1)
|
||||
- [x] 측정 가능한 성공 기준 1개 이상 — **§1 성공 기준(측정가능, R1) 추가 (2026-07-14)**: 4 패턴 각각 E2E `200` + signature 함정 재현→해결, done-bar 정량화 완료. ✓
|
||||
- [x] 아키텍처 다이어그램 1개 이상 첨부 (§3-1) — 기존 6 `.drawio` (2026-05-26, minimalist) ✓. **단 신 축 AP2·AP3 은 needs-diagram (§3-1-7) — 사용자 작성 대기.**
|
||||
- [x] 다이어그램의 모든 컴포넌트가 라벨 + 역할 표기 ✓
|
||||
- [x] 다이어그램의 모든 화살표가 프로토콜·데이터 종류 라벨링 ✓
|
||||
- [x] 외부 시스템이 점선 + 회색으로 시각적 구분 ✓ (Google OIDC = dashed gray box)
|
||||
- [x] 범례(Legend) 다이어그램 내부 + §3-1 도입부에 포함 ✓
|
||||
- [x] 신뢰 경계 / 네트워크 경계 표시 ✓ (Edge zone / Internal / EC2 / Public HTTPS)
|
||||
- [x] 시퀀스 다이어그램 1개 이상 (Mermaid) — happy path + error path 함께 (§3-2 P3A) ✓
|
||||
- [x] Cluster 섹션의 root branch 목록 채워짐 (§12.1) ✓
|
||||
- [x] 마지막 architecture review 날짜 frontmatter `architecture_review:` 에 기록 — 2026-05-26 ✓
|
||||
@@ -1 +0,0 @@
|
||||
../../vault/10-projects/llm-wiki-server-migration/project-notes/llm-wiki-server-migration.md
|
||||
@@ -0,0 +1,568 @@
|
||||
---
|
||||
title: LLM Wiki Server Migration
|
||||
source_type: project-note
|
||||
status: draft
|
||||
confidence: medium
|
||||
tags: [project-note, llm-wiki, architecture, application, persistence, api-design, static-analysis]
|
||||
related_projects: [llm-wiki-server-migration, llm-wiki]
|
||||
last_reviewed: 2026-06-29
|
||||
diagrams: []
|
||||
architecture_review: 2026-06-29
|
||||
status_label: active
|
||||
project_revision: 1
|
||||
semantic_surface_exclusions:
|
||||
- artifact-registry|legacy hub has no project-local Artifact Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
- contract-gate-registry|legacy hub has no project-local Contract/Gate Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
- flow-stage-registry|legacy hub has no project-local Flow/Stage Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
---
|
||||
|
||||
# LLM Wiki Server Migration
|
||||
|
||||
> Layer: `raw/project-notes/` (primary, hub) -> `/ingest` 후 검증된 사실은 `wiki/projects/` 로 추출.
|
||||
> 본 문서는 현재 파일 기반 LLM Wiki 를 서버/API/DB/local runner 기반 시스템으로 이전하기 위한 프로젝트 hub 초안이다.
|
||||
> 현재 등급은 `draft` 이며, 실제 구현·로컬 검증 전까지 외부 공개 가능한 프로젝트 성과로 취급하지 않는다.
|
||||
|
||||
## 1. 프로젝트 개요
|
||||
|
||||
- **한 줄 요약**: LLM Wiki Server Migration 은 현재 Markdown/Git 중심 LLM Wiki 를 개인용 서버, DB, desktop app, local agent runner 로 확장해 문서 작성·검증·상태 관리·스케줄링을 체계화하는 프로젝트다.
|
||||
- **기간**: 2026-06-29 ~ in-progress.
|
||||
- **현재 상태**: `active`.
|
||||
- **나의 역할 / Role**: 설계자, 구현자, 사용자, 운영자.
|
||||
- **저장소 / Repo**:
|
||||
- 현재 지식 저장소: `/home/donghyeon/dev/llm-wiki-private`
|
||||
- 예정 코드 저장소: 미정. 초기에는 본 repo 안의 project-note 로 요구사항을 관리하고, 구현 착수 시 별도 app repo 또는 monorepo 를 결정한다.
|
||||
|
||||
### 1.1 핵심 아이디어
|
||||
|
||||
현재 LLM Wiki 는 파일, 규칙, hook, agent skill 을 조합해 문서 품질을 관리한다. 이 방식은 Git diff 와 CLI 친화성이 강하지만, 문서 상태 추적, stale 관리, 작업 큐, dashboard, 정기 점검 같은 운영 기능은 수동 절차에 가깝다.
|
||||
|
||||
이 프로젝트는 LLM Wiki 를 "문서 모음"에서 "문서 운영 시스템"으로 확장한다.
|
||||
|
||||
```text
|
||||
Desktop App / Linux App
|
||||
|
|
||||
v
|
||||
Local Agent Runner <-- locally logged-in Codex / Claude Code / other CLI
|
||||
|
|
||||
v
|
||||
Personal Wiki Server API
|
||||
|
|
||||
v
|
||||
DB control plane + Git/Markdown document store
|
||||
```
|
||||
|
||||
초기 방향은 **Git/Markdown 을 문서 원본(SSOT)으로 유지하고, DB 는 index / metadata / state / job queue / audit log 로 둔다**. DB-first 는 가능하지만, 1차 MVP 에서는 diff, rollback, agent 호환성, vault portability 를 우선한다.
|
||||
|
||||
## 2. 문제 정의
|
||||
|
||||
### 2.1 현재 상태의 문제
|
||||
|
||||
- **문서 상태가 파일 안에 흩어져 있다**: `status`, `confidence`, `last_reviewed`, claim coverage, broken link, stale 여부를 파일마다 읽어야 한다.
|
||||
- **정적 분석 결과가 저장·추적되지 않는다**: `wiki_structure_lint.py`, coverage/depth review, forbidden word grep 결과가 일회성 command output 으로 끝난다.
|
||||
- **LLM 작업의 실행 경계가 약하다**: 각 CLI agent 가 파일을 직접 읽고 수정하므로, 작업 큐, 승인 상태, 실행 로그, rollback plan 이 서버 레벨에서 관리되지 않는다.
|
||||
- **문서 freshness 관리가 수동이다**: 오래된 문서, stale source, broken wikilink, 미승급 `documented-only` 항목을 주기적으로 찾아야 하지만 현재는 사람이 시작해야 한다.
|
||||
- **앱 UX 가 없다**: Obsidian 과 CLI 는 강하지만, 프로젝트별 상태판, review inbox, stale queue, branch-note lifecycle 을 한 화면에서 보는 도구가 없다.
|
||||
- **CLI model 인증 경계가 불분명해질 수 있다**: 서버가 개인 CLI 인증을 직접 보관하면 계정 공유, token 관리, 약관 검토 위험이 커진다.
|
||||
|
||||
### 2.2 왜 지금 해결해야 하는가
|
||||
|
||||
- **트리거**: LLM Wiki 문서 수가 늘어나면서 개별 branch-note 품질뿐 아니라 전체 문서 시스템의 lifecycle 관리가 필요해졌다.
|
||||
- **비용**: 상태 추적을 수동으로 계속하면 오래된 문서가 canonical 처럼 읽히거나, LLM 이 규칙을 놓친 문서를 누적시킬 수 있다.
|
||||
- **기회**: local agent runner 와 서버 API 를 분리하면 개인 CLI 로그인 상태를 유지하면서도 작업 큐, 승인, 검증, audit log 를 체계화할 수 있다.
|
||||
|
||||
### 2.3 성공 기준
|
||||
|
||||
- **S1. 문서 inventory API**: `raw/`, `wiki/` 문서의 path, source_type, status, confidence, tags, related_projects, last_reviewed 를 DB index 로 조회할 수 있다.
|
||||
- **S2. deterministic gate 저장**: lint/link/tag/stale 검사 결과가 DB 에 run 단위로 저장되고, 문서별 최신 gate 상태를 조회할 수 있다.
|
||||
- **S3. local runner 작업 큐**: 서버가 job 을 만들고 local runner 가 pull/execute/report 하는 흐름이 동작한다. 서버는 개인 CLI token 을 저장하지 않는다.
|
||||
- **S4. approval-first patch flow**: LLM 이 만든 수정안은 바로 적용되지 않고, diff/proposal 로 저장된 뒤 사용자가 승인하면 Git working tree 에 반영된다.
|
||||
- **S5. scheduled stale review**: 매일 00:00 KST 에 stale 후보를 계산하고, auto-modify 가 아니라 review inbox item 을 만든다.
|
||||
- **S6. Git/Markdown portability 유지**: 서버와 DB 없이도 Markdown vault 자체가 읽히고, Git history 로 복구 가능해야 한다.
|
||||
- **S7. security boundary 명시**: CLI provider 별 공식 API/SDK/CLI 허용 범위, local credential 사용 방식, 금지 automation 을 별도 branch 에서 검토한다.
|
||||
|
||||
<!-- section-id: architecture-components -->
|
||||
## 3. 시스템 아키텍처
|
||||
|
||||
### 3.1 아키텍처 다이어그램 (draw.io XML)
|
||||
|
||||
초안 단계에서는 draw.io 파일을 아직 만들지 않았다. 첫 architecture branch 에서 `raw/diagrams/llm-wiki-server-migration/architecture-overview-YYYY-MM-DD.drawio` 를 생성한다.
|
||||
|
||||
현재 텍스트 구조:
|
||||
|
||||
```text
|
||||
┌───────────────────────────┐
|
||||
│ Desktop App / Linux App │
|
||||
│ - dashboard │
|
||||
│ - review inbox │
|
||||
│ - document editor shell │
|
||||
└─────────────┬─────────────┘
|
||||
│ HTTPS / localhost API
|
||||
v
|
||||
┌───────────────────────────┐
|
||||
│ Personal Wiki Server API │
|
||||
│ - docs index API │
|
||||
│ - job queue API │
|
||||
│ - gate result API │
|
||||
│ - approval workflow │
|
||||
└───────┬─────────────┬─────┘
|
||||
│ │
|
||||
v v
|
||||
┌──────────────┐ ┌──────────────────┐
|
||||
│ Postgres DB │ │ Git/Markdown repo │
|
||||
│ metadata │ │ document SSOT │
|
||||
│ state/jobs │ │ raw/wiki files │
|
||||
│ audit log │ │ commits/diff │
|
||||
└──────────────┘ └──────────────────┘
|
||||
^
|
||||
│ job pull/report
|
||||
┌───────┴───────────────────┐
|
||||
│ Local Agent Runner │
|
||||
│ - invokes local CLI/SDK │
|
||||
│ - no central token storage │
|
||||
│ - returns proposal/diff │
|
||||
└───────────────────────────┘
|
||||
```
|
||||
|
||||
> Diagram rule note: 위 블록은 임시 설명용 text sketch 이다. project-template 상 정식 시스템 아키텍처는 draw.io 로 작성해야 한다.
|
||||
|
||||
### 3.2 컴포넌트 책임 분담
|
||||
|
||||
| 컴포넌트 | 역할 | 기술 스택 후보 | 의존하는 외부 |
|
||||
|---|---|---|---|
|
||||
| Desktop App | dashboard, review inbox, document navigation, approval UI | Tauri 또는 Electron | Server API |
|
||||
| Personal Wiki Server API | 문서 index, job queue, gate result, approval workflow, scheduler orchestration | FastAPI / Spring Boot / NestJS 중 택1 | DB, Git repo, local runner |
|
||||
| DB | metadata, parsed frontmatter, link graph, claim graph, gate runs, job state, audit log | PostgreSQL 우선, SQLite MVP 가능 | Server API |
|
||||
| Git/Markdown Store | 실제 문서 원본. `raw/`, `wiki/`, `rules/`, `templates/` 보존 | Git + Markdown | filesystem, optional remote |
|
||||
| Local Agent Runner | 로컬 로그인 CLI/SDK 를 호출하고 proposal/diff 를 서버에 보고 | Rust/Go/Python/Node 중 택1 | Codex/Claude Code/other CLI |
|
||||
| Static Gate Engine | frontmatter/link/tag/stale/forbidden-word/coverage precheck 실행 | 기존 Python hooks 재사용 | Git/Markdown Store |
|
||||
| Scheduler | 매일 stale scan, periodic lint, source review job 생성 | Server internal scheduler 또는 OS scheduler | DB, Static Gate Engine |
|
||||
| Policy Registry | provider 별 허용 실행 방식, secrets boundary, automation 금지사항 기록 | Markdown + DB indexed policy | official docs raw |
|
||||
|
||||
### 3.3 외부 의존성
|
||||
|
||||
| 외부 시스템 | 용도 | 통신 방식 | 장애 시 영향 |
|
||||
|---|---|---|---|
|
||||
| Local Codex / Claude Code / other CLI | 문서 초안, review, patch proposal 생성 | local process invocation 또는 official SDK | agent job 실패. deterministic gate 와 manual edit 는 유지 |
|
||||
| Git remote | backup/sync/collaboration 후보 | Git protocol / HTTPS | remote sync 실패. local Git 은 계속 사용 가능 |
|
||||
| Official vendor docs | CLI/API policy, SDK 사용 경계 근거 | manual archive to raw/official-docs | policy branch 가 `needs-confirmation` 으로 남음 |
|
||||
| OS scheduler | local daily task trigger 후보 | cron / launchd / Windows Task Scheduler | server internal scheduler 로 대체 가능 |
|
||||
|
||||
### 3.4 배포 다이어그램
|
||||
|
||||
초기 배포는 개인 로컬 환경 기준이다.
|
||||
|
||||
- **Mode A: local-only MVP**
|
||||
- server: localhost
|
||||
- DB: local PostgreSQL 또는 SQLite
|
||||
- Git/Markdown: local filesystem
|
||||
- runner: same machine
|
||||
|
||||
- **Mode B: personal home server**
|
||||
- server/DB: private server
|
||||
- runner: user workstation
|
||||
- Git/Markdown: private Git remote + local clone
|
||||
- 주의: server 는 CLI credential 을 저장하지 않고 runner 에 job 을 위임한다.
|
||||
|
||||
<!-- section-id: runtime-flow -->
|
||||
## 4. 핵심 시퀀스
|
||||
|
||||
<!-- section-id: sequence -->
|
||||
### 4.1 문서 정리 작업 요청
|
||||
|
||||
**시나리오**: 사용자가 desktop app 에서 특정 project-note 정리를 요청하고, local runner 가 로컬 CLI 를 호출해 proposal 을 만든다.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor User
|
||||
participant App as Desktop App
|
||||
participant API as Wiki Server API
|
||||
participant DB as DB
|
||||
participant Runner as Local Agent Runner
|
||||
participant CLI as Local CLI Model
|
||||
participant Git as Git/Markdown Repo
|
||||
participant Gate as Static Gate Engine
|
||||
|
||||
User->>App: 문서 정리 요청
|
||||
App->>API: POST /jobs {docPath, taskType}
|
||||
API->>DB: INSERT job(status=queued)
|
||||
Runner->>API: GET /jobs/next
|
||||
API-->>Runner: job payload
|
||||
Runner->>Git: read doc + related rules
|
||||
Runner->>CLI: generate proposal
|
||||
CLI-->>Runner: patch proposal
|
||||
Runner->>API: POST /jobs/{id}/result {proposal}
|
||||
API->>Git: apply patch to temp worktree
|
||||
API->>Gate: run lint/link/tag checks
|
||||
Gate-->>API: pass
|
||||
API->>DB: save proposal(status=needs-approval)
|
||||
API-->>App: review item created
|
||||
User->>App: approve proposal
|
||||
App->>API: POST /proposals/{id}/approve
|
||||
API->>Git: apply patch in working tree
|
||||
API->>DB: audit approved/applied
|
||||
```
|
||||
|
||||
### 4.2 매일 00:00 stale review
|
||||
|
||||
**시나리오**: scheduler 가 오래된 문서를 자동 수정하지 않고 stale review item 을 만든다.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant Scheduler as Scheduler
|
||||
participant API as Wiki Server API
|
||||
participant Gate as Static Gate Engine
|
||||
participant DB as DB
|
||||
participant Runner as Local Agent Runner
|
||||
participant CLI as Local CLI Model
|
||||
|
||||
Scheduler->>API: trigger daily stale scan
|
||||
API->>Gate: scan last_reviewed/status/link health
|
||||
Gate-->>API: stale candidates
|
||||
API->>DB: INSERT review_items
|
||||
opt agent review enabled
|
||||
Runner->>API: pull stale-review job
|
||||
Runner->>CLI: read-only review
|
||||
CLI-->>Runner: review summary
|
||||
Runner->>API: attach review summary
|
||||
API->>DB: update review item
|
||||
end
|
||||
```
|
||||
|
||||
### 4.3 deterministic gate before apply
|
||||
|
||||
**시나리오**: LLM proposal 이 적용되기 전 deterministic gate 가 최소 구조 위반을 잡는다.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor User
|
||||
participant App as Desktop App
|
||||
participant API as Wiki Server API
|
||||
participant Git as Git/Markdown Repo
|
||||
participant Gate as Static Gate Engine
|
||||
participant DB as DB
|
||||
|
||||
API->>Git: apply patch to temp worktree
|
||||
API->>Gate: run lint/link/tag checks
|
||||
alt gate pass
|
||||
API-->>App: proposal ready for approval
|
||||
User->>App: approve proposal
|
||||
App->>API: POST /proposals/{id}/approve
|
||||
API->>Git: apply patch to main working tree
|
||||
API->>DB: audit status=applied
|
||||
else gate fail
|
||||
API->>DB: audit status=blocked + findings
|
||||
API-->>App: show gate failures
|
||||
end
|
||||
```
|
||||
|
||||
## 5. 데이터 모델
|
||||
|
||||
초기 엔터티는 운영 상태 추적에 필요한 최소 모델로 둔다. 문서 본문은 1차 MVP 에서 Git/Markdown 이 SSOT 이며, DB 의 `document_index` 는 path 와 parsed metadata 를 저장한다.
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
DOCUMENT_INDEX ||--o{ DOCUMENT_VERSION_SNAPSHOT : indexes
|
||||
DOCUMENT_INDEX ||--o{ LINK_EDGE : has
|
||||
DOCUMENT_INDEX ||--o{ GATE_RUN : checked_by
|
||||
DOCUMENT_INDEX ||--o{ REVIEW_ITEM : creates
|
||||
JOB ||--o{ JOB_EVENT : records
|
||||
JOB ||--o{ PROPOSAL : produces
|
||||
PROPOSAL ||--o{ GATE_RUN : validated_by
|
||||
PROVIDER_PROFILE ||--o{ JOB : executes
|
||||
|
||||
DOCUMENT_INDEX {
|
||||
uuid id PK
|
||||
string path
|
||||
string layer
|
||||
string source_type
|
||||
string status
|
||||
string confidence
|
||||
string[] tags
|
||||
date last_reviewed
|
||||
string git_blob_sha
|
||||
}
|
||||
DOCUMENT_VERSION_SNAPSHOT {
|
||||
uuid id PK
|
||||
uuid document_id FK
|
||||
string git_commit_sha
|
||||
string content_hash
|
||||
timestamp indexed_at
|
||||
}
|
||||
LINK_EDGE {
|
||||
uuid id PK
|
||||
uuid from_document_id FK
|
||||
string to_path
|
||||
string link_type
|
||||
string status
|
||||
}
|
||||
GATE_RUN {
|
||||
uuid id PK
|
||||
uuid document_id FK
|
||||
uuid proposal_id FK
|
||||
string gate_name
|
||||
string status
|
||||
json result
|
||||
timestamp ran_at
|
||||
}
|
||||
JOB {
|
||||
uuid id PK
|
||||
string task_type
|
||||
string status
|
||||
string target_path
|
||||
uuid provider_profile_id FK
|
||||
timestamp created_at
|
||||
}
|
||||
JOB_EVENT {
|
||||
uuid id PK
|
||||
uuid job_id FK
|
||||
string event_type
|
||||
json payload
|
||||
timestamp created_at
|
||||
}
|
||||
PROPOSAL {
|
||||
uuid id PK
|
||||
uuid job_id FK
|
||||
string status
|
||||
string patch_ref
|
||||
string summary
|
||||
timestamp created_at
|
||||
}
|
||||
REVIEW_ITEM {
|
||||
uuid id PK
|
||||
uuid document_id FK
|
||||
string reason
|
||||
string status
|
||||
timestamp due_at
|
||||
}
|
||||
PROVIDER_PROFILE {
|
||||
uuid id PK
|
||||
string provider
|
||||
string execution_mode
|
||||
string credential_location
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 기술 결정
|
||||
|
||||
> **Legacy reference (v1).** 아래 비교표는 rationale을 보존한다. stable decision owner와 branch 상속 기준은 §6.1 registry다.
|
||||
|
||||
| 결정 영역 | 선택 | 검토한 대안 | 채택 이유 | 트레이드오프 | 근거 자료 |
|
||||
|---|---|---|---|---|---|
|
||||
| 문서 SSOT | 1차 MVP 는 Git/Markdown SSOT + DB index/control plane | DB-first, object storage-first | 현재 LLM Wiki 의 Git diff, Obsidian, CLI agent 호환성을 유지하기 위함 | DB 기반 rich editor 구현은 늦어진다 | 본 문서 §1.1 |
|
||||
| DB 역할 | metadata / state / queue / audit log / gate result | 문서 본문 전체 저장 | 상태 질의와 문서 원본을 분리해 복구성을 높인다 | DB 와 Git index sync 필요 | 본 문서 §5 |
|
||||
| agent 실행 | local runner 가 로컬 로그인 CLI/SDK 호출 | 서버가 provider token 보관, browser UI automation | credential centralization 을 피하고 사용자 로컬 환경을 활용한다 | runner 설치와 online 상태가 필요 | 별도 policy branch 필요 |
|
||||
| 수정 적용 | proposal -> deterministic gate -> approval -> apply | LLM direct write, auto-commit | LLM 작성 오류와 규칙 위반을 apply 전에 차단한다 | 작업 속도는 느려진다 | 본 문서 §4.3 |
|
||||
| scheduler | stale review item 생성, 자동 수정 금지 | 매일 자동 수정/커밋 | 개인 지식창고의 신뢰도를 유지하고 과잉 자동화를 피한다 | 사용자가 review inbox 를 처리해야 한다 | 본 문서 §4.2 |
|
||||
| desktop app | Tauri 우선 검토 | Electron, web-only | 개인용 local integration, filesystem bridge, 가벼운 배포를 기대 | frontend/native boundary 설계 필요 | 별도 branch 필요 |
|
||||
| server stack | 미정. FastAPI / Spring Boot / NestJS 비교 후 선택 | 단일 stack 선결정 | 이 문서는 project hub 이며, stack 결정은 별도 branch 에서 근거와 trade-off 를 박는다 | 초기 구현 착수 전 결정 필요 | `feature-server-stack-selection-contract` 예정 |
|
||||
|
||||
<!-- section-id: project-decisions -->
|
||||
## 6.1 안정 결정 레지스트리
|
||||
|
||||
| Decision ID | Revision | Domain | Decision Summary | Status | Owner | Evidence |
|
||||
|---|---:|---|---|---|---|---|
|
||||
| `DEC-LLM-WIKI-SERVER-MIGRATION-DOCUMENT-SSOT-001` | 1 | `document-ssot` | MVP는 Git·Markdown을 document SSOT로 유지하고 DB를 index·control plane으로 사용한다 | `active` | [[raw/project-notes/llm-wiki-server-migration]] | §6 `문서 SSOT`; §1.1 |
|
||||
| `DEC-LLM-WIKI-SERVER-MIGRATION-DATABASE-ROLE-001` | 1 | `database-role` | DB는 metadata·state·queue·audit log·gate result를 저장한다 | `active` | [[raw/project-notes/llm-wiki-server-migration]] | §6 `DB 역할`; §5 |
|
||||
| `DEC-LLM-WIKI-SERVER-MIGRATION-AGENT-EXECUTION-001` | 1 | `agent-execution` | local runner가 locally authenticated CLI 또는 SDK를 호출한다 | `needs-confirmation` | [[raw/project-notes/llm-wiki-server-migration]] | §6 `agent 실행`; 별도 policy branch 필요 |
|
||||
| `DEC-LLM-WIKI-SERVER-MIGRATION-APPLY-WORKFLOW-001` | 1 | `apply-workflow` | 변경은 proposal·deterministic gate·approval·apply 순서로 적용한다 | `active` | [[raw/project-notes/llm-wiki-server-migration]] | §6 `수정 적용`; §4.3 |
|
||||
| `DEC-LLM-WIKI-SERVER-MIGRATION-SCHEDULER-001` | 1 | `scheduler` | scheduler는 stale review item만 생성하고 문서를 자동 수정하지 않는다 | `active` | [[raw/project-notes/llm-wiki-server-migration]] | §6 `scheduler`; §4.2 |
|
||||
| `DEC-LLM-WIKI-SERVER-MIGRATION-DESKTOP-RUNTIME-001` | 1 | `desktop-runtime` | desktop runtime 후보는 Tauri 우선 검토이며 채택은 확정 전이다 | `needs-confirmation` | [[raw/project-notes/llm-wiki-server-migration]] | §6 `desktop app`; 별도 branch 필요 |
|
||||
| `DEC-LLM-WIKI-SERVER-MIGRATION-SERVER-STACK-001` | 1 | `server-stack` | FastAPI·Spring Boot·NestJS 중 server stack을 선택한다 | `needs-confirmation` | [[raw/project-notes/llm-wiki-server-migration]] | §6 `server stack`; `feature-server-stack-selection-contract` 예정 |
|
||||
|
||||
<!-- section-id: implementation-boundaries -->
|
||||
## 7. 비기능 요구사항
|
||||
|
||||
- **성능**: 1차 MVP 목표는 단일 사용자 기준 문서 5,000개 index rebuild 60초 이내, 단일 문서 gate run 5초 이내. 실제 측정 전까지 `planned`.
|
||||
- **가용성**: local-only MVP 는 개인 도구이므로 SLO 를 두지 않는다. home server 모드에서는 server down 시 Git/Markdown 직접 편집이 fallback 이다.
|
||||
- **확장성**: multi-user SaaS 는 범위 밖. 단일 사용자, 여러 device/runner 후보까지만 고려한다.
|
||||
- **보안**: 서버는 provider personal CLI token 을 저장하지 않는다. local runner credential boundary 를 문서화한다. API 는 local-only 모드에서도 token 또는 local secret 을 둔다.
|
||||
- **운영 / Observability**: job event, proposal lifecycle, gate result, scheduler run 을 audit log 로 남긴다.
|
||||
- **재해 복구 / DR**: Git remote backup 을 1차 복구 수단으로 둔다. DB 는 재인덱싱 가능해야 한다.
|
||||
- **컴플라이언스**: 개인용 도구이므로 외부 개인정보 처리 컴플라이언스는 1차 범위 밖. 단, secret/token/PII 가 문서에 들어갈 수 있으므로 local secret scan 은 별도 branch 후보로 둔다.
|
||||
|
||||
<!-- section-id: project-work-items -->
|
||||
## 8.0 실행계획
|
||||
|
||||
| Work Item ID | branch slug | 완료 조건 (측정가능) | Applies Decisions | Dependencies | Status |
|
||||
|---|---|---|---|---|---|
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-001` | `feature-repository-source-of-truth-contract` | Git-first·DB-first 결정표, rollback/fallback, sync invariant 5개 이상이 문서화된다 | `DEC-LLM-WIKI-SERVER-MIGRATION-DOCUMENT-SSOT-001@1`, `DEC-LLM-WIKI-SERVER-MIGRATION-DATABASE-ROLE-001@1` | - | `planned` |
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-002` | `feature-server-stack-selection-contract` | 3개 stack 비교와 선택 기준 5개 이상을 근거와 함께 기록한다 | `DEC-LLM-WIKI-SERVER-MIGRATION-SERVER-STACK-001@1` | - | `planned` |
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-003` | `feature-document-metadata-data-model` | document_index·link_edge·gate_run·job·proposal schema가 migration 가능한 형태로 정의된다 | `DEC-LLM-WIKI-SERVER-MIGRATION-DOCUMENT-SSOT-001@1`, `DEC-LLM-WIKI-SERVER-MIGRATION-DATABASE-ROLE-001@1` | `WI-LLM-WIKI-SERVER-MIGRATION-001` | `planned` |
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-004` | `feature-static-analysis-document-gates` | 기존 lint·link·tag·stale 검사가 server-side gate interface와 result schema로 노출된다 | `DEC-LLM-WIKI-SERVER-MIGRATION-APPLY-WORKFLOW-001@1` | `WI-LLM-WIKI-SERVER-MIGRATION-003` | `planned` |
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-005` | `feature-local-agent-runner-protocol` | registration·job pull·result·heartbeat·failure protocol이 정의된다 | `DEC-LLM-WIKI-SERVER-MIGRATION-AGENT-EXECUTION-001@1`, `DEC-LLM-WIKI-SERVER-MIGRATION-SERVER-STACK-001@1` | `WI-LLM-WIKI-SERVER-MIGRATION-002` | `planned` |
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-006` | `feature-cli-provider-policy-boundary` | provider별 official CLI·SDK 경계와 금지 automation이 official source에 연결된다 | `DEC-LLM-WIKI-SERVER-MIGRATION-AGENT-EXECUTION-001@1` | `WI-LLM-WIKI-SERVER-MIGRATION-005` | `planned` |
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-007` | `feature-server-api-job-queue` | job·proposal·review-item API와 state machine이 정의된다 | `DEC-LLM-WIKI-SERVER-MIGRATION-DATABASE-ROLE-001@1`, `DEC-LLM-WIKI-SERVER-MIGRATION-APPLY-WORKFLOW-001@1` | `WI-LLM-WIKI-SERVER-MIGRATION-003` | `planned` |
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-008` | `feature-desktop-review-workbench` | review inbox·document list·proposal diff·approve/reject 요구사항이 정의된다 | `DEC-LLM-WIKI-SERVER-MIGRATION-DESKTOP-RUNTIME-001@1`, `DEC-LLM-WIKI-SERVER-MIGRATION-APPLY-WORKFLOW-001@1` | `WI-LLM-WIKI-SERVER-MIGRATION-007` | `planned` |
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-009` | `feature-scheduled-stale-review-automation` | 00:00 scan·review-item creation·auto-modify 금지 조건이 정의된다 | `DEC-LLM-WIKI-SERVER-MIGRATION-SCHEDULER-001@1` | `WI-LLM-WIKI-SERVER-MIGRATION-004` | `planned` |
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-010` | `feature-git-sync-export-backup` | remote sync·DB reindex·Markdown export/import recovery 절차가 정의된다 | `DEC-LLM-WIKI-SERVER-MIGRATION-DOCUMENT-SSOT-001@1`, `DEC-LLM-WIKI-SERVER-MIGRATION-DATABASE-ROLE-001@1` | `WI-LLM-WIKI-SERVER-MIGRATION-001` | `planned` |
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-011` | `feature-security-secrets-auth-boundary` | local API auth·runner secret·provider credential non-storage·audit masking 기준이 정의된다 | `DEC-LLM-WIKI-SERVER-MIGRATION-AGENT-EXECUTION-001@1` | `WI-LLM-WIKI-SERVER-MIGRATION-005` | `planned` |
|
||||
| `WI-LLM-WIKI-SERVER-MIGRATION-012` | `feature-observability-audit-log-contract` | job·proposal·gate·scheduler event taxonomy와 minimum audit fields가 정의된다 | `DEC-LLM-WIKI-SERVER-MIGRATION-DATABASE-ROLE-001@1` | `WI-LLM-WIKI-SERVER-MIGRATION-007` | `planned` |
|
||||
|
||||
## 8.1 실행계획
|
||||
|
||||
> **Legacy reference (v1).** 기존 priority 표는 보존하며 stable ID·decision pin·dependency의 SSOT는 위 Work Item Registry다.
|
||||
|
||||
| branch slug | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|
||||
|---|---|---|---|
|
||||
| `feature-repository-source-of-truth-contract` | Git-first vs DB-first 결정표, rollback/fallback 시나리오, sync invariant 5개 이상을 문서화한다 | P1 | - |
|
||||
| `feature-server-stack-selection-contract` | FastAPI / Spring Boot / NestJS 후보 비교표와 선택 기준 5개 이상을 작성한다 | P1 | - |
|
||||
| `feature-document-metadata-data-model` | `document_index`, `link_edge`, `gate_run`, `job`, `proposal` 스키마 초안을 migration 가능한 형태로 작성한다 | P2 | `feature-repository-source-of-truth-contract` |
|
||||
| `feature-static-analysis-document-gates` | 기존 lint/link/tag/stale 검사를 server-side gate interface 로 감싸고 결과 schema 를 정의한다 | P2 | `feature-document-metadata-data-model` |
|
||||
| `feature-local-agent-runner-protocol` | runner registration, job pull, result report, heartbeat, failure code protocol 을 정의한다 | P2 | `feature-server-stack-selection-contract` |
|
||||
| `feature-cli-provider-policy-boundary` | Codex/Claude Code/other CLI 의 official API/SDK/CLI 사용 경계와 금지 automation 을 raw official docs 근거로 정리한다 | P2 | `feature-local-agent-runner-protocol` |
|
||||
| `feature-server-api-job-queue` | job/proposal/review-item API endpoint 초안과 state machine 을 정의한다 | P3 | `feature-document-metadata-data-model` |
|
||||
| `feature-desktop-review-workbench` | review inbox, document list, proposal diff, approve/reject 화면 요구사항을 정의한다 | P3 | `feature-server-api-job-queue` |
|
||||
| `feature-scheduled-stale-review-automation` | 매일 00:00 stale scan 조건, review item 생성 규칙, auto-modify 금지 조건을 정의한다 | P3 | `feature-static-analysis-document-gates` |
|
||||
| `feature-git-sync-export-backup` | Git remote sync, DB 재인덱싱, Markdown export/import 복구 절차를 정의한다 | P4 | `feature-repository-source-of-truth-contract` |
|
||||
| `feature-security-secrets-auth-boundary` | local API auth, runner secret, provider credential non-storage, audit log masking 기준을 정의한다 | P4 | `feature-local-agent-runner-protocol` |
|
||||
| `feature-observability-audit-log-contract` | job/proposal/gate/scheduler event taxonomy 와 최소 audit fields 를 정의한다 | P4 | `feature-server-api-job-queue` |
|
||||
|
||||
## 8. 묶음
|
||||
|
||||
<!-- GENERATED: sources:start -->
|
||||
- [[raw/company-tech-blogs/deliberate-practice-software-developers-redgreencode]]
|
||||
- [[raw/company-tech-blogs/senior-engineer-competency-mubin-shaikh]]
|
||||
- [[raw/company-tech-blogs/skillable-hands-on-lab-structure]]
|
||||
<!-- GENERATED: sources:end -->
|
||||
|
||||
### 8.1 브랜치
|
||||
|
||||
<!-- GENERATED: branches:start -->
|
||||
<!-- GENERATED: branches:end -->
|
||||
|
||||
> generated reverse view는 child branch의 v2 contract migration 후 채운다. 현재 branch-note가 없다는 기존 설명은 그대로 유지한다.
|
||||
|
||||
아직 생성된 branch-note 없음. 위 §8.0 의 branch slug 는 실행계획이며, 실제 생성 전까지 wikilink 로 만들지 않는다.
|
||||
|
||||
### 8.2 근거 자료
|
||||
|
||||
Foundational source 는 아직 raw 로 archive 하지 않았다. 첫 source 수집 후보:
|
||||
|
||||
- OpenAI Codex official docs / manual — Codex CLI, SDK, MCP, non-interactive execution, credentials boundary 확인.
|
||||
- Anthropic Claude Code official docs — CLI/SDK, automation, credentials boundary 확인.
|
||||
- Google Gemini CLI / API official docs — local CLI/API boundary 확인.
|
||||
- SQLite / PostgreSQL official docs — MVP DB 선택 근거.
|
||||
- Tauri / Electron official docs — desktop app runtime 선택 근거.
|
||||
|
||||
### 8.3 오류 기록
|
||||
|
||||
- 아직 없음.
|
||||
|
||||
### 8.4 면접 준비
|
||||
|
||||
- 아직 없음. 후보 질문: "LLM 문서 시스템에서 Git-first 와 DB-first 를 어떻게 비교했는가?"
|
||||
|
||||
### 8.5 블로그·채용공고 연계 글감
|
||||
|
||||
- 아직 없음. 후보 글감: "개인 LLM Wiki 를 문서 운영 시스템으로 확장하기".
|
||||
|
||||
### 8.6 파생 wiki 문서
|
||||
|
||||
- canonical 검증 사실: 아직 없음.
|
||||
- 관련 일반 개념: 아직 없음.
|
||||
- 포트폴리오: 아직 없음.
|
||||
- 블로그 글: 아직 없음.
|
||||
|
||||
## 9. 검증 등급
|
||||
|
||||
| 영역 | 등급 | 근거 |
|
||||
|---|---|---|
|
||||
| 아키텍처 다이어그램 | `planned` | draw.io 미작성 |
|
||||
| 시퀀스 다이어그램 | `documented-only` | 본 문서 §4 Mermaid 초안 |
|
||||
| 기술 결정 | `documented-only` | 본 문서 §6 초안. official docs raw archive 전 |
|
||||
| 비기능 요구사항 | `planned` | 목표값만 있음. 측정 없음 |
|
||||
| local runner policy | `needs-confirmation` | provider official docs 기반 별도 branch 필요 |
|
||||
|
||||
### 9.1 실제 구현 내용 (`actually-implemented`)
|
||||
|
||||
- 없음. 본 문서는 프로젝트 착수 초안이다.
|
||||
|
||||
### 9.2 로컬/dev 검증 (`locally-verified`)
|
||||
|
||||
- 없음.
|
||||
|
||||
### 9.3 운영 검증 (`prod-verified`)
|
||||
|
||||
- 없음.
|
||||
|
||||
### 9.4 문서/계획만 존재 (`documented-only`
|
||||
|
||||
- Git/Markdown SSOT + DB index/control plane 방향.
|
||||
- Local Agent Runner 가 로컬 CLI/SDK 를 호출하고 서버가 provider token 을 저장하지 않는 경계.
|
||||
- Approval-first patch flow.
|
||||
- Scheduled stale review.
|
||||
- Static gate result persistence.
|
||||
|
||||
## 10. 면접·외부 공개 답변 경계
|
||||
|
||||
### 10.1 자신 있게 답할 수 있는 범위
|
||||
|
||||
- 현재 LLM Wiki 의 한계와 서버/DB/control plane 으로 확장하려는 문제 정의.
|
||||
- Git-first 와 DB-first 의 trade-off.
|
||||
- local runner 로 개인 CLI 인증 경계를 분리하려는 설계 의도.
|
||||
- 자동 수정이 아니라 proposal + approval + deterministic gate 를 기본으로 두는 이유.
|
||||
|
||||
### 10.2 적당히 답할 수 있는 범위
|
||||
|
||||
- desktop app 후보(Tauri/Electron/web-only) 비교 방향.
|
||||
- PostgreSQL vs SQLite MVP 선택 방향.
|
||||
- stale review scheduler 의 초기 정책.
|
||||
|
||||
### 10.3 답하면 안 되는 / 공식 문서 다시 확인 해야 하는 범위
|
||||
|
||||
- 특정 CLI provider 약관상 허용/금지의 확정 판단. 별도 official docs raw archive 와 policy branch 가 필요하다.
|
||||
- 성능 수치 달성 여부. 아직 구현과 측정이 없다.
|
||||
- 보안적으로 안전하다는 단정. credential boundary 설계와 검증 전이다.
|
||||
- multi-user SaaS 로 확장 가능하다는 주장. 현재 범위는 개인용이다.
|
||||
|
||||
### 10.4 과장 금지 지점
|
||||
|
||||
- "서버로 옮겼다"라고 말하지 않는다. 현재는 project-note 초안이다.
|
||||
- "AI 가 문서를 자동 관리한다"라고 말하지 않는다. 초기 방향은 review item/proposal 생성이다.
|
||||
- "CLI provider 정책을 준수한다"라고 단정하지 않는다. official docs 확인 전에는 `needs-confirmation` 이다.
|
||||
- "DB 가 문서 신뢰도를 보장한다"라고 말하지 않는다. 신뢰도는 evidence, deterministic gate, review process 로 관리한다.
|
||||
|
||||
## 11. 아키텍처 검토 체크리스트
|
||||
|
||||
- [x] 한 줄 요약 + 현재 상태 + 나의 역할 채워짐 (§1)
|
||||
- [x] 측정 가능한 성공 기준 1개 이상 (§2.3)
|
||||
- [ ] 아키텍처 다이어그램 (`.drawio.svg`) 1개 이상 첨부 (§3.1) — 미작성
|
||||
- [ ] 다이어그램이 [[rules/diagram-standards]] v2 minimalist 통과 — 미검증
|
||||
- [ ] 외부 시스템이 점선 + 회색 fill 로 시각적 구분 — draw.io 작성 후 확인
|
||||
- [x] 시퀀스 다이어그램 1개 이상 (Mermaid) — §4 총 3개
|
||||
- [x] 데이터 모델 ER 그림 — §5 초안
|
||||
- [x] 주요 기술 결정 표에 트레이드오프 명시 (§6)
|
||||
- [x] 비기능 요구사항 명시 (§7)
|
||||
- [x] Branch 분해표 채워짐 (§8.0)
|
||||
- [x] Cluster 섹션 작성 (§8)
|
||||
- [x] 검증 등급 명시 (§9)
|
||||
- [x] 면접 답변 경계 명시 (§10)
|
||||
- [x] 마지막 architecture review 날짜 frontmatter `architecture_review:` 에 기록
|
||||
|
||||
## 12. 다이어그램 파일 관리 가이드
|
||||
|
||||
- 예정 위치: `raw/diagrams/llm-wiki-server-migration/`
|
||||
- 첫 다이어그램 후보:
|
||||
- `architecture-overview-2026-06-29.drawio`
|
||||
- `architecture-deployment-local-2026-06-29.drawio`
|
||||
- `architecture-runner-boundary-2026-06-29.drawio`
|
||||
- 생성 후 frontmatter `diagrams:` 에 활성 파일을 추가한다.
|
||||
|
||||
## 13. 관련 개념
|
||||
|
||||
- [[llm-wiki]] — 전체 vault / MOC.
|
||||
- [[rules/linking-rules]] — raw/wiki upward link 와 derived gate.
|
||||
- [[rules/naming-conventions]] — project-note 와 branch-note naming.
|
||||
- [[rules/tag-taxonomy]] — project-note tags.
|
||||
- [[rules/advisory-depth]] — 권고/설계 문서의 overclaim 방지.
|
||||
|
||||
## 14. 다음 단계
|
||||
|
||||
- [ ] `feature-repository-source-of-truth-contract` branch-note 생성.
|
||||
- [ ] provider official docs 를 raw/official-docs 로 archive 한 뒤 `feature-cli-provider-policy-boundary` 작성.
|
||||
- [ ] draw.io architecture overview 생성.
|
||||
- [ ] server stack selection branch 에서 FastAPI / Spring Boot / NestJS 비교.
|
||||
- [ ] data model branch 에서 DB-first 전환 가능성을 별도 open risk 로 정리.
|
||||
@@ -1 +0,0 @@
|
||||
../../vault/10-projects/nplus1-presentation-prep/project-notes/nplus1-presentation-prep.md
|
||||
@@ -0,0 +1,282 @@
|
||||
---
|
||||
title: N+1 Presentation Preparation Contract
|
||||
source_type: project-note
|
||||
status: raw
|
||||
confidence: medium
|
||||
tags: [project-note, nplus1-presentation-prep, learning, hibernate, hands-on-lab]
|
||||
related_projects: [nplus1-presentation-prep, ca-tmpl]
|
||||
created: 2026-07-20
|
||||
last_reviewed: 2026-07-20
|
||||
diagrams: [nplus1-presentation-prep/architecture-lab-loop-2026-07-20.drawio, sequence-api-replay-lab-mermaid]
|
||||
architecture_review: 2026-07-20
|
||||
status_label: active
|
||||
project_revision: 1
|
||||
semantic_surface_exclusions:
|
||||
- artifact-registry|legacy hub has no project-local Artifact Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
- contract-gate-registry|legacy hub has no project-local Contract/Gate Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
- flow-stage-registry|legacy hub has no project-local Flow/Stage Registry; harness/source/typed-contracts.json is authoritative until migration
|
||||
---
|
||||
|
||||
# N+1 Presentation Preparation Contract
|
||||
|
||||
> Layer: `raw/project-notes/` (primary, hub) → `/ingest` 후 검증된 사실만 `wiki/projects/`로 추출한다.
|
||||
> 이 문서는 N+1 재현·측정·발표 준비 작업의 최상위 project hub이자 project decision/work-item SSOT다.
|
||||
> `status_label`: `active`
|
||||
|
||||
## 1. 프로젝트 개요
|
||||
|
||||
- **한 줄 요약**: ca-tmpl의 feed 조회를 단계별로 재현하고, HTTP·PostgreSQL·Hibernate 관찰값을 근거 등급과 함께 설명할 수 있는 N+1 학습 랩을 만든다.
|
||||
- **기간**: 2026-07-08 ~ 진행 중
|
||||
- **현재 상태**: `active`
|
||||
- **나의 역할 / Role**: 학습 랩 설계자·검증자·발표 준비자
|
||||
- **저장소 / Repo**: ca-tmpl 로컬 저장소의 `lab/nplus1-highlight-feed`, `lab/nplus1-api-replay` Git branch를 사용한다. 원격 URL은 이 문서에서 확인하지 않았다.
|
||||
|
||||
## 2. 문제 정의
|
||||
|
||||
### 2.1 현재 상태의 문제
|
||||
|
||||
- 마지막 최적화 상태만 보면 lazy collection N+1부터 one-query read까지의 원인·선택·관찰값 변화를 순서대로 재현하기 어렵다.
|
||||
- 테스트 결과만 읽으면 학습자가 HTTP 응답과 실제 PostgreSQL row를 함께 관찰하는 실행 경로가 드러나지 않는다.
|
||||
- 로컬 측정 결과를 production 성능·배포 증거로 확대 해석할 위험이 있다.
|
||||
|
||||
### 2.2 왜 지금 해결해야 하는가
|
||||
|
||||
- **트리거**: N+1 주제를 구현 결과 나열이 아니라 재현 가능한 발표·학습 흐름으로 준비해야 한다.
|
||||
- **비용**: 단계별 checkpoint와 근거 등급이 없으면 어떤 해법이 어떤 문제를 해결했는지 다시 검증하기 어렵다.
|
||||
- **기회**: 동일한 관찰 루프를 반복하면 쿼리 수 최적화와 read-model 분리를 서로 다른 선택으로 비교할 수 있다.
|
||||
|
||||
### 2.3 성공 기준
|
||||
|
||||
- L1, L2, L3, L4, L5, L6, L14, L15, L16, Crown, L12의 정확히 11개 replay checkpoint가 guide와 대응한다.
|
||||
- 각 checkpoint가 reset → HTTP → PostgreSQL 관찰 순서와 기대 관찰점을 가진다.
|
||||
- local·Testcontainers·production 증거가 같은 등급으로 섞이지 않고 각 결과에 evidence grade가 기록된다.
|
||||
- 두 직접 자식 branch가 아래 Work Item Registry의 pinned decision refs와 dependency를 그대로 상속한다.
|
||||
|
||||
<!-- section-id: architecture-components -->
|
||||
## 3. 시스템 아키텍처
|
||||
|
||||
### 3.1 아키텍처 다이어그램 (draw.io XML)
|
||||
|
||||
**질문**: 학습자가 checkout한 N+1 checkpoint는 어떤 경로를 거쳐 검토 가능한 관찰 기록이 되는가?
|
||||
|
||||
![[raw/diagrams/nplus1-presentation-prep/architecture-lab-loop-2026-07-20.drawio]]
|
||||
|
||||
다이어그램은 Learner → Lab Checkpoint → Feed Module → PostgreSQL → Evidence Record → Presentation 경로를 나타낸다. 이는 정적 구조와 증거 승격 경계를 설명하며, 시간 순서의 세부 호출은 §4 Mermaid가 소유한다.
|
||||
|
||||
### 3.2 컴포넌트 책임 분담
|
||||
|
||||
| 컴포넌트 | 역할 | 기술 스택 | 의존하는 외부 |
|
||||
|---|---|---|---|
|
||||
| Learner | checkpoint를 checkout하고 관찰 절차를 실행한다 | Git, HTTP client, psql | 로컬 실행 환경 |
|
||||
| Lab Checkpoint | 학습용 reset·feed 경로를 profile 안에서 노출한다 | Spring profile, HTTP API | Feed Module |
|
||||
| Feed Module | checkpoint별 조회 전략을 실행한다 | Spring Data JPA, Hibernate | PostgreSQL |
|
||||
| PostgreSQL | fixture row와 SQL 실행 결과를 제공한다 | PostgreSQL, Docker Compose/Testcontainers | 없음 |
|
||||
| Evidence Record | 쿼리·entity load·row 관찰값과 등급을 기록한다 | Markdown, test report | 각 checkpoint 결과 |
|
||||
|
||||
### 3.3 외부 의존성
|
||||
|
||||
| 외부 시스템 | 용도 | 통신 방식 | 장애 시 영향 |
|
||||
|---|---|---|---|
|
||||
| Docker runtime | 로컬 PostgreSQL과 Compose/Testcontainers 실행 | local container API | DB 기반 replay와 integration evidence를 수집할 수 없다 |
|
||||
| PostgreSQL | fixture·native query·row 확인 | JDBC, psql | SQL 관찰 단계가 실패하며 in-memory 결과로 대체하지 않는다 |
|
||||
|
||||
### 3.4 배포 다이어그램
|
||||
|
||||
운영 배포 토폴로지는 이 프로젝트의 검증 범위가 아니다. `lab` profile이 운영 환경에서 비활성이라는 deployment-level 증거는 아직 `needs-confirmation`이다.
|
||||
|
||||
<!-- section-id: runtime-flow -->
|
||||
## 4. 핵심 시퀀스
|
||||
|
||||
<!-- section-id: sequence -->
|
||||
### 4.1 API replay lab flow
|
||||
|
||||
**시나리오**: 학습자가 checkpoint를 checkout한 뒤 lab fixture를 reset하고 feed·DB·Hibernate 관찰값을 기록한다.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor Learner
|
||||
participant API as Lab API
|
||||
participant Feed as Feed Module
|
||||
participant DB as PostgreSQL
|
||||
participant Stats as Hibernate Statistics
|
||||
|
||||
Learner->>API: POST /api/lab/feed:reset {count}
|
||||
alt lab profile active and input valid
|
||||
API->>DB: replace marker-owned fixture
|
||||
DB-->>API: row counts
|
||||
API-->>Learner: 200 reset result
|
||||
Learner->>API: GET /api/lab/feed
|
||||
API->>Feed: execute checkpoint strategy
|
||||
Feed->>DB: SELECT feed rows
|
||||
DB-->>Feed: result rows
|
||||
Feed->>Stats: read statement and load counts
|
||||
Stats-->>Feed: observation values
|
||||
Feed-->>API: feed and observations
|
||||
API-->>Learner: 200 replay result
|
||||
else lab profile inactive
|
||||
API-->>Learner: 404 route not registered
|
||||
else input outside guard
|
||||
API-->>Learner: 400 VALIDATION_FAILED
|
||||
end
|
||||
```
|
||||
|
||||
성공 경로의 수치는 checkpoint마다 다르므로 프로젝트 문서가 하나의 고정 수치를 일반화하지 않는다. 관찰값은 각 branch의 Evidence 섹션에서 환경과 함께 판정한다.
|
||||
|
||||
## 5. 데이터 모델
|
||||
|
||||
별도 프로젝트 데이터 모델을 소유하지 않는다. ca-tmpl feed model과 `created_by = nplus1-lab` marker fixture를 사용하며, 이 문서는 단계·관찰·근거 등급 계약만 소유한다.
|
||||
|
||||
## 6. 기술 결정
|
||||
|
||||
| 결정 영역 | 선택 | 검토한 대안 | 채택 이유 | 트레이드오프 | 근거 자료 |
|
||||
|---|---|---|---|---|---|
|
||||
| 학습 루프 | Measure→Break→Diagnose→Fix→Re-measure→Generalize | 마지막 결과만 설명 | 각 단계의 원인·수정·재측정을 연결한다 | checkpoint와 관찰 기록 유지 비용이 생긴다 | [[raw/branch-notes/experiment-nplus1-highlight-feed]] |
|
||||
| 실행 substrate | ca-tmpl production substrate + profile/sibling 격리 | 독립 예제 앱 | 실제 모듈 경계를 사용하면서 학습 경로를 정상 runtime과 분리한다 | profile 오활성 여부는 별도 배포 검증이 필요하다 | [[raw/branch-notes/experiment-nplus1-feed-api-replay]] |
|
||||
| 증거 등급 | local·Testcontainers 결과는 `locally-verified` | 로컬 결과를 운영 결과로 표현 | 검증 환경이 증명하는 범위를 보존한다 | production 결론에는 추가 검증이 필요하다 | [[raw/official-docs/test-taxonomy-testcontainers-official]] |
|
||||
| CQRS 범위 | same-store CQRS-lite까지 | 별도 physical read store를 즉시 도입 | 쿼리 최적화와 application read-model 분리를 현재 실습 범위에서 비교한다 | full CQRS의 동기화·운영 문제는 다루지 않는다 | [[raw/official-docs/cqrs-pattern-azure-architecture-center]] |
|
||||
|
||||
<!-- section-id: project-decisions -->
|
||||
## 6.1 안정 결정 레지스트리
|
||||
|
||||
> 프로젝트가 소유하는 project-wide decision SSOT다. 두 branch packet의 `Project Summary`와 byte-equivalent한 요약을 유지한다.
|
||||
|
||||
| Decision ID | Revision | Domain | Decision Summary | Status | Owner | Evidence |
|
||||
|---|---:|---|---|---|---|---|
|
||||
| `DEC-NPLUS1-PRESENTATION-PREP-LEARNING-001` | 1 | `learning` | Measure→Break→Diagnose→Fix→Re-measure→Generalize를 랩 완료 루프로 사용한다. | `active` | [[raw/project-notes/nplus1-presentation-prep]] | [[raw/branch-notes/experiment-nplus1-highlight-feed]] |
|
||||
| `DEC-NPLUS1-PRESENTATION-PREP-SUBSTRATE-001` | 1 | `substrate` | ca-tmpl production substrate를 사용하고 학습 API·측정 경로는 profile과 sibling 경로로 격리한다. | `active` | [[raw/project-notes/nplus1-presentation-prep]] | [[raw/branch-notes/experiment-nplus1-feed-api-replay]] |
|
||||
| `DEC-NPLUS1-PRESENTATION-PREP-EVIDENCE-001` | 1 | `evidence` | local·Testcontainers 결과는 locally-verified로만 기록하고 prod evidence로 승격하지 않는다. | `active` | [[raw/project-notes/nplus1-presentation-prep]] | [[raw/official-docs/test-taxonomy-testcontainers-official]] |
|
||||
| `DEC-NPLUS1-PRESENTATION-PREP-SCOPE-001` | 1 | `scope` | same-store CQRS-lite까지를 현재 범위로 두고 full CQRS는 ca-tmpl contract escalation 이후에만 허용한다. | `active` | [[raw/project-notes/nplus1-presentation-prep]] | [[raw/official-docs/cqrs-pattern-azure-architecture-center]] |
|
||||
|
||||
<!-- section-id: implementation-boundaries -->
|
||||
## 7. 비기능 요구사항
|
||||
|
||||
- **성능**: production RPS·P99 목표는 설정하지 않는다. checkpoint별 쿼리·entity load 관찰값만 환경과 함께 기록한다.
|
||||
- **가용성**: 운영 SLO는 이 프로젝트 범위가 아니다.
|
||||
- **확장성**: 로컬 단일 학습 실행만 검증 범위로 둔다.
|
||||
- **보안**: 학습 reset/API는 `lab` profile에 한정하고, 정상 profile에서는 route/use case가 등록되지 않아야 한다.
|
||||
- **운영 / Observability**: Hibernate Statistics, HTTP response, PostgreSQL row 확인을 같은 checkpoint evidence에 연결한다.
|
||||
- **재해 복구 / DR**: 해당 없음. marker-owned local fixture는 reset으로 재생성한다.
|
||||
- **컴플라이언스**: 해당 없음. production 데이터는 이 랩의 입력으로 사용하지 않는다.
|
||||
|
||||
<!-- section-id: project-work-items -->
|
||||
## 8.0 실행계획
|
||||
|
||||
> 두 직접 자식 branch의 stable handoff SSOT다. Applies Decisions는 revision 1 project decisions 네 개를 모두 pin한다.
|
||||
|
||||
| Work Item ID | branch slug | 완료 조건 (측정가능) | Applies Decisions | Dependencies | Status |
|
||||
|---|---|---|---|---|---|
|
||||
| `WI-NPLUS1-PRESENTATION-PREP-001` | `experiment-nplus1-highlight-feed` | L2 ToOne EAGER 격리 측정값을 확정하고, L1~L6·L14~L16·Crown·L12의 증거 등급과 사용자 commit-range review를 본문 Closure에 반영한다. | `DEC-NPLUS1-PRESENTATION-PREP-LEARNING-001@1`, `DEC-NPLUS1-PRESENTATION-PREP-SUBSTRATE-001@1`, `DEC-NPLUS1-PRESENTATION-PREP-EVIDENCE-001@1`, `DEC-NPLUS1-PRESENTATION-PREP-SCOPE-001@1` | - | `in-progress` |
|
||||
| `WI-NPLUS1-PRESENTATION-PREP-002` | `experiment-nplus1-feed-api-replay` | 11개 replay tag와 guide mapping을 고정하고, clean clone/worktree에서 Compose·HTTP·PostgreSQL smoke 및 full-check 상태를 재검증하며 lab profile의 deployment 비활성 증거를 기록한다. | `DEC-NPLUS1-PRESENTATION-PREP-LEARNING-001@1`, `DEC-NPLUS1-PRESENTATION-PREP-SUBSTRATE-001@1`, `DEC-NPLUS1-PRESENTATION-PREP-EVIDENCE-001@1`, `DEC-NPLUS1-PRESENTATION-PREP-SCOPE-001@1` | `WI-NPLUS1-PRESENTATION-PREP-001` | `in-progress` |
|
||||
|
||||
## 8. 묶음 (이 프로젝트에 묶이는 모든 raw 자료)
|
||||
|
||||
<!-- GENERATED: blog-topics:start -->
|
||||
- [[raw/blog-topics/nplus1-lab-checkoutable-api-replay-2026-07-15]]
|
||||
<!-- GENERATED: blog-topics:end -->
|
||||
|
||||
### 8.1 브랜치 (project의 직접 자식 branch)
|
||||
|
||||
<!-- GENERATED: branches:start -->
|
||||
- [[raw/branch-notes/experiment-nplus1-feed-api-replay]]
|
||||
- [[raw/branch-notes/experiment-nplus1-highlight-feed]]
|
||||
<!-- GENERATED: branches:end -->
|
||||
|
||||
> 아래 표는 사람이 빠르게 식별하기 위한 lookup view다. 완료 조건·decision pin·dependency의 SSOT는 `## 8.0 Work Item Registry / 실행계획`이다.
|
||||
|
||||
| Branch | Work Item | 현재 단계 |
|
||||
|---|---|---|
|
||||
| `experiment-nplus1-highlight-feed` | `WI-NPLUS1-PRESENTATION-PREP-001` | `in-progress` |
|
||||
| `experiment-nplus1-feed-api-replay` | `WI-NPLUS1-PRESENTATION-PREP-002` | `in-progress` |
|
||||
|
||||
### 8.2 근거 자료 (프로젝트 전체 차원 foundational 조사)
|
||||
|
||||
프로젝트에 직접 매달린 source는 없다. 각 source는 자신이 정당화하는 branch의 `## Sources / 근거`에서 추적한다.
|
||||
|
||||
### 8.3 오류 기록 (branch 외 발생한 환경·운영 이슈)
|
||||
|
||||
프로젝트에 직접 매달린 error-note는 없다. replay 과정의 오류는 해당 branch cluster가 소유한다.
|
||||
|
||||
### 8.4 면접 준비
|
||||
|
||||
프로젝트에 직접 매달린 interview-prep 문서는 없다.
|
||||
|
||||
### 8.5 블로그·채용공고 연계 글감
|
||||
|
||||
직접 자식은 없다. checkout replay 글감은 [[raw/branch-notes/experiment-nplus1-feed-api-replay]]의 child로 관리한다.
|
||||
|
||||
### 8.6 파생 wiki 문서
|
||||
|
||||
아직 생성하지 않았다. `reviewed` 이상 canonical로 승급되기 전에는 interview·portfolio·blog를 파생하지 않는다.
|
||||
|
||||
## 9. 검증 등급
|
||||
|
||||
| 영역 | 등급 | 근거 |
|
||||
|---|---|---|
|
||||
| 아키텍처 다이어그램 | `documented-only` | [[raw/diagrams/nplus1-presentation-prep/architecture-lab-loop-2026-07-20.drawio]] |
|
||||
| 시퀀스 다이어그램 | `documented-only` | §4는 branch의 lab API·DB 관찰 경계를 요약하며 별도 실행 증거를 주장하지 않는다 |
|
||||
| 기술 결정 | `documented-only` | §6.1 stable registry와 두 branch packet이 동일한 revision 1 refs를 사용한다 |
|
||||
| replay 구현·로컬 측정 | `locally-verified` | [[raw/branch-notes/experiment-nplus1-feed-api-replay]]의 Docker HTTP + PostgreSQL smoke 기록 |
|
||||
| 전체 checkpoint closure | `needs-confirmation` | WI-001의 L2 실측과 WI-002의 clean clone/deployment 확인이 남아 있다 |
|
||||
|
||||
### 9.1 실제 구현 내용 (`actually-implemented`)
|
||||
|
||||
- 11개 replay commit/tag와 `lab` profile의 reset·feed 관찰 경로는 branch note에 코드 존재 근거와 함께 기록되어 있다.
|
||||
|
||||
### 9.2 로컬/dev 검증 (`locally-verified`)
|
||||
|
||||
- final L12와 historical L1 checkpoint의 Docker HTTP·PostgreSQL smoke 결과는 [[raw/branch-notes/experiment-nplus1-feed-api-replay]]에 환경·명령 경계와 함께 기록되어 있다.
|
||||
|
||||
### 9.3 운영 검증 (`prod-verified`)
|
||||
|
||||
- 없음. 이 프로젝트는 production 성능·권한·배포를 검증했다고 주장하지 않는다.
|
||||
|
||||
### 9.4 문서/계획만 존재 (`documented-only`
|
||||
|
||||
- 다른 clean machine/worktree의 전체 11-stage 재현과 deployment manifest의 `lab` profile 비활성 확인은 `needs-confirmation`이다.
|
||||
|
||||
## 10. 면접·외부 공개 답변 경계
|
||||
|
||||
### 10.1 자신 있게 답할 수 있는 범위
|
||||
|
||||
- 각 checkout 단계에서 무엇을 측정하고 다음 단계가 어떤 문제를 다루는지 branch evidence를 근거로 설명할 수 있다.
|
||||
- Crown one-query 경로와 L12 same-store CQRS-lite two-query read-model이 같은 선택이 아님을 설명할 수 있다.
|
||||
|
||||
### 10.2 적당히 답할 수 있는 범위
|
||||
|
||||
- 로컬 Docker Compose/Testcontainers에서 관찰한 SQL·HTTP 결과는 환경과 evidence grade를 함께 제시할 때만 답한다.
|
||||
|
||||
### 10.3 답하면 안 되는 / 공식 자료를 다시 확인해야 하는 범위
|
||||
|
||||
- production latency·throughput·권한 경계·다중 인스턴스 동작은 검증하지 않았다.
|
||||
- 다른 환경에서 11개 tag가 모두 같은 결과를 낸다고 단정하지 않는다.
|
||||
|
||||
### 10.4 과장 금지 지점
|
||||
|
||||
- local·Testcontainers 결과를 production evidence로 표현하지 않는다.
|
||||
- `addScalar` runtime mapping을 SQL compile-time 검증으로 표현하지 않는다.
|
||||
- same-store CQRS-lite를 별도 read store·동기화 파이프라인을 가진 full CQRS로 표현하지 않는다.
|
||||
|
||||
## 11. 아키텍처 검토 체크리스트
|
||||
|
||||
- [x] 한 줄 요약·상태·역할을 기록했다.
|
||||
- [x] 11 checkpoint와 evidence grade의 측정 가능한 성공 기준을 기록했다.
|
||||
- [x] 정적 구조는 draw.io, 시간축은 Mermaid sequence diagram으로 분리했다.
|
||||
- [x] Mermaid에 happy path와 profile/input error path를 함께 넣었다.
|
||||
- [x] project decision 4개와 Work Item 2개를 stable ID·pinned revision으로 고정했다.
|
||||
- [x] 생성 children block이 두 직접 자식 branch와 일치한다.
|
||||
- [ ] draw.io에 대한 독립 `wiki-diagram-reviewer` ≥95 판정은 이 문서 작성 범위에서 수행하지 않았다.
|
||||
- [ ] WI-001·WI-002의 남은 완료 조건을 충족한 뒤 project status와 evidence grade를 재검토한다.
|
||||
|
||||
## 12. 다이어그램 파일 관리 가이드
|
||||
|
||||
- 정적 구조 SSOT: `raw/diagrams/nplus1-presentation-prep/architecture-lab-loop-2026-07-20.drawio`
|
||||
- 시간축 SSOT: 이 문서 §4의 Mermaid `sequenceDiagram`
|
||||
- 구조 또는 흐름이 바뀌면 새 날짜의 draw.io를 추가하고 `architecture_review`와 `last_reviewed`를 함께 갱신한다.
|
||||
- 검증 환경·수치 변경은 다이어그램 안이 아니라 branch evidence와 이 문서 §9에 기록한다.
|
||||
|
||||
## 13. 관련 개념
|
||||
|
||||
- [[raw/official-docs/spring-data-jpa-projections-spring-official]] — projection/read shape의 공식 경계.
|
||||
- [[raw/official-docs/cqrs-pattern-azure-architecture-center]] — same-store read/write model 분리와 별도 store CQRS의 범위 구분.
|
||||
- [[raw/official-docs/test-taxonomy-testcontainers-official]] — 실제 dependency를 사용하는 integration evidence의 근거.
|
||||
@@ -1 +0,0 @@
|
||||
../../vault/10-projects/project-infra-overview/project-notes/project-infra-overview.md
|
||||
@@ -0,0 +1,196 @@
|
||||
---
|
||||
title: 프로젝트 인프라 개요
|
||||
source_type: project-note
|
||||
status: raw
|
||||
confidence: unknown
|
||||
tags: [project-note, project-overview, infra, stub]
|
||||
related_projects: []
|
||||
last_reviewed:
|
||||
diagrams: []
|
||||
architecture_review:
|
||||
status_label: stub
|
||||
project_revision: 1
|
||||
url:
|
||||
semantic_surface_exclusions:
|
||||
- artifact-registry|stub project has no project-local Artifact Registry; harness/source/typed-contracts.json is authoritative until facts are supplied
|
||||
- contract-gate-registry|stub project has no project-local Contract/Gate Registry; harness/source/typed-contracts.json is authoritative until facts are supplied
|
||||
- flow-stage-registry|stub project has no project-local Flow/Stage Registry; harness/source/typed-contracts.json is authoritative until facts are supplied
|
||||
---
|
||||
|
||||
# 프로젝트 인프라 개요
|
||||
|
||||
> **작성 안내**
|
||||
> 이 파일은 첫 `/ingest` → `/tag` → `/lint` 사이클 검증용 raw 문서입니다.
|
||||
> 아래 `<...>` 자리표시자를 **본인 프로젝트의 사실**로 교체하세요.
|
||||
> 일반론·추측·계획은 적지 말고 실제 한 일·확인한 것만 기록합니다.
|
||||
> 작성 후 `/ingest raw/project-notes/project-infra-overview.md`로 파이프라인을 검증합니다.
|
||||
>
|
||||
> **관련 문서**:
|
||||
> - [[CLAUDE]] — LLM Wiki 운영 규칙
|
||||
> - [[llm-wiki]] — vault MOC
|
||||
> - [[raw/project-notes/ca-skeleton-operational-contract]] — sister project note (ca-tmpl 운영 계약)
|
||||
> - [[templates/project-template]] — `wiki/projects/` 승급 시 사용할 템플릿
|
||||
|
||||
---
|
||||
|
||||
<!-- section-id: project-decisions -->
|
||||
## 6.1 안정 결정 레지스트리
|
||||
|
||||
> `NEEDS_CONFIRMATION`: 이 문서에는 아직 placeholder가 남아 있어서, 문서 자체 근거만으로 확정할 결정이 없다. 사실이 채워질 때까지 registry는 비워 둔다.
|
||||
|
||||
| Decision ID | Revision | Domain | Decision Summary | Status | Owner | Evidence |
|
||||
|---|---:|---|---|---|---|---|
|
||||
|
||||
<!-- section-id: project-work-items -->
|
||||
## 8.0 실행계획
|
||||
|
||||
> `NEEDS_CONFIRMATION`: 기존 branch decomposition row가 없으므로 stable WI를 생성하지 않는다.
|
||||
|
||||
| Work Item ID | branch slug | 완료 조건 (측정가능) | Applies Decisions | Dependencies | Status |
|
||||
|---|---|---|---|---|---|
|
||||
|
||||
## 1. 프로젝트 한 줄 설명
|
||||
|
||||
<무엇을 만드는/만든 프로젝트인지 1–2문장>
|
||||
|
||||
## 2. 본인 역할
|
||||
|
||||
- 개인/팀 여부: <개인 프로젝트 | 팀 프로젝트 (N인)>
|
||||
- 본인이 맡은 영역: <예: 백엔드 API, 인프라/배포, DB 모델링 등>
|
||||
- 기간: <YYYY-MM ~ YYYY-MM>
|
||||
|
||||
## 3. 기술 스택
|
||||
|
||||
- 언어:
|
||||
- 프레임워크:
|
||||
- DB:
|
||||
- 캐시 / 메시징:
|
||||
- 인프라 / 배포:
|
||||
- 모니터링 / 로깅:
|
||||
- 기타:
|
||||
|
||||
<!-- section-id: sequence -->
|
||||
## 4. 인프라 구성 요약
|
||||
|
||||
<어떤 환경에서 돌고 있는지. 도식이 있으면 붙이고, 없으면 글로 풀어 쓴다. 로컬/dev/staging/prod 중 어디까지 실제로 띄워 봤는지 밝힌다.>
|
||||
|
||||
<!-- section-id: architecture-components -->
|
||||
### 4.1 시스템 아키텍처 (draw.io)
|
||||
|
||||
> `templates/project-template.md` §3.1 표준에 따라 작성. 저장 경로: `raw/diagrams/<project-slug>/architecture-overview-YYYY-MM-DD.drawio.svg`.
|
||||
> 다이어그램이 생기면 아래 wikilink 갱신:
|
||||
|
||||
```markdown
|
||||
실제 사용 예 (drawio 파일 생성 후 placeholder 부분을 실제 값으로 치환):
|
||||
![[raw/diagrams/<project-slug>/architecture-overview-YYYY-MM-DD.drawio.svg]]
|
||||
```
|
||||
|
||||
(아직 다이어그램 없음. drawio 생성 후 위 code block 밖으로 wikilink 빼기.)
|
||||
|
||||
<!-- section-id: runtime-flow -->
|
||||
### 4.2 핵심 시퀀스 (Mermaid)
|
||||
|
||||
> 주요 user flow 1개 이상. happy path + error path 함께.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor User
|
||||
participant System
|
||||
User->>System: <action>
|
||||
System-->>User: <response>
|
||||
```
|
||||
|
||||
(아직 시퀀스 미정. 작업 진입 후 채움.)
|
||||
|
||||
## 5. 본인이 한 작업 (사실만)
|
||||
|
||||
각 항목 옆에 증거 등급을 표기합니다.
|
||||
가능한 등급: `actually-implemented` | `locally-verified` | `prod-verified` | `documented-only` | `planned` | `needs-confirmation`
|
||||
|
||||
- <작업 1 설명> — 등급: `<...>`
|
||||
- <작업 2 설명> — 등급: `<...>`
|
||||
- <작업 3 설명> — 등급: `<...>`
|
||||
|
||||
## 6. 마주친 문제 / 트러블슈팅
|
||||
|
||||
<실제 겪은 이슈만. 원인 → 시도 → 해결 순. 일반론 X>
|
||||
|
||||
- 이슈 1:
|
||||
- 원인:
|
||||
- 시도:
|
||||
- 해결:
|
||||
|
||||
<!-- section-id: implementation-boundaries -->
|
||||
## 7. 자신 없는 부분
|
||||
|
||||
<면접에서 나올 수 있지만 본인이 확실히 답하지 못하는 영역. `/interviewize`가 "모른다고 답해야 할 범위"를 정리할 때 쓴다.>
|
||||
|
||||
## 8. 관련 자료
|
||||
|
||||
- 저장소 URL:
|
||||
- 관련 PR / 커밋:
|
||||
- README 경로:
|
||||
- 설계 문서:
|
||||
|
||||
## 9. 묶음 (이 프로젝트에 묶이는 모든 raw 자료)
|
||||
|
||||
> 본 project-note가 cluster의 entry point다. branch / errors / interviews / lectures / job-postings / sources 는 모두 여기로 upward link 를 건다. hub 쪽에서도 카테고리별로 적어 둔다.
|
||||
|
||||
### 9.1 브랜치 (작업 단위 hub)
|
||||
|
||||
<!-- GENERATED: branches:start -->
|
||||
<!-- GENERATED: branches:end -->
|
||||
|
||||
> generated reverse view는 child branch의 v2 contract migration 후 채운다. 아래 수기 Cluster는 그 전까지 보존한다.
|
||||
|
||||
| Branch migration status | Reason |
|
||||
|---|---|
|
||||
| `NEEDS_CONFIRMATION` | placeholder를 실제 project 사실로 교체하기 전에는 branch row를 만들지 않는다 |
|
||||
|
||||
> 최상위 root branch들. sub-branch들은 root branch hub의 Cluster 섹션 참조.
|
||||
|
||||
- (없음 — 본 프로젝트 작업 시작 전. branch 생성 시 wikilink 추가.)
|
||||
|
||||
### 9.2 근거 자료 (프로젝트 전체 차원 foundational 조사)
|
||||
|
||||
- (없음)
|
||||
|
||||
### 9.3 오류 기록 (branch 외 발생한 환경·운영 이슈)
|
||||
|
||||
- (없음)
|
||||
|
||||
### 9.4 면접 준비 (프로젝트 전체 차원 면접 질문)
|
||||
|
||||
- (없음)
|
||||
|
||||
### 9.5 Job postings (프로젝트 관련 채용공고)
|
||||
|
||||
- (없음)
|
||||
|
||||
### 9.6 파생 wiki 문서
|
||||
|
||||
- canonical 검증 사실: (없음)
|
||||
- 관련 일반 개념: (없음)
|
||||
- 포트폴리오: (없음)
|
||||
- 블로그 글: (없음)
|
||||
|
||||
## 10. 아키텍처 검토 체크리스트 (작성/갱신 시 self-check)
|
||||
|
||||
> 본 project-note가 hub 역할을 제대로 하려면 모두 ✓ 여야 함. 현재는 placeholder 상태이므로 모두 미달.
|
||||
|
||||
- [ ] 한 줄 요약 + 현재 상태 + 나의 역할 채워짐 (§1, §2)
|
||||
- [ ] 측정 가능한 성공 기준 1개 이상
|
||||
- [ ] 아키텍처 다이어그램 (`.drawio.svg`) 1개 이상 첨부 (§4.1)
|
||||
- [ ] 다이어그램의 모든 컴포넌트가 라벨 + 역할 + 기술 스택 표기
|
||||
- [ ] 다이어그램의 모든 화살표가 프로토콜·데이터 종류 라벨링
|
||||
- [ ] 외부 시스템이 점선 또는 색으로 시각적 구분
|
||||
- [ ] 범례(Legend) 다이어그램에 포함
|
||||
- [ ] 신뢰 경계 / 네트워크 경계 표시
|
||||
- [ ] 시퀀스 다이어그램 1개 이상 (Mermaid) — happy path + error path 함께 (§4.2)
|
||||
- [ ] Cluster 섹션의 root branch 목록 채워짐 (§9.1)
|
||||
- [ ] 마지막 architecture review 날짜 frontmatter `architecture_review:` 에 기록
|
||||
|
||||
---
|
||||
|
||||
> 다 쓴 뒤에도 `status`는 `raw` 그대로 둡니다(이건 raw 문서니까요). 그 상태에서 `/ingest`를 실행하면 `wiki/projects/`에 변환 문서가 만들어집니다.
|
||||
Reference in New Issue
Block a user