1
0
forked from baron/baron-sso

조직도 M2M조회 추가, 자동로그인 보완

This commit is contained in:
2026-05-13 13:44:30 +09:00
parent 72288f1d39
commit 8c2b2f71ef
29 changed files with 2985 additions and 81 deletions

View File

@@ -99,7 +99,7 @@ Tenant/RP 단위로 묶어서 전달한다.
{
"tenant_profiles": [
{
"tenant_id": "tenant-uuid",
"tenant_id": "01970f0a-5c28-74d8-a73a-f6e9e9a7b210",
"tenant_slug": "hanmac-family",
"fields": {
"employeeNo": "E1001"
@@ -119,3 +119,123 @@ Tenant/RP 단위로 묶어서 전달한다.
- `claimEnabled=true` field만 RP claim 후보로 포함한다.
- 긴 JSON 값은 기본적으로 token claim보다 userinfo/profile API 응답에 싣는 방향을 우선한다.
## 한맥가족 Tenant Claim Projection
한맥가족(`hanmac-family`) subtree의 tenant claim은 기본 claim과 상세 claim으로 나눈다. 기본 claim은 대표소속 tenant UUID인 `tenant_id`와 전체 소속 목록인 `joined_tenants`이며, RP가 `tenant` claim을 요청하면 tenant별 map 안에 조직 소속 정보를 묶어서 전달한다. 이 정보는 RP가 tenant context를 표시하거나 조직별 기본값을 선택하기 위한 projection이며, 관계형 데이터의 SoT는 PostgreSQL Business DB와 사용자 metadata이다.
기본 claim 예시는 다음과 같다.
```json
{
"tenant_id": "01970f0a-5c28-74d8-a73a-f6e9e9a7b210",
"joined_tenants": [
"01970f0a-5c28-74d8-a73a-f6e9e9a7b210",
"01970f0b-3448-7bb8-bdc7-16b6a1d2e661"
]
}
```
Issue #775 구현 결과 기준으로 RP가 `tenant` claim을 요청했을 때 받는 대표 예시는 다음과 같다.
```json
{
"email": "hanmac-user@example.com",
"name": "한맥 사용자",
"tenant_id": "01970f0a-5c28-74d8-a73a-f6e9e9a7b210",
"joined_tenants": [
"01970f0a-5c28-74d8-a73a-f6e9e9a7b210",
"01970f0b-3448-7bb8-bdc7-16b6a1d2e661"
],
"lead_tenants": [
"01970f0a-5c28-74d8-a73a-f6e9e9a7b210"
],
"tenants": {
"01970f0a-5c28-74d8-a73a-f6e9e9a7b210": {
"id": "01970f0a-5c28-74d8-a73a-f6e9e9a7b210",
"slug": "tech-planning",
"name": "기술기획팀",
"type": "USER_GROUP",
"lead": true,
"representative": true,
"isPrimary": true,
"grade": "책임",
"jobTitle": "기술기획",
"position": "팀장",
"parentTenantId": "01970f08-91da-7286-bd19-882fb98d1f2c",
"ancestors": [
{
"id": "01970f08-91da-7286-bd19-882fb98d1f2c",
"slug": "hanmac",
"name": "한맥기술",
"type": "COMPANY",
"parentTenantId": "01970f07-4f01-7d9a-a71e-b53ad508f345"
},
{
"id": "01970f07-4f01-7d9a-a71e-b53ad508f345",
"slug": "hanmac-family",
"name": "한맥가족",
"type": "COMPANY_GROUP",
"parentTenantId": null
}
]
},
"01970f0b-3448-7bb8-bdc7-16b6a1d2e661": {
"id": "01970f0b-3448-7bb8-bdc7-16b6a1d2e661",
"slug": "quality",
"name": "품질관리팀",
"type": "USER_GROUP",
"lead": false,
"representative": false,
"isPrimary": false,
"grade": "선임",
"jobTitle": "품질관리",
"position": "파트원",
"parentTenantId": "01970f08-91da-7286-bd19-882fb98d1f2c",
"ancestors": [
{
"id": "01970f08-91da-7286-bd19-882fb98d1f2c",
"slug": "hanmac",
"name": "한맥기술",
"type": "COMPANY",
"parentTenantId": "01970f07-4f01-7d9a-a71e-b53ad508f345"
},
{
"id": "01970f07-4f01-7d9a-a71e-b53ad508f345",
"slug": "hanmac-family",
"name": "한맥가족",
"type": "COMPANY_GROUP",
"parentTenantId": null
}
]
}
},
"profile": {
"emails": [
"hanmac-user@example.com"
],
"names": {
"name": "한맥 사용자"
}
}
}
```
- 예시의 `id` 값은 UUID 형식의 샘플이며, `slug`와 다르다.
- `tenant_id``joined_tenants`는 기본 claim이다.
- `tenant_id`는 사용자의 대표소속 tenant UUID이다. RP/client context tenant가 없더라도 공백으로 내려가지 않는다.
- `joined_tenants`는 사용자가 claim 상에서 소속된 모든 tenant UUID 목록이다.
- `lead_tenants``tenant` claim 요청 시 포함되며, `lead=true`인 tenant UUID 목록이다.
- `lead`는 tenant lead/조직장 역할을 나타낸다. 입력 metadata에서는 `lead`, `isLead`, `isOwner`, `isManager`를 허용한다.
- `representative``isPrimary`는 대표조직 여부를 나타낸다. 입력 metadata에서는 `representative`, `isPrimary`, `primary`를 허용한다.
- `grade`, `jobTitle`, `position`은 각각 직급, 직무, 직책이다.
- `parentTenantId`는 현재 tenant의 직속 parent tenant UUID이다. 최상위 root는 `null`이다.
- `ancestors`는 직속 상위 tenant부터 `hanmac-family` root까지의 parent chain이다.
- 기본 tenant와 각 ancestor 객체는 `parentTenantId`를 포함하므로, parent edge를 별도 추론 없이 그릴 수 있다.
- 대표소속 결정은 명시적 `tenant_id`, `additionalAppointments``representative/isPrimary/primary=true`, 가장 먼저 등록된 소속 순서로 적용한다.
- 생성 시 소속 tenant가 하나도 없으면 PERSONAL tenant를 자동 생성하고, 해당 tenant를 `tenant_id``joined_tenants`에 포함한다.
- RP/client tenant context는 대표소속 `tenant_id`를 덮어쓰지 않는다.
- tenant별 namespaced traits map이 없어도 `tenant_id` 또는 `additionalAppointments[].tenantId`를 기준으로 projection 항목을 만들 수 있다.
- 멀티 소속이면 기본 claim의 `joined_tenants`에 모든 소속 tenant를 넣는다. `tenant` claim 요청 시에는 `tenants`에도 모든 소속 tenant 상세를 넣고, `lead_tenants`에는 lead tenant만 넣는다.
- token 크기 보호를 위해 전체 조직도나 긴 custom JSON은 claim에 싣지 않고 profile/userinfo API 또는 backend API 응답으로 분리한다.
- RP는 `joined_tenants`로 전체 소속을 읽고, `lead_tenants`로 lead tenant를 빠르게 식별한다. 상세 표시는 `tenants[tenant_id]` 또는 `tenants[joined_tenants[n]]``ancestors`를 조합한다.