테넌트 어드민 JWT 인증 으로 호출. SDK 측의 X-API-KEY 와 다른 인증 체계입니다. 호스트는 https://{tenantCode}.aika.life (베타) / https://{tenantCode}.ones1ght.com (프로덕션).백오피스(admin.aika.life) 는 /api/v1/admin/sdk-chat/... 로 모든 테넌트 데이터를 무제한 조회 가능 (super admin 권한).
1. 실시간 SSE 스트림
GET /api/v1/sdk-chat/events/stream
Content-Type: text/event-stream. 테넌트 어드민으로 1 회 연결하면 그 테넌트 내 모든 SDK 채팅 라이프사이클 이벤트가 실시간으로 푸시됩니다. 25 초 간격 ping heartbeat 로 ALB / nginx idle timeout 방지.
이벤트 종류
| event | 트리거 | data 페이로드 |
|---|
ready | 연결 직후 1회 | {} |
ping | 25 초마다 | (빈 문자열) |
chat_completed | 폴링 응답이 status: "completed" 로 처음 전이 | {profile_id, chat_id} |
backlist_triggered | iOS 가 POST /v1/chat/{pid}/backlist-trigger 호출 | {profile_id, chat_id, notification_items} |
클라이언트 예 (브라우저)
const es = new EventSource("/api/v1/sdk-chat/events/stream", { withCredentials: true });
es.addEventListener("chat_completed", (e) => {
const { profile_id, chat_id } = JSON.parse(e.data);
// → /api/v1/sdk-chat/{chat_id} 디테일 재조회
});
es.addEventListener("backlist_triggered", (e) => {
const { profile_id, chat_id, notification_items } = JSON.parse(e.data);
// → 대시보드 우측 토스트 / 지도 마커 등 즉시 렌더
});
라이브 only — 구독자가 없는 시점에 발생한 이벤트는 buffering 없이 drop. 누적 데이터는 아래 히스토리 엔드포인트로.
2. 히스토리 리스트 (페이징)
GET /api/v1/sdk-chat?profile_id={uuid}&page=0&size=20
자기 테넌트의 sdk_chat 행을 최신순으로 페이징. profile_id 필터 선택. size 최대 100.
Response 200
{
"success": true,
"data": {
"items": [
{
"chat_id": "3736f10f-...",
"profile_id": "6b97957c-...",
"profile_summary": { "name": "佐藤花子", "gender": "F", "age": 32, "locale": "ja" },
"prompt": "오늘 저녁 카레 땡기는데",
"status": "completed",
"last_error": null,
"created_at": "2026-04-23T05:28:08Z",
"updated_at": "2026-04-23T05:30:00Z",
"ended_at": "2026-04-23T05:31:00Z"
}
],
"total": 234,
"page": 0,
"size": 20
}
}
| 필드 | 설명 |
|---|
status | in_progress / completed / error / ended (폴링과 같은 어휘) |
profile_summary | sdk_profile.data JSONB 에서 name / gender / age / locale 만 추출 |
last_error | error 일 때만 채워짐 |
ended_at | DELETE 호출 시점, 그 외 null |
pipeline_result 는 리스트에 포함하지 않음 (용량 ↑). 상세는 아래.
3. 히스토리 상세
GET /api/v1/sdk-chat/{chat_id}
폴링 완료 시점의 응답을 그대로 보존 — status / back_list_status / todos / recommended_items / notification_items 가 top-level 에 hoist 되어 있어 폴링 응답과 동일 shape. 자세한 필드 설명은 Profile Chat — 4. 채팅 이력 조회 참조 (응답 구조 동일).
추가로 리스트와 동일하게 profile_summary, profile_session_id 까지 동봉.
4. 백오피스 (super admin) 엔드포인트
admin.aika.life 에서 호출. 테넌트 경계 없이 전체 조회. tenant_id, profile_id 둘 다 선택 필터.
| 엔드포인트 | 동작 |
|---|
GET /api/v1/admin/sdk-chat?tenant_id=...&profile_id=...&page=...&size=... | 테넌트 어드민 리스트와 동일 shape, 추가로 각 row 에 tenant_id 동봉 |
GET /api/v1/admin/sdk-chat/{chat_id} | 테넌트 어드민 상세와 동일 shape (테넌트 제약 없음) |
권한: ROLE_ADMIN (Spring Security @PreAuthorize).
5. 권한 매트릭스
| 엔드포인트 | 인증 | 권한 |
|---|
GET /api/v1/sdk-chat/events/stream | 테넌트 JWT | user.role == 'admin' |
GET /api/v1/sdk-chat | 테넌트 JWT | user.role == 'admin' |
GET /api/v1/sdk-chat/{chat_id} | 테넌트 JWT | user.role == 'admin' |
GET /api/v1/admin/sdk-chat | 백오피스 JWT | ROLE_ADMIN |
GET /api/v1/admin/sdk-chat/{chat_id} | 백오피스 JWT | ROLE_ADMIN |
미인가 시 401 / 403.
6. 푸시 / 풀 둘 다 사용하는 권장 패턴
[페이지 진입]
├─ GET /api/v1/sdk-chat?page=0 → 초기 리스트 렌더
└─ EventSource(/events/stream) → 이후 변경 사항 실시간 반영
├─ chat_completed → 해당 row 만 GET /{chat_id} 로 fresh detail 갱신
└─ backlist_triggered → 토스트 / 지도 마커 등 즉시 표시