한 줄 목표
AI 분석 요청을 Server DB에 남는 비동기 AiRun resource 로 생성·조회·재시도하고, HR이 채택한 candidate만 Task로 만들도록 구현합니다.
화면 기준
Figma [PWF] Prototype-WireFrame-3rd의 05_Desktop Core Product > CREATE / REVIEW
자연어 입력 후 즉시 완료된 것처럼 보이지 않고 실행 상태를 조회합니다.
여러 candidate를 카드로 보여 주고 HR이 각각 채택·수정·폐기합니다.
누락정보나 모호성이 있으면 실패 화면이 아니라 추가 확인 화면을 보여 줍니다.
세부 요청·응답 필드는 Notion API 명세 를 기준으로 합니다.
사용자 흐름
POST /api/v1/ai-runs가 요청·Idempotency-Key를 저장하고 202 + aiRunId 반환
Durable worker가 attempt를 만들고 [AI Integration] AiRuntimeClient·계약 검증·장애 격리 구현 #8 AiRuntimeClient 호출
Server가 Runtime 응답을 다시 검증하고 candidate 저장
Client가 GET /api/v1/ai-runs/{aiRunId}로 기술 상태와 분석 outcome 조회
HR이 candidate-decisions로 후보를 채택·수정·폐기
채택 후보만 제안 상태에 맞는 Task가 되며 승인·발송은 별도 command
소유 API
POST /tasks/analyze, /task-analyses/{id}/confirm, /ai-runs/{id}/confirm은 canonical API가 아닙니다.
서로 다른 상태를 구분합니다
종류
값
의미
AiRun status
QUEUED, RUNNING, RETRYING, SUCCEEDED, FAILED
Server의 실행·복구 상태
analysisOutcome
NEEDS_INFO, REVIEW_REQUIRED
정상 분석 결과와 HR의 다음 행동
candidate.proposedTaskStatus
DRAFT, NEEDS_INFO, READY_FOR_REVIEW
후보를 채택했을 때 만들 Task의 시작 상태
낮은 confidence, ambiguity, missing slot은 FAILED가 아닙니다. Runtime 호출·Schema·deadline처럼 기술적으로 결과를 신뢰할 수 없을 때만 실패합니다.
수동 retry는 같은 Run에서 FAILED → RETRYING으로 전이하고 새 AiAttempt를 만듭니다. 이전 attempt 기록은 수정·삭제하지 않습니다.
Candidate 결정 계약
Header: Idempotency-Key
Body: decisions[{candidateId, action=ACCEPT|DISCARD, edits?}], expectedRunVersion
ACCEPT: Server가 허용 필드와 업무 규칙을 재검증한 뒤 Task 생성
DISCARD: 후보는 삭제하지 않고 폐기 결정을 감사 가능하게 보존
같은 decision 재전송은 같은 결과를 반환하며 Task를 중복 생성하지 않음
일부 후보만 선택할 수 있고, 선택되지 않은 후보를 자동 승인하지 않음
저장할 정보
id, companyId, actor, masked input/hash, Idempotency-Key hash
status, analysisOutcome, attempt/retry count, nextAttemptAt, @Version
candidate와 validation error, 제안 Task 상태, 채택/폐기 decision, Task reference
requestId, attemptId, traceId, latencyMs, error code
backend/agent/model/prompt/contextPack/workflowCatalog/contract/knowledge version
민감 원문, 전체 Prompt, Provider secret은 저장하지 않습니다.
구현 범위
Retry 소유권
Server retry: 같은 AiRun에 새로운 AiAttempt를 영속 생성하고 202 + 같은 aiRunId 반환
AI Runtime retry: 한 attempt 내부의 제한된 Provider retry
RemoteAiRuntimeClient 투명 retry 금지; 총 호출 횟수가 곱해지지 않게 함
같은 retry Idempotency-Key의 반복 호출은 AiAttempt 하나만 생성
완료 조건
경계 밖
관계
한 줄 목표
AI 분석 요청을 Server DB에 남는 비동기 AiRun resource로 생성·조회·재시도하고, HR이 채택한 candidate만 Task로 만들도록 구현합니다.
화면 기준
[PWF] Prototype-WireFrame-3rd의05_Desktop Core Product > CREATE / REVIEW사용자 흐름
POST /api/v1/ai-runs가 요청·Idempotency-Key를 저장하고202 + aiRunId반환AiRuntimeClient호출GET /api/v1/ai-runs/{aiRunId}로 기술 상태와 분석 outcome 조회candidate-decisions로 후보를 채택·수정·폐기소유 API
POST /api/v1/ai-runsGET /api/v1/ai-runs/{aiRunId}POST /api/v1/ai-runs/{aiRunId}/retryPOST /api/v1/ai-runs/{aiRunId}/candidate-decisionsPOST /tasks/analyze,/task-analyses/{id}/confirm,/ai-runs/{id}/confirm은 canonical API가 아닙니다.서로 다른 상태를 구분합니다
QUEUED,RUNNING,RETRYING,SUCCEEDED,FAILEDNEEDS_INFO,REVIEW_REQUIREDDRAFT,NEEDS_INFO,READY_FOR_REVIEW낮은 confidence, ambiguity, missing slot은
FAILED가 아닙니다. Runtime 호출·Schema·deadline처럼 기술적으로 결과를 신뢰할 수 없을 때만 실패합니다.수동 retry는 같은 Run에서
FAILED → RETRYING으로 전이하고 새AiAttempt를 만듭니다. 이전 attempt 기록은 수정·삭제하지 않습니다.Candidate 결정 계약
Idempotency-Keydecisions[{candidateId, action=ACCEPT|DISCARD, edits?}], expectedRunVersionACCEPT: Server가 허용 필드와 업무 규칙을 재검증한 뒤 Task 생성DISCARD: 후보는 삭제하지 않고 폐기 결정을 감사 가능하게 보존저장할 정보
id,companyId, actor, masked input/hash, Idempotency-Key hashstatus,analysisOutcome, attempt/retry count, nextAttemptAt,@VersionrequestId,attemptId,traceId,latencyMs, error code민감 원문, 전체 Prompt, Provider secret은 저장하지 않습니다.
구현 범위
409RUNNINGlease/timeout 복구Retry 소유권
202 + 같은 aiRunId반환RemoteAiRuntimeClient투명 retry 금지; 총 호출 횟수가 곱해지지 않게 함완료 조건
경계 밖
fowoco/aifowoco/knowledge관계
blocked by참조