# tdc114plus API 계약 작성일: 2026-07-02 최종 개정일: 2026-07-10 상태: v3.3 목적: `tdc114plus` Flutter 앱이 공식 인터페이스 기준으로 설계·개발될 수 있도록 1차 API 계약 원칙과 우선 사용 흐름을 정리한다. 상위 기준 문서: - `docs/00_policy_tdc114plus_decoupled_api_migration_2026-07-07.md` - `docs/00_policy_tdc114plus_development_2026-07-02.md` 공식 인터페이스 기준: - Swagger/API Docs: `https://sadmin.hmac.kr/api/docs#/` - 사용자 확인 추가 기준: `tdc114plus 앱 전용 API는 없고`, Swagger에 공개된 Baron API를 앱이 직접 소비한다. ## 1. 전제 - `tdc114plus` 신규 앱은 Baron SSO에 등록되는 별도 `RP(Relying Party)`다. - 앱 인증은 Baron SSO의 RP 로그인 절차 일부로 본다. - 앱은 Baron SSO 내부 구현이 아니라 공식 API 계약을 기준으로 설계한다. - 실제 backend 구현 상태와 무관하게 Flutter 앱은 이 계약을 바탕으로 mock/real 병행 개발이 가능해야 한다. - 현재 저장소 코드에 남아 있는 `/api/v1/tdc114plus/...` 가정은 확정 계약이 아니라 재검증 대상이다. - 재검증 대상 경로는 기능이 유지되는지 확인하면서 단계적으로 교체 또는 제거한다. ## 2. 핵심 원칙 - 신규 앱의 기본 로그인은 `Baron SSO Hosted Login + OIDC Authorization Code + PKCE`로 진행한다. - 앱은 Baron SSO 인증 URL을 열고, Baron SSO 로그인 화면에서 휴대폰번호 입력 및 문자/메일 링크 인증을 처리한다. - 앱은 callback으로 받은 authorization code를 PKCE `code_verifier`로 token 교환한 뒤 앱 세션을 저장한다. - 로그인 성공 후 Baron SSO가 조직도 API 호출에 필요한 연동 키 묶음을 내려주는 구조를 최종 목표로 둔다. - 해당 Baron SSO 기능이 개발되기 전까지는 앱 개발/검증용으로 로컬 비추적 환경값에 설정한 staging `org-context` 키를 fallback으로 사용한다. - 기존 `선진행 후확인` 방식은 신규 앱 기본 인증 정책으로 사용하지 않는다. - 기존 `phone-login` 방식은 개발용 fallback 또는 제한적 호환 범위로만 둔다. - 레거시 계약 제거는 `대체 path 반영 -> mock/real 테스트 통과 -> 실제 화면 확인 -> 제거` 순서를 지킨다. - JSON field는 camelCase를 사용한다. - 목록 응답은 가능하면 `items`, `limit`, `offset`, `total`, `nextCursor` 형식을 따른다. - UI는 DTO와 repository interface만 의존하고, endpoint path나 header를 직접 다루지 않는다. ## 3. 1차 범위 - Baron SSO Hosted Login 시작 - App Link callback 수신 - PKCE authorization code token 교환 - 로그인 세션 저장 후 앱 진입 - 직원검색 - 가족사/조직 탐색 - 조직도 - 직원 상세 - 즐겨찾기 로컬 저장 보류: - 공지사항 - 전자결재 - 수신전화식별 - 수신팝업 - 서버 기반 즐겨찾기 동기화 ## 4. 인증 계약 주의: - `tdc114plus 앱 전용 API는 없다`는 사용자 확인이 들어왔으므로, 아래 계약은 Baron Swagger 기준으로 재정렬한다. - Flutter 앱은 Baron headless API를 직접 호출하지 않는다. - 휴대폰번호 입력과 링크 발송/승인은 Baron SSO Hosted Login 화면과 서버 내부 구현으로 둔다. - legacy `/api/v1/tdc114plus/...` path는 예외 호환 또는 과거 흔적으로만 취급한다. ### 4.1 로그인 시작 ```http GET https://sso.hmac.kr/oidc/oauth2/auth ``` 의미: - 앱이 PKCE `code_verifier`, `code_challenge`, `state`, `nonce`를 생성한다. - 앱이 Baron SSO authorization endpoint를 브라우저/커스텀탭으로 연다. - 사용자는 Baron SSO Hosted Login 화면에서 휴대폰번호 입력과 문자/메일 링크 인증을 진행한다. 예시 query: ```http client_id=39d6190d-72f6-4a58-a84f-cdc5ece3e8af redirect_uri=https://114.hmac.kr/auth/callback response_type=code scope=openid profile email tenants state={random-state} nonce={random-nonce} code_challenge={S256-code-challenge} code_challenge_method=S256 ``` ### 4.2 callback 수신 ```http GET https://114.hmac.kr/auth/callback?code={authorization-code}&state={state} ``` 의미: - `https://114.hmac.kr/auth/callback`은 Android App Link로 앱에 연결한다. - 앱은 callback의 `state`가 저장된 PKCE transaction의 `state`와 같은지 검증한다. - `state`가 다르면 token 교환을 중단한다. ### 4.3 token 교환 ```http POST https://sso.hmac.kr/oidc/oauth2/token ``` 의미: - 앱은 authorization code와 저장된 `code_verifier`를 사용해 token endpoint를 호출한다. - PKCE 공개 앱이므로 Client Secret을 보내지 않는다. 예시 요청: ```http grant_type=authorization_code client_id=39d6190d-72f6-4a58-a84f-cdc5ece3e8af code={authorization-code} code_verifier={stored-code-verifier} redirect_uri=https://114.hmac.kr/auth/callback ``` 완료 응답 예시: ```json { "access_token": "access-token", "token_type": "Bearer", "expires_in": 3600, "id_token": "id-token", "org_context": { "base_url": "https://sadmin.hmac.kr", "tenant_slug": "hanmac-family", "key_id": "org-context-key-id", "key_secret": "org-context-key-secret", "expires_at": "2026-07-10T12:00:00Z" } } ``` `org_context`는 향후 Baron SSO가 제공할 예정인 확장 필드 예시다. 현재 staging 서버 기능이 미개발이면 응답에 없을 수 있으며, 앱은 이 필드가 없을 때 로컬 비추적 환경값의 staging 고정 키를 사용한다. ### 4.4 headless API 직접 호출 제외 ```http POST /api/v1/auth/headless/phone-login POST /api/v1/auth/headless/link/poll ``` - 위 API는 Baron SSO 내부 구현 또는 confidential client용 참고 계약으로 본다. - 현재 Flutter 앱은 공개 PKCE 앱이므로 `client_assertion`, `private_key_jwt`, RP 개인키를 APK에 넣지 않는다. - 따라서 위 API는 신규 앱 기본 로그인 구현에서 직접 호출하지 않는다. ### 4.5 레거시/개발용 즉시 로그인 ```http POST /api/v1/tdc114plus/auth/phone-login ``` - 이 경로는 개발용 fallback 또는 제한적 호환 범위로만 본다. - 신규 앱 기본 로그인 UX로 간주하지 않는다. ## 5. 세션 및 사용자 정보 ### 5.1 세션 저장 기준 - token 교환 성공 시 반환된 access token과 만료시간을 앱 저장소에 저장한다. - 사용자 정보는 `id_token` claim 또는 후속 `userinfo` 응답에서 가져온다. - 조직도 API 호출용 연동 키가 token 응답, userinfo, 또는 별도 session endpoint로 전달되면 앱 세션의 선택적 `orgContextCredential`로 저장한다. - `orgContextCredential`이 있으면 `integrations/org-context` 호출 시 이 값을 우선 사용하고, 없으면 개발/검증용 비추적 환경값 fallback을 사용한다. - 연동 키는 로그에 출력하지 않고, 운영 배포 전에는 안전 저장소 적용 여부를 별도 검토한다. - 앱 재실행 시 저장 세션이 유효하면 로그인 화면을 건너뛴다. - API 호출 중 `401/403`이 발생하면 세션 정리 후 재로그인 흐름으로 돌린다. ### 5.2 사용자 기본 정보 로그인 완료 후 앱이 기대하는 최소 사용자 정보: ```json { "id": "user-uuid", "name": "홍길동", "phoneNumber": "+821012345678", "tenantId": "tenant-uuid", "tenantName": "한맥", "tenantSlug": "hanmac", "department": "기술연구소", "grade": "책임", "position": "팀장", "jobTitle": "개발" } ``` ## 6. 조직/직원 데이터 계약 원칙 - 직원검색과 조직도는 공식 인터페이스가 제공하는 조직/직원 endpoint를 기준으로 설계한다. - 실제 배포 전까지 조직/직원 API 기준은 staging Swagger(`https://sadmin.hmac.kr/api/docs#/Integrations/get_api_v1_integrations_org_context`)와 staging `org-context` endpoint를 따른다. - 가족사/조직 탐색은 `tenant` 계층과 `tenantSlug`를 기준으로 진행한다. - 로그인 직후 기본 범위는 사용자의 회사급 `tenantSlug`를 우선 기준으로 한다. - 화면 정책상 필요한 drilldown 구조는 repository 계층에서 정리하고 UI는 결과 모델만 소비한다. - 현재 `/api/v1/tdc114plus/organization/*`, `/api/v1/tdc114plus/directory/*` 같은 path는 확정 계약이 아니라 placeholder 성격일 수 있으므로, Swagger의 실제 공개 path인 `integrations/org-context`, `public/orgchart` 기준으로 교체한다. - 교체 전까지는 mock과 실제 화면이 같은 결과를 내는지 확인해 기능 공백 없이 전환한다. ### 6.1 subtree 계약 보강 필요사항 - 회사 선택 후 `부서 -> 팀 -> 개인` drilldown을 구현하려면 조직 subtree 조회 계약이 필요하다. - 현재 API가 최상위 tenant 위주 응답만 제공하는 경우, 앱은 fallback으로 회사 단위 직원 목록과 본인팀 synthetic chip만 유지한다. - Swagger의 `public/orgchart`처럼 `tenants[]`, `users[]` 중심 응답을 사용할 경우에도, 최종 목표 계약은 해당 배열만으로 특정 tenant 기준 자식 조직 subtree와 leaf 판단 정보를 복원할 수 있는 형태다. - 해당 보강 요청은 `docs/00_guide_baron_sso_subtree_api_issue_request_2026-07-07.md` 초안 기준으로 Baron SSO 이슈로 병행 관리한다. ## 7. Flutter 구현 해석 - `auth` feature는 Hosted Login authorization URL 생성, PKCE transaction 저장, callback token 교환, 세션 저장 흐름을 우선 구현한다. - `directory`, `organization` feature는 `org-context` 중심 Swagger DTO와 repository interface를 먼저 고정한다. - mock repository는 실제 API 미구현 상태에서도 유지한다. - 실제 API 경로와 mock 경로는 동일한 UI 흐름을 만족해야 한다. ## 8. 문서 갱신 원칙 - Swagger 기준이 달라지면 이 문서를 먼저 갱신한다. - 새 endpoint를 사용하기 시작하면 request/response 예시를 추가한다. - 내부 추정이 아니라 공식 인터페이스에서 확인된 내용만 확정 표현으로 남긴다. - 사용자 확인으로 뒤집힌 가정은 즉시 `가정` 또는 `재검증 대상`으로 강등한다.