Stabilize auth flow and profile images

This commit is contained in:
Codex
2026-07-20 13:38:39 +09:00
parent 57caca8dc8
commit 5d3eee7a16
128 changed files with 28860 additions and 1468 deletions
@@ -0,0 +1,234 @@
# tdc114plus org-context 응답 매핑 판단서
작성일: 2026-07-08
상태: v1.0
목적: Baron Swagger의 `GET /api/v1/integrations/org-context` 설명과 예시 응답을 기준으로, 현재 `tdc114plus` 앱 화면 요소에 어떤 필드를 직접 매핑할 수 있는지와 어떤 부분은 추가 가공이 필요한지 판단한다.
관련 문서:
- `docs/00_contract_tdc114plus_api_2026-07-02.md`
- `docs/00_guide_tdc114plus_external_api_usage_2026-07-03.md`
- `docs/00_policy_tdc114plus_screen_feature_2026-07-07.md`
## 1. 결론
- `org-context`는 현재 기준으로 `조직도/직원 데이터 원형 API`로 매우 유력하다.
- 특히 `tenantSlug` 기준 subtree, `tree`, `tenants`, `members` 구조는 `전체 > 회사 > 하위조직 > 개인` 탐색 정책과 잘 맞는다.
- 다만 이 API는 `Integrations` 영역이며 `API Key`가 필요하므로, 모바일 앱이 운영 Key를 직접 넣고 호출하는 구조는 기본안으로 채택하면 안 된다.
- 따라서 `데이터 구조 기준 API`로는 채택 가능하지만, `실기기 앱 직접 호출 방식`은 보안 검토가 끝나기 전까지 확정하지 않는다.
## 2. Swagger에서 확인된 사실
대상 API:
```http
GET /api/v1/integrations/org-context
```
특징:
- 계정 세션 없이 `API Key`로 조회
- `tenantSlug`가 없으면 기본 `hanmac-family` subtree 반환
- `includeUsers=false`이면 tenant members는 빈 배열
- `includeUserIds=true`이면 `members[].id`, `members[].phone` 추가
주요 응답 구조:
- `scope.tenantId`
- `scope.tenantSlug`
- `tree`
- `tenants[]`
- `tenant.members[]`
즉, 조직 트리와 조직별 직접 소속 구성원 목록을 함께 주는 구조다.
여기서 `tenant.members[]``tenant.memberCount`는 해당 조직에 직접 붙어 있는 구성원 기준으로 해석한다.
화면의 하위조직 카드에 표시하는 인원 수는 직접 소속 수가 아니라, 해당 조직과 모든 descendant 조직의 직접 소속 인원을 합산한 `subtree 인원 수`로 앱에서 계산한다.
## 3. 현재 앱 기능과의 적합도 판단
### 3.1 매우 잘 맞는 부분
1. 회사/가족사 칩
- `tree.name`, `tree.slug`, `tenants[].name`, `tenants[].slug`, `parentId`
- 현재 상단 칩 구조와 직접 연결 가능
2. 하위조직 drilldown
- `tree.children[]`
- `tenant.parentId`
- 현재 정책의 `전체 > 회사 > 하위조직 > 개인` 탐색 구조와 잘 맞음
3. 조직별 소속 인원 표시
- `tenant.members[]`
- leaf 조직에서 직원 목록으로 진입하는 정책과 맞음
- 비-leaf 조직의 `members[]`는 직접 소속 인원이므로, 하위조직 목록과 한 화면에 섞어 표시하지 않는다
4. 직원 상세 기본 텍스트
- `members[].name`
- `members[].email`
- `members[].department`
- `members[].grade`
- `members[].position`
- `members[].jobTitle`
5. 조직도 정렬 힌트
- `members[].isOwner`
- `members[].isLeader`
- `members[].isPrimary`
- 현재 `팀장 우선` 정렬 정책에 보조 신호로 활용 가능
### 3.2 조건부로 맞는 부분
1. 전화/문자 기능
- `members[].phone`
- 하지만 Swagger 설명상 `includeUserIds=true`일 때만 포함
- 즉, 전화/문자 기능까지 쓰려면 `includeUserIds=true`가 사실상 필요
2. 직원 식별자 기반 상세/즐겨찾기
- `members[].id`
- 이것도 `includeUserIds=true`일 때만 포함
- 즐겨찾기/상세/프로필 이미지 매핑 안정성을 높이려면 필요
- 2026-07-15 실조회 기준 이 값은 실제 UUID 형식으로 내려오는 것을 확인했다
3. 초기 내 팀 뱃지 계산
- `members[].department``tenant.name` 매칭으로 어느 정도 가능
- 다만 `department` 문자열과 tenant 이름이 항상 1:1 대응하는지 추가 확인 필요
### 3.3 그대로는 부족한 부분
1. 앱 현재 `Employee` 모델의 `tenantId`, `tenantName`, `tenantSlug`
- `OrgContextMember` 안에는 tenant 정보가 직접 들어있지 않음
- 따라서 `tenant.members[]`를 순회하며 `상위 tenant 정보`를 멤버에 주입하는 앱 내부 flatten 가공이 필요
2. 현재 `EmployeeListResponse.items` 형태
- `org-context``items[]` 응답이 아니라 `tree + tenants[] + tenant.members[]` 구조
- 즉, 직원검색용 평탄 목록은 앱 내부에서 별도 생성해야 함
3. 현재 `TenantListResponse.items`
- `org-context``items[]` 래퍼가 아님
- `tenants[]` 또는 `tree.children[]``TenantSummary` 형태로 바꾸는 adapter 필요
4. `totalMemberCount`
- Swagger 예시에는 `memberCount`는 보이지만 `totalMemberCount`는 보장되지 않음
- 현재 앱 모델의 `totalMemberCount`는 앱 내부에서 descendant 포함 합산 계산이 필요
- 예: `CM본부` 자체 직접 소속이 0명이라도 하위 `CM사업부`에 511명이 있으면 `CM본부` 카드에는 511명으로 표시한다
- 반대로 leaf 조직의 직접 소속이 0명이면 leaf 진입 시 `검색 결과 없음` 표시가 정상일 수 있다
5. 프로필 사진 URL
- `profileImageUrl` 필드는 없음
- 사번/이미지 URL 직접 연결은 불가
## 4. 현재 Flutter 모델 기준 매핑 판단
### 4.1 `TenantSummary`
현재 필드:
- `id`
- `name`
- `slug`
- `type`
- `parentId`
- `memberCount`
- `totalMemberCount`
매핑 판단:
| 앱 필드 | org-context 소스 | 판단 |
| --- | --- | --- |
| `id` | `tenant.id` | 직접 가능 |
| `name` | `tenant.name` | 직접 가능 |
| `slug` | `tenant.slug` | 직접 가능 |
| `type` | `tenant.type` | 직접 가능 |
| `parentId` | `tenant.parentId` | 직접 가능 |
| `memberCount` | `tenant.memberCount` 또는 `tenant.members.length` | 직접 소속 수로 사용 |
| `totalMemberCount` | 없음 | 앱 내부에서 subtree 합산 계산 필요 |
### 4.2 `Employee`
현재 필드:
- `id`
- `name`
- `phoneNumber`
- `email`
- `tenantId`
- `tenantName`
- `tenantSlug`
- `department`
- `grade`
- `position`
- `jobTitle`
- `status`
- `profileImageUrl`
매핑 판단:
| 앱 필드 | org-context 소스 | 판단 |
| --- | --- | --- |
| `id` | `member.id` | `includeUserIds=true` 필요 |
| `name` | `member.name` | 직접 가능 |
| `phoneNumber` | `member.phone` | `includeUserIds=true` 필요 |
| `email` | `member.email` | 직접 가능 |
| `tenantId` | 상위 `tenant.id` | 가공 필요 |
| `tenantName` | 상위 `tenant.name` | 가공 필요 |
| `tenantSlug` | 상위 `tenant.slug` | 가공 필요 |
| `department` | `member.department` | 직접 가능 |
| `grade` | `member.grade` | 직접 가능 |
| `position` | `member.position` | 직접 가능 |
| `jobTitle` | `member.jobTitle` | 직접 가능 |
| `status` | 없음 또는 tenant status와 혼동 가능 | 재정의 필요 |
| `profileImageUrl` | 없음 | 별도 정책 필요 |
## 5. 화면 정책 기준 판단
### 5.1 바로 충족 가능한 정책
- 회사급 초기 범위
- 전체 > 회사 > 하위조직 > 개인 drilldown
- breadcrumb 유지
- leaf 조직 진입 후 직원 목록 표시
- 하위조직 카드의 subtree 인원 수 표시
- 조직도 그룹 내 리더 우선 정렬 보조
### 5.2 추가 가공 후 충족 가능한 정책
- 본인 팀 뱃지 고정 노출
- 선택 scope 기준 직원검색
- 즐겨찾기 로컬 저장
- 상세 화면 tenant/부서/직급/직위 표시
- 프로필 이미지 2순위 UUID 파일명 연결
### 5.3 현재 구조만으로는 바로 어려운 정책
- 프로필 사진 URL 표시
- 안정적인 직원 상세 단건 조회
- 서버 기반 즐겨찾기 동기화
## 6. 최종 판단
`org-context`는 다음 의미에서 채택 가치가 높다.
1. 조직도와 직원검색의 데이터 원형으로 충분히 쓸 수 있다.
2. 현재 앱이 원하는 조직 탐색 UX와 구조적으로 잘 맞는다.
3. 현재 코드의 `tdc114plus 전용 DTO`는 상당 부분 이 응답을 flatten/adapter 한 결과로 재해석할 수 있다.
하지만 아래 2가지는 분리해서 봐야 한다.
1. `데이터 구조 기준으로 채택할 것인가`
-
2. `모바일 앱이 운영 Key를 넣고 직접 호출할 것인가`
- 현재 기준으로는 보안 검토 전까지 아니오
### 6.1 2026-07-15 추가 확인
- 가족사 전체 `org-context` 응답과 기존 프로필 파일 CSV를 대조한 결과, 기존 `2457`건이 `members[].id`와 전건 매핑됐다.
- 따라서 현재 기준으로 `members[].id`는 프로필 이미지 2순위 식별자로 실사용 가능한 후보가 아니라, 사실상 채택 가능한 기준값으로 본다.
## 7. 다음 작업 권장 순서
1. `org-context`를 기준 데이터 구조로 채택한다고 문서에 명시
2. 현재 `Employee`, `TenantSummary`, `OrgChartSnapshot``org-context adapter` 기준으로 재설계
3. `includeUserIds=true`를 전제로 해야 하는 기능과 아닌 기능을 분리
4. 운영 Key 보호 방식을 확정
5. 그 다음 실제 코드 변경