# 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 예시를 추가한다.
- 내부 추정이 아니라 공식 인터페이스에서 확인된 내용만 확정 표현으로 남긴다.
- 사용자 확인으로 뒤집힌 가정은 즉시 `가정` 또는 `재검증 대상`으로 강등한다.
