From 5c19b88230a0c4baf02bd20b3cf8d45d72dab35e Mon Sep 17 00:00:00 2001 From: Lectom C Han Date: Tue, 27 Jan 2026 17:56:17 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AC=B8=EC=84=9C=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 77 +++++++++++++++++++++++++++-------- AGENTS.md => docs/AGENTS.md | 0 Gemini.md => docs/Gemini.md | 0 docs/idp_policy.md | 27 ++++++++++++ PRD.md => docs/initial_PRD.md | 0 docs/shadowing_policy.md | 64 +++++++++++++++++++++++++++++ docs/tenant_policy.md | 61 --------------------------- to-do.md | 27 ------------ 8 files changed, 152 insertions(+), 104 deletions(-) rename AGENTS.md => docs/AGENTS.md (100%) rename Gemini.md => docs/Gemini.md (100%) create mode 100644 docs/idp_policy.md rename PRD.md => docs/initial_PRD.md (100%) create mode 100644 docs/shadowing_policy.md delete mode 100644 docs/tenant_policy.md delete mode 100644 to-do.md diff --git a/README.md b/README.md index 99c2f8aa..7b6ba87f 100644 --- a/README.md +++ b/README.md @@ -5,27 +5,68 @@ ## ๐Ÿ— ์•„ํ‚คํ…์ฒ˜ (Architecture) -### 1. Frontend (Flutter Web) -- **Framework**: Flutter 3.32+ -- **Organization**: `kr.co.baroncs` -- **Key Packages**: `descope`, `flutter_riverpod`, `go_router` -- **Features**: - - ํƒญ ๊ธฐ๋ฐ˜ ๋กœ๊ทธ์ธ UI (์ด๋ฉ”์ผ / SMS) - - Descope SDK ์—ฐ๋™ (Enchanted Link) +### 0. Ory Stack +- Ory Kratos: ์‚ฌ์šฉ์ž ์ธ์ฆ/๊ณ„์ • ๊ด€๋ฆฌ(Identity). +- Kratos Selfservice UI: Kratos ์…€ํ”„์„œ๋น„์Šค ํ”Œ๋กœ์šฐ UI. +- Ory Hydra: OAuth2/OIDC ๋ฐœ๊ธ‰ ๋ฐ ํ† ํฐ ๊ด€๋ฆฌ. +- Ory Keto: ๊ถŒํ•œ/์ •์ฑ… ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์ œ์–ด. +- Oathkeeper: ์ธ์ฆ/์ธ๊ฐ€ ํ”„๋ก์‹œ ๋ฐ ๋ผ์šฐํŒ… ๊ฒŒ์ดํŠธ์›จ์ด. -### 2. Backend (Go Fiber) +### 1. Backend (Go Fiber) - **Language**: Go 1.25+ - **Framework**: Fiber v2.25+ - **Database**: - **ClickHouse**: ๊ฐ์‚ฌ ๋กœ๊ทธ (๊ณ ์„ฑ๋Šฅ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘) - **PostgreSQL**: ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ (Primary) - **Features**: + - ์ธ์ฆ์šฉ SMS ๋ฐœ์†ก ๋“ฑ Ory-Stack์œผ๋กœ ๊ตฌํ˜„ ์–ด๋ ค์šด ๋ถ€๋ถ„ ์ง์ ‘ ๊ตฌํ˜„ - `POST /api/v1/audit`: ๊ฐ์‚ฌ ๋กœ๊ทธ ์ˆ˜์ง‘ API + - User-Front๊ฐ€ ๋ฐ”๋ผ๋ณด๋Š” backend + +### 2. User-Front(Flutter Web/App) +- **Framework**: Flutter 3.32+ +- **Key Packages**: `flutter_riverpod`, `go_router` +- **Features**: + - ํƒญ ๊ธฐ๋ฐ˜ ๋กœ๊ทธ์ธ UI (๋น„๋ฐ€๋ฒˆํ˜ธ ๊ธฐ๋ฐ˜ / ๋งํฌ ๊ธฐ๋ฐ˜ / QR ๊ธฐ๋ฐ˜ ๋“ฑ) + +### 3. Admin-Front(Web) +- **Framework**: Vite, React 19+, Shadcn/ui ๋“ฑ +- **Features**: + - ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ, ๊ถŒํ•œ ๋ถ€์—ฌ ๋“ฑ ๊ด€๋ฆฌ์ž ๊ธฐ๋Šฅ + - ์•ฑ ๋ณ„ ์‚ฌ์šฉ๋Ÿ‰(ํ˜ธ์ถœ๋Ÿ‰) ๋“ฑ ํ†ต๊ณ„ + - ํ•ต์‹ฌ Audit ๋Œ€์ƒ + +### 4. Dev-Front(Web) - ํ–ฅํ›„ ๋ถ„๋ฆฌ ์˜ˆ์ • +- **Framework**: Vite, React 19+, Shadcn/ui ๋“ฑ +- **Features**: + - RP ๋“ฑ๋ก ๋ฐ ๊ด€๋ฆฌ + - RP๋ณ„ Consent ๊ด€๋ฆฌ + ### 4. ์ฃผ์š” ์‹œ๋‚˜๋ฆฌ์˜ค (Core Scenarios) -1. **Same Browser SSO**: Baron SSO์— ๋กœ๊ทธ์ธ๋œ ์ƒํƒœ์—์„œ ๋Ÿฐ์ฒ˜๋ฅผ ํ†ตํ•ด ํƒ€ ์•ฑ/์„œ๋น„์Šค๋กœ ์ด๋™ (์ž๋™ ๋กœ๊ทธ์ธ). -2. **Cross-Device Auth**: PC์—์„œ ๋กœ๊ทธ์ธ ์‹œ๋„ ์‹œ, ์ด๋ฏธ ๋กœ๊ทธ์ธ๋œ ๋ชจ๋ฐ”์ผ ์•ฑ์œผ๋กœ ์•Œ๋ฆผ์„ ๋ณด๋‚ด ์Šน์ธ (Enchanted Link ํ™œ์šฉ). -3. **Clean Login**: ์ตœ์ดˆ ์ง„์ž… ์‹œ ์ด๋ฉ”์ผ ๋˜๋Š” SMS๋ฅผ ํ†ตํ•œ ๋กœ๊ทธ์ธ (ํ–ฅํ›„ OTP, MFA ํ™•์žฅ ์˜ˆ์ •). +1. **Same Browser SSO**: Baron ํ†ตํ•ฉ๋กœ๊ทธ์ธ ์„œ๋น„์Šค์— ๋กœ๊ทธ์ธ๋œ ์ƒํƒœ์—์„œ ๋Ÿฐ์ฒ˜๋ฅผ ํ†ตํ•ด ํƒ€ ์•ฑ/์„œ๋น„์Šค๋กœ ์ด๋™ (์ž๋™ ๋กœ๊ทธ์ธ). + 1.1. ๋‹จ ์•ฝ๊ด€๋™์˜(Consent) ์ด๋ ฅ์ด ์—†์œผ๋ฉด Consent ๋‹จ๊ณ„๋กœ ์ด๋™ +2. **Cross-Device Auth**: ์ด๋ฉ”์ผ SMS ๋“ฑ์˜ ์ˆ˜๋‹จ์œผ๋กœ ๋งํฌ๋ฅผ ์ „๋‹ฌ๋ฐ›๊ณ  ํ•ด๋‹น ๋งํฌ๋ฅผ ์‚ฌ์šฉ์ž๊ฐ€ ํด๋ฆญํ•˜๋ฉด ์ตœ์ดˆ ๋กœ๊ทธ์ธ ์š”์ฒญํ•œ ์„ธ์…˜์ด ํ™œ์„ฑํ™” + 2.1 ํ–ฅํ›„ App Push ๋“ฑ 2์ฐจ ์ธ์ฆ ๊ฐ•ํ™”์ˆ˜๋‹จ ๊ฒ€ํ†  ํ•„์š” +3. **QR Login**: ์ตœ์ดˆ ์ง„์ž… ์‹œ ์‚ฌ์ „ ๋กœ๊ทธ์ธ๋˜์–ด ์žˆ๋Š” ์›น/์•ฑ์„ ์ด์šฉํ•ด QR ์ฝ”๋“œ๋ฅผ ์Šค์บ”ํ•˜์—ฌ, QR์ฝ”๋“œ๊ฐ€ ๋กœ๋”ฉ๋œ Device๋ฅผ ๋กœ๊ทธ์ธ ์ƒํƒœ๋กœ ์ „ํ™˜ + + +### ์ „์ฒด ์—ฐ๊ฒฐ ๊ตฌ์กฐ๋„ + +```mermaid +flowchart LR + AF[Admin Front] -->|"OIDC authorize/token (PKCE)"| HY["Hydra (OIDC ์—”์ง„)"] + DF[Dev Front] -->|"OIDC authorize/token (PKCE)"| HY + UF["User Front (Login/Consent UI)"] <-->|Hydra login/consent redirect| HY + UF -->|Kratos Browser Flow| KR["Kratos (SoT: identities/traits)"] + KR -->|subject=identity.id| HY + HY -->|ID/Access Token| RP[Relying Party Apps] + MG["Magic Link Wrapper (Fiber)"] -->|1ํšŒ์šฉ ํ† ํฐโ†’Kratos CreateSession| KR + MG -->|"Hydra Login Accept (์˜ต์…˜)"| HY + DS["Descope/Social IDP"] -->|Kratos Social/OIDC| KR +``` + +Kratos๊ฐ€ ์‚ฌ์šฉ์ž SoT์ด๋ฉฐ Hydra๋Š” ์ˆœ์ˆ˜ OIDC ํ† ํฐ ์—”์ง„์ž…๋‹ˆ๋‹ค. Magic Link๋Š” Fiber ๋ž˜ํผ๊ฐ€ Kratos ์„ธ์…˜์„ ๋งŒ๋“ค๊ณ  ํ•„์š” ์‹œ Hydra Login Accept๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. Descope ๋“ฑ ๋ณด์กฐ IDP๋Š” Kratos Social/OIDC provider๋กœ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. --- @@ -91,9 +132,13 @@ baron_sso/ โ”‚ โ”œโ”€โ”€ cmd/server/ # ์ง„์ž…์  (Entry point) โ”‚ โ”œโ”€โ”€ internal/ # ๋„๋ฉ”์ธ, ํ•ธ๋“ค๋Ÿฌ, ์ €์žฅ์†Œ(Repository) โ”‚ โ””โ”€โ”€ Dockerfile -โ”œโ”€โ”€ frontend/ # Flutter ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ -โ”‚ โ”œโ”€โ”€ lib/ # UI ๋ฐ ๋กœ์ง +โ”œโ”€โ”€ user-front/ # Flutter ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ +โ”‚ โ”œโ”€โ”€ src/ # UI ๋ฐ ๋กœ์ง โ”‚ โ””โ”€โ”€ pubspec.yaml +โ”œโ”€โ”€ admin-front/ # React ๊ธฐ๋ฐ˜ ๊ด€๋ฆฌ +โ”‚ โ”œโ”€โ”€ src/ # UI ๋ฐ ๋กœ์ง +โ”‚ โ””โ”€โ”€ pubspec.yaml +โ”œโ”€โ”€ compose.ory-stack.yaml # DB ์„œ๋น„์Šค (Postgres, ClickHouse) โ”œโ”€โ”€ compose.infra.yaml # DB ์„œ๋น„์Šค (Postgres, ClickHouse) โ”œโ”€โ”€ docker-compose.yaml # ์•ฑ ์„œ๋น„์Šค (Front, Back) โ”œโ”€โ”€ .env.sample # ํ™˜๊ฒฝ ์„ค์ • ํ…œํ”Œ๋ฆฟ @@ -102,7 +147,7 @@ baron_sso/ ## ๐Ÿ“ ์ƒํƒœ ๋ฐ ๋กœ๋“œ๋งต (Status & Roadmap) - [x] **Phase 1**: ์ดˆ๊ธฐ ์„ค์ • ๋ฐ ์•„ํ‚คํ…์ฒ˜ ์„ค๊ณ„ (์™„๋ฃŒ) -- [x] **Phase 2**: Backend Audit API ๊ตฌํ˜„ (์™„๋ฃŒ) -- [x] **Phase 3**: Frontend ๋กœ๊ทธ์ธ UI ๋ฐ Descope ์ธ์ฆ ๋กœ์ง (์™„๋ฃŒ) -- [ ] **Phase 4**: Frontend - Backend ์—ฐ๋™ (Audit ์ „์†ก) (์˜ˆ์ •) +- [x] **Phase 2**: Backend Audit API ๊ตฌํ˜„ (์ผ๋ถ€ ์™„๋ฃŒ) +- [x] **Phase 3**: User Front ๋กœ๊ทธ์ธ UI ์ธ์ฆ ๋กœ์ง (์™„๋ฃŒ) +- [ ] **Phase 4**: Admin Front ๊ธฐ๋Šฅ ์ถ”๊ฐ€ (์˜ˆ์ •) - [ ] **Phase 5**: ๋Œ€์‹œ๋ณด๋“œ ๋ฐ ํ†ตํ•ฉ ๋Ÿฐ์ฒ˜ ๊ตฌํ˜„ (์˜ˆ์ •) diff --git a/AGENTS.md b/docs/AGENTS.md similarity index 100% rename from AGENTS.md rename to docs/AGENTS.md diff --git a/Gemini.md b/docs/Gemini.md similarity index 100% rename from Gemini.md rename to docs/Gemini.md diff --git a/docs/idp_policy.md b/docs/idp_policy.md new file mode 100644 index 00000000..71544392 --- /dev/null +++ b/docs/idp_policy.md @@ -0,0 +1,27 @@ +# IDP Abstraction & Perfect Wrapping Policy + +## 1. ํ•ต์‹ฌ ์›์น™ (Core Principles) + +**"์‚ฌ์šฉ์ž์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐœ๋ฐœ์ž๋Š” IDP๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ ์ˆ˜๋„ ์—†๊ณ , ์•Œ์•„์„œ๋„ ์•ˆ ๋œ๋‹ค."** + +Baron SSO์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์•„ํ‚คํ…์ฒ˜ ์›์น™์€ **IDP Agnostic(IDP ๋ถˆ๊ฐ€์ง€๋ก )**์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ Descope๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„, ๋‚ด์ผ ๋‹น์žฅ Hydra, Authentik, Keycloak ๋˜๋Š” ์ž์ฒด ๊ตฌ์ถ• ์ธ์ฆ ์„œ๋ฒ„๋กœ ๋ณ€๊ฒฝํ•˜๋”๋ผ๋„ **Frontend, Client App, ๊ทธ๋ฆฌ๊ณ  ์ตœ์ข… ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” ๋‹จ 1์ค„์˜ ์ฝ”๋“œ ๋ณ€๊ฒฝ์ด๋‚˜ ๊ฒฝํ—˜์˜ ๋ณ€ํ™”๊ฐ€ ์—†์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.** + +## 2. ์„ธ๋ถ€ ์ง€์นจ (Guidelines) + +### 2.1. Frontend & Client Side +- **No Vendor SDK**: ํ”„๋ก ํŠธ์—”๋“œ ์ฝ”๋“œ(User App, Admin Front)์—์„œ `descope-sdk` ๋“ฑ ํŠน์ • ๋ฒค๋”์˜ SDK๋ฅผ ์ง์ ‘ importํ•˜์—ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ธˆ์ง€ํ•ฉ๋‹ˆ๋‹ค. +- **Unified Interface**: ๋ชจ๋“  ์ธ์ฆ ์š”์ฒญ์€ Baron SSO Backend API (`/api/v1/auth/*`)๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. +- **Response Format**: ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ˆ˜์‹ ํ•˜๋Š” ํ† ํฐ ๋ฐ ์‚ฌ์šฉ์ž ์ •๋ณด๋Š” Baron SSO๊ฐ€ ์ •์˜ํ•œ ํ‘œ์ค€ ์Šคํ‚ค๋งˆ(`BrokerUser`)์—ฌ์•ผ ํ•˜๋ฉฐ, IDP์˜ Raw Data๊ฐ€ ๋…ธ์ถœ๋˜์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. + +### 2.2. Backend Side +- **Provider Pattern**: ๋ชจ๋“  IDP ๊ด€๋ จ ๋กœ์ง์€ `interface IDPProvider` ๋’ค์— ์ˆจ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•ธ๋“ค๋Ÿฌ(Handler) ๊ณ„์ธต์€ ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„์ฒด(DescopeService ๋“ฑ)๋ฅผ ์•Œ์ง€ ๋ชปํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. +- **Error Mapping**: IDP์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ(์˜ˆ: `E062907`)๋Š” ๋ฐ˜๋“œ์‹œ Baron SSO์˜ ํ‘œ์ค€ ์—๋Ÿฌ(์˜ˆ: `AUTH_PROVIDER_ERROR`)๋กœ ๋ณ€ํ™˜๋˜์–ด ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. +- **Configuration Isolation**: IDP ์„ค์ •(Project ID, API Key)์€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜์™€ ํŒฉํ† ๋ฆฌ ๋‚ด๋ถ€๋กœ ๊ฒฉ๋ฆฌํ•˜๋ฉฐ, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + +### 2.3. OIDC/OAuth2 Compliance +- ์™ธ๋ถ€ ์„œ๋น„์Šค(RP) ์—ฐ๋™ ์‹œ, Baron SSO ์ž์ฒด๊ฐ€ OIDC Provider๋กœ ๋™์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. +- RP๋Š” `Issuer`๋ฅผ Baron SSO์˜ URL๋กœ ์„ค์ •ํ•˜๋ฉฐ, ์›์ฒœ IDP์˜ URL์„ ๋ฐ”๋ผ๋ณด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + +## 3. ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ณด์žฅ (Migration Guarantee) +์ด ์ •์ฑ…์˜ ์ตœ์ข… ๋ชฉํ‘œ๋Š” **"IDP ๊ต์ฒด ๋น„์šฉ์„ 0์— ์ˆ˜๋ ดํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ"**์ž…๋‹ˆ๋‹ค. +IDP ๋ณ€๊ฒฝ ์‹œ ๋ฐฑ์—”๋“œ์˜ `IDPProvider` ๊ตฌํ˜„์ฒด๋งŒ ๊ต์ฒดํ•˜๋ฉด, ๋ฐ์ดํ„ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์ œ์™ธํ•œ ๋ชจ๋“  ์„œ๋น„์Šค๊ฐ€ ์ค‘๋‹จ ์—†์ด ๋™์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/PRD.md b/docs/initial_PRD.md similarity index 100% rename from PRD.md rename to docs/initial_PRD.md diff --git a/docs/shadowing_policy.md b/docs/shadowing_policy.md new file mode 100644 index 00000000..4922cbe1 --- /dev/null +++ b/docs/shadowing_policy.md @@ -0,0 +1,64 @@ +# Shadow Account Policy (Identity Sovereignty) + +## 1. ๊ฐœ์š” (Overview) +Baron SSO๋Š” ์™ธ๋ถ€ IDP(Descope ๋“ฑ)์— ์˜์กดํ•˜์ง€ ์•Š๊ณ , **์‹๋ณ„์ž ์ฃผ๊ถŒ(Identity Sovereignty)**์„ ๊ฐ–๊ธฐ ์œ„ํ•ด **Shadow Account (๊ทธ๋ฆผ์ž ๊ณ„์ •)** ๋ชจ๋ธ์„ ์ฑ„ํƒํ•ฉ๋‹ˆ๋‹ค. +์™ธ๋ถ€ IDP๋Š” ๋‹จ์ง€ "์ธ์ฆ ์ˆ˜๋‹จ"์ผ ๋ฟ์ด๋ฉฐ, ์„œ๋น„์Šค ๋‚ด๋ถ€์˜ ๋ชจ๋“  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง, ๋กœ๊ทธ, RP ์—ฐ๋™์€ Baron SSO๊ฐ€ ๋ฐœ๊ธ‰ํ•œ ๊ณ ์œ  ์‹๋ณ„์ž(`Baron ID`)๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. + +## 2. ์‹๋ณ„์ž ์ •์ฑ… (Identifier Policy) + +### 2.1. Baron ID (Internal User ID) +- **Format**: **UUID v7** (Time-ordered 128-bit) +- **ํŠน์ง•**: ์ƒ์„ฑ ์‹œ๊ฐ„ ์ˆœ ์ •๋ ฌ ๊ฐ€๋Šฅ, DB ์ธ๋ฑ์‹ฑ ํšจ์œจ ์ตœ์ ํ™”, ์™ธ๋ถ€ ์‹œ์Šคํ…œ ์ถฉ๋Œ ์—†์Œ. +- **์šฉ๋„**: `users` ํ…Œ์ด๋ธ” PK, `audit_logs`์˜ Actor ID, RP์— ์ „๋‹ฌ๋˜๋Š” `sub` ๊ฐ’. +- **์›์น™**: **๋ถˆ๋ณ€(Immutable)**. ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฉ”์ผ์ด๋‚˜ ์—ฐ๋™ IDP๋ฅผ ๋ณ€๊ฒฝํ•ด๋„ Baron ID๋Š” ๋ณ€ํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +### 2.2. Audit Log ID +- **Format**: **Snowflake** (64-bit Integer) +- **์šฉ๋„**: ๊ฐ์‚ฌ ๋กœ๊ทธ์˜ Primary Key. +- **์ด์œ **: ์ดˆ๋‹น ๋Œ€๋Ÿ‰์œผ๋กœ ๋ฐœ์ƒํ•˜๋Š” ๋กœ๊ทธ ๋ฐ์ดํ„ฐ์˜ ์ ์žฌ ์„ฑ๋Šฅ๊ณผ ClickHouse ์••์ถ• ํšจ์œจ์„ ์œ„ํ•ด ์ •์ˆ˜ํ˜• ID ์‚ฌ์šฉ. + +## 3. ๋ฐ์ดํ„ฐ ๋ชจ๋ธ (Shadow Schema) + +### 3.1. Users Table (Core) +์„œ๋น„์Šค๊ฐ€ ๋ฐ”๋ผ๋ณด๋Š” ์‚ฌ์šฉ์ž์˜ ์‹ค์ฒด์ž…๋‹ˆ๋‹ค. +```sql +CREATE TABLE users ( + id UUID PRIMARY KEY, -- Baron ID (UUID v7) + email VARCHAR(255), -- ๊ฒ€์ƒ‰ ๋ฐ ์•Œ๋ฆผ์šฉ (Unique X, ์—ฌ๋Ÿฌ ๊ณ„์ • ๊ฐ€๋Šฅ์„ฑ) + name VARCHAR(100), + status VARCHAR(20), -- 'active', 'blocked' + created_at TIMESTAMPTZ, + last_login_at TIMESTAMPTZ +); +``` + +### 3.2. Federated Identities Table (Mapping) +์™ธ๋ถ€ IDP ๊ณ„์ •๊ณผ Baron ๊ณ„์ •์„ ์—ฐ๊ฒฐํ•˜๋Š” ๋งคํ•‘ ํ…Œ์ด๋ธ”์ž…๋‹ˆ๋‹ค. N:1 ๋งคํ•‘์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. +```sql +CREATE TABLE federated_identities ( + provider VARCHAR(50), -- 'descope', 'google', 'legacy_db' + provider_sub VARCHAR(255), -- IDP์˜ ์›์ฒœ User ID + user_id UUID REFERENCES users(id), + created_at TIMESTAMPTZ, + PRIMARY KEY (provider, provider_sub) +); +``` + +## 4. ๋™๊ธฐํ™” ๋ฐ ๋กœ๊ทธ์ธ ํ๋ฆ„ (Sync Flow) + +1. **์ธ์ฆ ์„ฑ๊ณต**: ๋ฐฑ์—”๋“œ๊ฐ€ IDP(Descope) ํ† ํฐ์„ ๊ฒ€์ฆํ•˜๊ณ  `Provider Sub`(์˜ˆ: `U12345`)๋ฅผ ํš๋“. +2. **์กฐํšŒ (Lookup)**: `federated_identities` ํ…Œ์ด๋ธ”์—์„œ `(provider='descope', provider_sub='U12345')` ์กฐํšŒ. +3. **๋ถ„๊ธฐ ์ฒ˜๋ฆฌ**: + - **Case A (๊ธฐ์กด ํšŒ์›)**: ๋งคํ•‘๋œ `user_id` ํš๋“. `users` ํ…Œ์ด๋ธ”์˜ ์ •๋ณด(์ด๋ฉ”์ผ, ์ด๋ฆ„)๋ฅผ IDP ํ† ํฐ ์ •๋ณด๋กœ **์—…๋ฐ์ดํŠธ(Sync)**. + - **Case B (์‹ ๊ทœ ํšŒ์›)**: ์ƒˆ๋กœ์šด `UUID v7` ์ƒ์„ฑ -> `users` Insert -> `federated_identities` Insert. +4. **์„ธ์…˜ ๋ฐœ๊ธ‰**: Baron ID(`user_id`)๋ฅผ Payload๋กœ ๋‹ด์€ Baron ์ž์ฒด ์„ธ์…˜/ํ† ํฐ์„ ๋ฐœ๊ธ‰ํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌ. + +## 5. IDP ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ „๋žต (Migration Strategy) + +### 5.1. ์‹๋ณ„์ž ์œ ์ง€ +IDP๊ฐ€ `Descope`์—์„œ `Keycloak`์œผ๋กœ ๋ฐ”๋€Œ๋”๋ผ๋„, ๋ฐฑ์—”๋“œ๋Š” ์ƒˆ๋กœ์šด IDP์˜ `sub`๋ฅผ ๊ธฐ์กด ์‚ฌ์šฉ์ž์˜ `Baron ID`์™€ ๋งคํ•‘(`federated_identities` ์ถ”๊ฐ€)ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. RP์™€ ํด๋ผ์ด์–ธํŠธ๋Š” ์•„๋ฌด๋Ÿฐ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. + +### 5.2. ๋น„๋ฐ€๋ฒˆํ˜ธ ์ฒ˜๋ฆฌ (Password Handling) +- ํ•ด์‹œ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ์ด๊ด€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค (๋ถˆ๊ฐ€๋Šฅ/๋น„ํšจ์œจ). +- **Magic Link / Passwordless ์šฐ์„ **: ์‚ฌ์šฉ์ž๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ์—†์ด ๊ณ„์† ์ด์šฉ ๊ฐ€๋Šฅ. +- **์žฌ์„ค์ • ์œ ๋„**: ๋น„๋ฐ€๋ฒˆํ˜ธ ์‚ฌ์šฉ ํ•„์ˆ˜ ์‹œ, "๋ณด์•ˆ ์ •์ฑ… ๋ณ€๊ฒฝ" ์•ˆ๋‚ด์™€ ํ•จ๊ป˜ ๋ฆฌ์…‹ ๋งํฌ ๋ฐœ์†ก. diff --git a/docs/tenant_policy.md b/docs/tenant_policy.md deleted file mode 100644 index 08cff53a..00000000 --- a/docs/tenant_policy.md +++ /dev/null @@ -1,61 +0,0 @@ -# Tenant ์ •์ฑ… (Tenant Policy) - -## 1. ๊ฐœ์š” (Overview) -Baron SSO๋Š” **Multi-Tenancy**๋ฅผ ์ง€์›ํ•˜์—ฌ, ๋‹จ์ผ ์ธ์Šคํ„ด์Šค์—์„œ ์—ฌ๋Ÿฌ ์กฐ์ง(Tenant)์˜ ๋ฐ์ดํ„ฐ์™€ ์‚ฌ์šฉ์ž๋ฅผ ๊ฒฉ๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ฌธ์„œ๋Š” ํ…Œ๋„ŒํŠธ์˜ ๊ณ„์ธต ๊ตฌ์กฐ, ๋ฆฌ์†Œ์Šค ์†Œ์œ ๊ถŒ, ๋ฐ์ดํ„ฐ ๋ชจ๋ธ๋ง ๋ฐ ๋ณด์•ˆ ์ •์ฑ…์„ ์ •์˜ํ•œ๋‹ค. - ---- - -## 2. ๊ณ„์ธต ๊ตฌ์กฐ ๋ฐ ์ œ์•ฝ (Hierarchy & Constraints) - -### 2.1 ๊ณ„์ธต ์ œํ•œ (Depth Limit) -๋ณต์žก์„ฑ์„ ํ†ต์ œํ•˜๊ธฐ ์œ„ํ•ด ํ…Œ๋„ŒํŠธ ๊ณ„์ธต์€ **์ตœ๋Œ€ 2 Depth (1๋‹จ๊ณ„ ๊นŠ์ด)**๊นŒ์ง€๋งŒ ํ—ˆ์šฉํ•œ๋‹ค. -* **Root Tenant (Level 1)**: ์ตœ์ƒ์œ„ ์กฐ์ง (์˜ˆ: ๋ณธ์‚ฌ, ๊ณ ๊ฐ์‚ฌ A) -* **Sub Tenant (Level 2)**: ํ•˜์œ„ ์กฐ์ง (์˜ˆ: ์ธ์‚ฌํŒ€, ์ง€์‚ฌ B) -* **์ œ์•ฝ**: Sub Tenant ๋ฐ‘์— ๋˜ ๋‹ค๋ฅธ Tenant๋ฅผ ๋‘˜ ์ˆ˜ ์—†๋‹ค. - -### 2.2 ๋ฆฌ์†Œ์Šค ์†Œ์œ ๊ถŒ (Resource Ownership) -* **Root Tenant Only**: - * **Relying Party (Client App)**, **IDP ์„ค์ •** ๋“ฑ ์‹œ์Šคํ…œ์˜ ํ•ต์‹ฌ ๋ฆฌ์†Œ์Šค๋Š” **์˜ค์ง Root Tenant๋งŒ ์ƒ์„ฑํ•˜๊ณ  ์†Œ์œ **ํ•  ์ˆ˜ ์žˆ๋‹ค. - * ๋ชจ๋“  ์ •์ฑ…(Policy) ๊ฒฐ์ • ๊ถŒํ•œ์€ Root Tenant์—๊ฒŒ ์žˆ๋‹ค. -* **Sub Tenant**: - * ๋…์ž์ ์ธ RP๋‚˜ IDP ์„ค์ •์„ ๊ฐ€์งˆ ์ˆ˜ **์—†๋‹ค**. - * Root Tenant๊ฐ€ ์„ค์ •ํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณต์œ ํ•˜๋ฉฐ, ๋‹จ์ˆœํžˆ ์‚ฌ์šฉ์ž๋ฅผ ๊ทธ๋ฃนํ•‘ํ•˜๊ฑฐ๋‚˜ ์กฐ์ง ๋‹จ์œ„(Organizational Unit)๋กœ ๊ด€๋ฆฌํ•˜๋Š” ์—ญํ• ๋งŒ ์ˆ˜ํ–‰ํ•œ๋‹ค. - ---- - -## 3. ๋ฐ์ดํ„ฐ ๋ชจ๋ธ (Data Model) - -### 3.1 ์‚ฌ์šฉ์ž ๊ด€๊ณ„ (User Membership) -์‚ฌ์šฉ์ž๋Š” **๋‹จ์ผ ๊ณ„์ •(User ID)์œผ๋กœ ์—ฌ๋Ÿฌ Tenant์— ๋™์‹œ์— ์†Œ์†(N:M ๊ด€๊ณ„)**๋  ์ˆ˜ ์žˆ๋‹ค. -* **`users` ํ…Œ์ด๋ธ”**: ์‚ฌ์šฉ์ž์˜ ๊ณ ์œ  ์‹๋ณ„์ž ๋ฐ ์ „์—ญ ์†์„ฑ(Email, Name, Phone)๋งŒ ์ €์žฅ. -* **`tenants` ํ…Œ์ด๋ธ”**: ํ…Œ๋„ŒํŠธ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ (`id`, `parent_id`, `name` ๋“ฑ). `parent_id`๊ฐ€ NULL์ด๋ฉด Root Tenant์ด๋‹ค. -* **`user_tenants` ํ…Œ์ด๋ธ” (Membership)**: `user_id`์™€ `tenant_id`๋ฅผ ๋งคํ•‘ํ•˜๋ฉฐ, ํ•ด๋‹น ํ…Œ๋„ŒํŠธ ๋‚ด์—์„œ์˜ `roles`(๊ถŒํ•œ) ์ •๋ณด๋ฅผ ์ €์žฅํ•œ๋‹ค. - -### 3.2 ID ์‹๋ณ„ ๋ฐ ๋งคํ•‘ (Identification) -* **Internal Tenant ID**: ์‹œ์Šคํ…œ ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ํ•ญ์ƒ **UUID** ๊ธฐ๋ฐ˜์˜ ๊ณ ์œ  ์‹๋ณ„์ž๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. -* **External Mapping**: Descope, Ory Hydra ๋“ฑ ์™ธ๋ถ€ IDP์˜ Tenant ID ํ˜•์‹์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, `provider_mappings` ์ปฌ๋Ÿผ(๋˜๋Š” ํ…Œ์ด๋ธ”)์„ ํ†ตํ•ด ์™ธ๋ถ€ ID์™€ ๋‚ด๋ถ€ UUID๋ฅผ ๋งคํ•‘ํ•œ๋‹ค. - ---- - -## 4. ์ธ์ฆ ๋ฐ ์ธ๊ฐ€ (Authentication & Authorization) - -### 4.1 Active Tenant Context -์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ Tenant์— ์†ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๋ชจ๋“  API ์š”์ฒญ์€ **"ํ˜„์žฌ ์–ด๋–ค Tenant ๋ฌธ๋งฅ์—์„œ ์ž‘์—… ์ค‘์ธ๊ฐ€"**๋ฅผ ๋ช…ํ™•ํžˆ ํ•ด์•ผ ํ•œ๋‹ค. -* **Header**: `X-Tenant-ID` (ํ•„์ˆ˜) -* **Middleware ๊ฒ€์ฆ ๋กœ์ง**: - 1. ์š”์ฒญ ํ—ค๋”์—์„œ `TargetTenantID`๋ฅผ ์ถ”์ถœํ•œ๋‹ค. - 2. User์˜ JWT Claims(๋˜๋Š” DB)๋ฅผ ํ™•์ธํ•˜์—ฌ, ์‚ฌ์šฉ์ž๊ฐ€ `TargetTenantID`์— ์†Œ์†๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. - 3. ํ•ด๋‹น Tenant์—์„œ์˜ Role(์˜ˆ: Tenant Admin)์ด ์š”์ฒญํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ๊ฒ€์ฆํ•œ๋‹ค. - ---- - -## 5. ๋ณด์•ˆ ๋ฐ ๊ฐ์‚ฌ (Security & Audit) - -### 5.1 Audit Log ์ •์ฑ… -`X-Tenant-ID` ํ—ค๋”์˜ ์กด์žฌ ์—ฌ๋ถ€์™€ ๊ด€๊ณ„์—†์ด, **๋ชจ๋“  ๋ณด์•ˆ ์ด๋ฒคํŠธ๋Š” ๋ฐ˜๋“œ์‹œ ๊ธฐ๋ก**๋˜์–ด์•ผ ํ•œ๋‹ค. -* **Tenant Context ์กด์žฌ ์‹œ**: ํ•ด๋‹น `tenant_id`์™€ ํ•จ๊ป˜ ๋กœ๊ทธ ์ €์žฅ. -* **Tenant Context ๋ถ€์žฌ ์‹œ** (์˜ˆ: ๋กœ๊ทธ์ธ ์งํ›„, ํ”„๋กœํ•„ ์ˆ˜์ •, ๋‚ด ํ…Œ๋„ŒํŠธ ๋ชฉ๋ก ์กฐํšŒ): `tenant_id`๋ฅผ `NULL` ๋˜๋Š” ์˜ˆ์•ฝ์–ด(`system`, `personal`)๋กœ ์ €์žฅ. - -### 5.2 API ์ ‘๊ทผ ์ œ์–ด ์ •์ฑ… -* **Tenant-Scoped API** (์˜ˆ: RP ์ƒ์„ฑ, ๋ฉค๋ฒ„ ์ดˆ๋Œ€): ํ—ค๋” ๋ˆ„๋ฝ ์‹œ **400 Bad Request** ๊ฑฐ์ ˆ. -* **User/Global API** (์˜ˆ: ๋‚ด ์ •๋ณด ์ˆ˜์ •): ํ—ค๋” ๋ˆ„๋ฝ ํ—ˆ์šฉ (Global Context). diff --git a/to-do.md b/to-do.md deleted file mode 100644 index e8d6f769..00000000 --- a/to-do.md +++ /dev/null @@ -1,27 +0,0 @@ -# Baron SSO ์ž‘์—… ๋ชฉ๋ก (To-Do) - -## 1. ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ (Go Fiber) -- [x] Go ๋ชจ๋“ˆ ์ดˆ๊ธฐํ™” -- [x] Fiber ์•„ํ‚คํ…์ฒ˜ (Clean Arch) ๊ตฌ์„ฑ -- [x] Audit Log DB ๊ตฌ์ถ• (PostgreSQL + ClickHouse) -- [x] ํ”„๋ก ํŠธ์—”๋“œ ์—ฐ๋™์šฉ API ์ƒ์„ฑ (`POST /api/v1/audit`) - -## 2. Descope ์—ฐ๋™ ์ „๋žต -- [x] Ncloud SMS ์ปค๋„ฅํ„ฐ ์„ค์ • (Descope Console) -- [x] Audit Log Webhook/API ์„ค๊ณ„ - -## 3. ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ (Flutter Web PoC) -- [x] Flutter ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐํ™” -- [x] ๋กœ๊ทธ์ธ UI ๊ตฌํ˜„ (ํƒญ: ์ด๋ฉ”์ผ/๋น„๋ฒˆ & SMS) -- [x] Enchanted Link ํ•ธ๋“ค๋ง ๋กœ์ง ๊ตฌํ˜„ (Cross-Device Auth ์ง€์›) -- [ ] ๋Œ€์‹œ๋ณด๋“œ ๊ตฌํ˜„ (์„ธ์…˜ ๋ฆฌ์ŠคํŠธ) -- [ ] ํ†ตํ•ฉ ๋Ÿฐ์ฒ˜ UI ๊ตฌํ˜„ (Same Browser SSO) -- [ ] ๊ด€๋ฆฌ์ž ๋ชจ๋“œ (Descope ๊ด€๋ฆฌ ๊ธฐ๋Šฅ) - -## 4. ๊ฒ€์ฆ (Verification) -- [ ] End-to-End ๋กœ๊ทธ์ธ ํ๋ฆ„ ํ…Œ์ŠคํŠธ -- [ ] Audit Log ์ €์žฅ ํ™•์ธ - -## 5. ํ–ฅํ›„ ๋งˆ์ผ์Šคํ†ค (Milestones) -- [ ] Passkey ์ง€์› (Scenario 2, 3) -- [ ] ์‹ฌํ™” MFA (OTP ๋“ฑ) ํ™•์žฅ