diff --git a/tdc114plus/tdc114plus 프로필 이미지 관리 정책 및 단계별 진행안.md b/tdc114plus/tdc114plus 프로필 이미지 관리 정책 및 단계별 진행안.md new file mode 100644 index 0000000..07543f7 --- /dev/null +++ b/tdc114plus/tdc114plus 프로필 이미지 관리 정책 및 단계별 진행안.md @@ -0,0 +1,328 @@ +# tdc114plus 프로필 이미지 관리 정책 및 단계별 진행안 + +작성일: 2026-07-14 +최종 개정일: 2026-07-15 +상태: draft +관련 Phase: `Phase 7-C` + +## 1. 목적 + +신규앱의 직원 프로필 이미지를 어떤 우선순위와 어떤 저장/조회 구조로 운영할지 정리한다. + +본 문서의 목적은 아래 네 가지다. + +- 프로필 이미지 노출 우선순위를 고정한다. +- 네이버웍스, 114 중계서버 내부 DB, R2 버킷의 역할을 분리한다. +- 중계서버 내부에 둘 매핑 테이블의 권고 컬럼을 정리한다. +- 실제 구현을 위한 단계별 진행작업을 타임테이블 형식으로 정리한다. + +## 2. 현재까지 확인된 사실 + +### 2-1. 이미지 노출 우선순위 + +현재 정리된 우선순위는 아래와 같다. + +1. 네이버웍스 프로필 사진 +2. 114 중계서버 내부 매핑 DB + R2 버킷 fallback 이미지 +3. 신규앱 기본 아바타 + +즉, R2 버킷 기반 이미지는 기본 경로가 아니라 `2차 fallback` 경로다. + +### 2-2. 네이버웍스 문서 검토 결과 + +2026-07-15 기준 네이버웍스 개발자 문서 `구성원 프로필 조회` 화면에서 아래는 확인했다. + +- Endpoint: `GET /users/{userId}` +- Scope: `user.profile.read` +- `userId`에는 구성원 ID, 메일, 리소스 ID, `externalKey:{externalKey}` 형식 사용 가능 +- 응답 예시 기준 확인 필드: + - `email` + - `userId` + - `userExternalKey` + - 이름, 전화번호, 조직 정보 + +아직 추가 확인이 필요한 사항: + +- 프로필 사진 URL 필드 존재 여부 +- 프로필 사진 바이너리 직접 응답 여부 +- `사진 조회` API의 endpoint, scope, 응답 형식 +- 사진이 없는 사용자의 판별 방식 + +### 2-3. 현재 준비된 외부 자산 + +현재 다른 개발자가 준비한 자산은 아래와 같다. + +- 프로필 이미지 파일은 Cloudflare R2 Object Storage 버킷에 업로드되어 있다. +- 현재 확인된 버킷/도메인 구조는 아래와 같다. + - 공개 도메인 prefix: `https://baroncs.co.kr/employee_img/TDC/` + - 파일명 suffix: 해시 기반 `.jpg` +- 즉, 최종 URL은 아래 구조로 해석할 수 있다. + +```text +https://baroncs.co.kr/employee_img/TDC/{hash_filename}.jpg +``` + +- 현재 파일 경로 앞부분 `https://baroncs.co.kr/employee_img/TDC/` 는 고정값으로 간주하고 진행한다. + +### 2-4. 현재 준비된 매핑 테이블 + +현재 다른 서버에 `mapping_profile_img` 테이블이 이미 생성되어 있다. + +확인된 컬럼은 아래와 같다. + +- `id` +- `comp` +- `old_name` +- `new_name` +- `status` +- `name` +- `email` +- `hash_name` +- `hash_status` +- `created_at` + +현재 테이블은 `파일명 변경/해시 매핑 결과 관리` 용도로는 유효하지만, 신규앱 런타임 조회를 직접 담당하는 `114 중계서버 운영 테이블`로 쓰기에는 일부 컬럼이 더 필요하다. + +### 2-5. 목표 운영 위치 + +현재 DB는 다른 서버에 있으나, 목표 방향은 `114 신규어플 중계서버 내부`에 매핑 DB를 두는 것이다. + +핵심 이유는 아래와 같다. + +- 해시/매핑 테이블을 114 시스템 내부에 두어 외부 노출을 줄이기 위함 +- 신규앱이 직접 파일명 규칙, 해시 규칙, 외부 DB를 알지 않게 하기 위함 +- 중계서버가 사용자 식별과 최종 이미지 경로를 내부에서만 매핑하도록 만들기 위함 + +## 3. 현재 기준 정책 + +### 3-1. 기본 정책 + +- 신규앱은 직접 파일명을 만들지 않는다. +- 신규앱은 직접 R2 객체 경로를 계산하지 않는다. +- 신규앱은 먼저 네이버웍스 프로필 사진을 사용한다. +- 네이버웍스 사진이 없을 때만 114 중계서버 fallback 경로를 사용한다. +- 114 중계서버는 내부 매핑 DB를 조회해 R2 버킷의 이미지와 사용자를 연결한다. +- 그마저도 실패하면 앱은 기본 아바타를 사용한다. + +### 3-2. 권장 조회 흐름 + +```text +신규앱 +-> 네이버웍스 사진 확인 +-> 없으면 114 중계서버에 직원 식별값 전달 +-> 114 중계서버가 내부 매핑 DB 조회 +-> R2 객체 경로 또는 최종 이미지 응답 반환 +-> 실패 시 기본 아바타 +``` + +### 3-3. 신규앱이 직접 하지 않아야 하는 일 + +- `이메일 @ 앞부분.jpg` 직접 조합 +- 해시 파일명 직접 계산 +- R2 저장 경로 직접 추론 +- 외부 DB 직접 접근 + +## 4. 현재 테이블 구조 해석 + +현재 `mapping_profile_img` 테이블의 의미는 아래처럼 해석할 수 있다. + +- `comp` + - 한글명: `회사구분` + - 의미: 계열사/회사 코드 + +- `old_name` + - 한글명: `기존 파일명` + - 의미: 기존 프로필 파일명 + +- `new_name` + - 한글명: `변경 파일명` + - 의미: 1차 치환 또는 정리 후 파일명 + +- `status` + - 한글명: `변환 상태` + - 의미: 파일명 변경 상태 + +- `name` + - 한글명: `직원명` + - 의미: 직원 실명 + +- `email` + - 한글명: `직원 이메일` + - 의미: 직원의 전체 이메일 주소 + +- `hash_name` + - 한글명: `해시 파일명` + - 의미: 최종 해시 기반 이미지 파일명 + +- `hash_status` + - 한글명: `해시 매핑 상태` + - 의미: 해시 파일명 매핑 처리 상태 + +- `created_at` + - 한글명: `생성일시` + - 의미: 매핑 행 생성 시각 + +## 5. 중계서버 내부 테이블에 추가 권장되는 컬럼 + +현재 테이블은 변환 이력 관리에는 도움이 되지만, 신규앱 조회 운영을 위해서는 아래 컬럼을 추가하는 편이 좋다. + +### 5-1. 핵심 추가 권장 컬럼 + +- `employee_email` + - 한글명: `직원 이메일` + - 설명: 직원 전체 이메일 주소 + - 비고: 현재 테이블의 `email`이 사실상 같은 역할을 하므로, 이름만 정리해도 된다. + +- `employee_email_local_part` + - 한글명: `이메일 @앞부분` + - 설명: 이메일의 `@` 앞부분 + - 예: `khkang@samaneng.com` -> `khkang` + - 비고: 기존 자산 규칙과 직접 연결할 때 유용하다. + +- `object_key` + - 한글명: `버킷 내부 파일경로` + - 설명: R2 버킷 안의 실제 저장 경로 + - 예: `employee_img/TDC/81f931388c85da0ec18cac730231827f58e5338cb1bf4751d472af413d5c557e.jpg` + - 비고: 현재 `hash_name`만으로도 조합은 가능하지만, 운영 테이블에는 전체 경로를 저장하는 편이 낫다. + +### 5-2. 운영용 추가 권장 컬럼 + +- `is_active` + - 한글명: `사용 여부` + - 설명: 현재 앱 fallback 이미지로 사용할 수 있는 행인지 표시 + +- `updated_at` + - 한글명: `수정일시` + - 설명: 최근 변경 시각 + +- `deleted_at` + - 한글명: `삭제일시` + - 설명: soft delete 관리용 + +- `profile_source` + - 한글명: `프로필 이미지 출처` + - 설명: `NAVER_WORKS`, `R2_FALLBACK`, `DEFAULT` 같은 출처 관리 + +- `object_bucket` + - 한글명: `버킷명` + - 설명: 예: `baron-hompage` + +- `public_base_url` + - 한글명: `공개 URL 기준경로` + - 설명: 예: `https://baroncs.co.kr/employee_img/TDC/` + - 비고: 현재는 고정값이지만 환경 분리를 고려하면 설정 또는 컬럼화 검토 가능 + +- `last_verified_at` + - 한글명: `객체 확인일시` + - 설명: 실제 버킷 객체 존재 여부를 마지막으로 확인한 시각 + +### 5-3. 현재 구조 대비 최소 권장안 + +중계서버 내부에 최소 구성으로 새 테이블을 만든다면 아래는 반드시 권장한다. + +- `comp` +- `employee_email` +- `employee_email_local_part` +- `name` +- `object_key` +- `hash_name` +- `is_active` +- `created_at` +- `updated_at` + +## 6. object_key와 hash_name의 차이 + +현재 고정 경로 prefix는 아래와 같다. + +```text +https://baroncs.co.kr/employee_img/TDC/ +``` + +따라서 두 컬럼의 차이는 아래처럼 정리된다. + +- `hash_name` + - 한글명: `해시 파일명` + - 예: `81f931388c85da0ec18cac730231827f58e5338cb1bf4751d472af413d5c557e.jpg` + +- `object_key` + - 한글명: `버킷 내부 파일경로` + - 예: `employee_img/TDC/81f931388c85da0ec18cac730231827f58e5338cb1bf4751d472af413d5c557e.jpg` + +- 최종 URL + - 한글명: `프로필 이미지 URL` + - 예: `https://baroncs.co.kr/employee_img/TDC/81f931388c85da0ec18cac730231827f58e5338cb1bf4751d472af413d5c557e.jpg` + +운영 편의성 기준으로는 `hash_name`만 보관하기보다 `object_key`를 같이 두는 편이 더 낫다. + +## 7. 114 중계서버 운영 기준 권장 스키마 + +현재 테이블을 그대로 쓰기보다, 중계서버 내부 운영용 테이블은 아래 같은 형태를 권장한다. + +| 컬럼명 | 한글명 | 용도 | +| --- | --- | --- | +| `id` | 식별자 | PK | +| `comp` | 회사구분 | 회사/계열사 구분 | +| `employee_email` | 직원 이메일 | 신규앱/직원 API 매핑 기준 | +| `employee_email_local_part` | 이메일 @앞부분 | 기존 자산 규칙 연결용 | +| `employee_name` | 직원명 | 운영 확인용 | +| `object_bucket` | 버킷명 | 저장 버킷 식별 | +| `object_key` | 버킷 내부 파일경로 | 실제 이미지 객체 경로 | +| `hash_name` | 해시 파일명 | 파일명 원본 보관용 | +| `profile_source` | 프로필 이미지 출처 | `R2_FALLBACK` 등 출처 구분 | +| `is_active` | 사용 여부 | fallback 사용 가능 여부 | +| `created_at` | 생성일시 | 생성 시각 | +| `updated_at` | 수정일시 | 수정 시각 | +| `deleted_at` | 삭제일시 | soft delete 용 | + +## 8. 단계별 진행작업 타임테이블 + +아래 타임테이블은 현재까지 확보된 정보 기준의 권장 순서다. + +| 단계 | 상태 | 작업 구분 | 작업 내용 | 완료 기준 | +| --- | --- | --- | --- | --- | +| Step 1 | 진행 중 | 문서/정책 | 프로필 이미지 우선순위, R2 구조, 중계서버 내부 DB 방향을 문서에 정리 | 본 문서와 타임테이블 반영 완료 | +| Step 2 | 대기 | 네이버웍스 검증 | `사진 조회` API endpoint, scope, 응답 형식, 무사진 응답 규칙 확인 | 네이버웍스 사진 연동 가능/불가 기준 확정 | +| Step 3 | 대기 | 현행 자산 점검 | 현재 R2 버킷 구조, 고정 prefix, 해시 파일명 규칙, 공개 URL 정책 확인 | 버킷/경로/공개정책 확정 | +| Step 4 | 대기 | 현행 DB 점검 | 현재 `mapping_profile_img` 실제 데이터 의미와 컬럼 용도 재확인 | 현행 테이블 해석표 확정 | +| Step 5 | 대기 | 중계서버 DB 설계 | 114 내부 운영용 테이블 컬럼, 인덱스, 활성여부, 수정일시 설계 | 운영용 스키마 초안 확정 | +| Step 6 | 대기 | 데이터 이관 설계 | 외부 서버 DB -> 114 내부 DB 이관 방식과 컬럼 매핑 정리 | 이관 계획서 확정 | +| Step 7 | 대기 | 중계 API 설계 | 신규앱이 중계서버에 어떤 식별값을 보내고 어떤 응답을 받을지 정리 | API 요청/응답 계약 초안 확정 | +| Step 8 | 대기 | 앱 연동 설계 | `네이버웍스 -> 중계서버 fallback -> 기본 아바타` 구현 순서 정리 | 앱 연동 시나리오 확정 | +| Step 9 | 대기 | 검증/테스트 | 정상 이미지, 무사진, 매핑 누락, 404, timeout, 비활성 이미지 테스트 | 테스트 케이스 확정 | +| Step 10 | 대기 | 구현 착수 | 중계서버 DB 생성, 데이터 이관, API 구현, 앱 연결 순차 진행 | 실제 구현 시작 가능 상태 | + +## 9. 단계별 상세 진행 순서 + +### 9-1. 문서 정리 단계 + +1. 프로필 이미지 정책 문서를 최신 사실 기준으로 정리한다. +2. R2 버킷 구조와 매핑 테이블 컬럼 의미를 고정한다. +3. 중계서버 내부 DB 이전 방향을 정책으로 명시한다. + +### 9-2. 중계서버 DB 설계 단계 + +1. 현재 `mapping_profile_img`의 재사용 범위를 결정한다. +2. 운영용 테이블을 별도로 둘지, 기존 테이블을 확장할지 결정한다. +3. `employee_email`, `employee_email_local_part`, `object_key` 포함 여부를 확정한다. +4. `is_active`, `updated_at`, `deleted_at` 같은 운영 컬럼을 확정한다. + +### 9-3. API 및 앱 연동 단계 + +1. 신규앱이 중계서버로 어떤 식별값을 보내는지 결정한다. +2. 중계서버가 어떤 컬럼으로 이미지를 조회할지 결정한다. +3. 중계서버가 URL을 반환할지, 이미지 바이너리를 프록시할지 결정한다. +4. 앱에서 네이버웍스 실패 시에만 fallback 호출하도록 연결한다. + +## 10. 현재 시점 우선 결론 + +- 프로필 이미지 1순위는 네이버웍스다. +- fallback 이미지는 R2 버킷을 사용하되, 조회 책임은 114 중계서버 내부로 가져오는 방향이 적절하다. +- 현재 다른 서버의 `mapping_profile_img`는 참고 소스/이관 원본으로 보고, 114 내부 운영용 테이블은 별도 정리하는 쪽이 안전하다. +- 최소 추가 권장 컬럼은 `employee_email_local_part`, `object_key`, `is_active`, `updated_at` 이다. +- 현재 단계에서는 구현보다 문서/정책/스키마 정리를 먼저 완료하는 것이 맞다. + +## 11. 관련 문서 + +- `docs/00_guide_tdc114plus_work_progress_timetable_2026-07-02.md` +- `docs/00_contract_tdc114plus_api_2026-07-02.md` +- `docs/00_guide_tdc114plus_org_context_mapping_2026-07-08.md`