Files
voiceon-character-admin/docs/20260806_수정요청변경필드만전송/api-contract.md

7.0 KiB

수정 요청 변경 필드 전송 API Contract

1. 공통 계약

이 문서는 기존 AI 캐릭터 관리자 OpenAPI의 endpoint·DTO를 바꾸지 않고, 프론트엔드가 수정 request를 구성하는 규칙을 구체화한다. 이 문서와 정식 OpenAPI가 충돌하면 정식 OpenAPI의 field type·nullable·response·error 계약을 우선하고 이 문서는 payload 선택 규칙만 소유한다.

1.1 유지되는 항목

  • 기존 PUT method와 path를 유지한다.
  • 기존 bearer 인증, Accept-Language, 성공 envelope, 오류 status·key를 유지한다.
  • 캐릭터·오디오 콘텐츠·커뮤니티 게시글·시리즈는 multipart/form-data를 유지한다.
  • multipart JSON part 이름은 request, MIME은 application/json이다.
  • FanTalk 답글은 application/json body를 유지한다.

1.2 변경 판정

  1. 상세·목록 응답으로 form을 초기화할 때 수정 기준값을 보존한다.
  2. 현재 form 값과 기준값에 같은 기존 직렬화 규칙을 적용한다.
  3. 문자열 trim, 빈 optional 값의 null 변환, 배열·객체 배열 변환 후 필드별 값을 비교한다.
  4. 값이 다른 field만 request object에 포함한다.
  5. 사용자가 값을 바꾼 뒤 기준값으로 되돌리면 해당 field를 생략한다.

비교 대상은 각 기능의 update DTO field다. route ID, 조회 전용 field, 서버 계산값과 수정 화면에 없는 field를 request에 복사하지 않는다.

1.3 생략, null, falsy 값

표현 의미 예시
key 생략 미변경 { "title": "새 제목" }에는 detail 변경 없음
null 해당 DTO가 허용하는 기존 값 삭제 { "writer": null }
false boolean 값을 false로 변경 { "isAdult": false }
0 숫자 값을 0으로 변경 { "price": 0 }
배열·객체 배열 해당 필드 전체의 새 값 { "publishedDaysOfWeek": ["RANDOM"] }

false, 0, 빈값 삭제용 null은 falsy 값이라는 이유로 생략하지 않는다.

1.4 변경 없음

  • 변경 field와 교체 file이 모두 0개면 저장 control은 native disabled 상태다.
  • disabled 상태에서는 API helper를 호출하지 않는다.
  • 빈 JSON 또는 빈 multipart mutation을 전송하지 않는다.

1.5 파일 part

상태 파일 part request JSON
텍스트 field만 변경 생략 변경 field만 포함
파일과 field 변경 새 파일 1개 변경 field만 포함
파일만 변경 새 파일 1개 {}
변경 없음 요청 자체 없음 요청 자체 없음

기존 파일을 선택하지 않으면 서버의 현재 파일을 유지한다. 파일 삭제 기능은 이 계약에 추가하지 않는다.

2. 기능별 계약

2.1 AI 캐릭터

PUT /api/v2/admin/ai-characters/{characterId}

  • Content-Type: multipart/form-data
  • optional file part: image
  • JSON part: request
  • 비교 가능 field: name, systemPrompt, description, age, gender, mbti, speechPattern, speechStyle, appearance, originalTitle, originalLink, originalWorkId, characterType, tags, hobbies, values, goals, relationships, personalities, backgrounds, memories
  • 금지 field: region, 일반 수정의 isActive
  • 기존 예외: 원작 미선택·선택 해제의 originalWorkId는 현재 serializer 계약대로 key를 생략하며, 원작 연결 해제 기능은 추가하지 않는다.

이름만 변경:

{
  "name": "루나 수정"
}

태그를 모두 삭제:

{
  "tags": null
}

2.2 오디오 콘텐츠

PUT /api/v2/admin/ai-characters/{characterId}/audio-contents/{contentId}

  • Content-Type: multipart/form-data
  • optional file part: coverImage
  • JSON part: request
  • 수정 화면 비교 field: title, detail, tags, price
  • 일반 수정 금지 field: isActive
  • 화면에 없는 isAdult, isPointAvailable, isCommentAvailable은 상세 응답에서 복사하지 않는다.

상세 설명만 변경:

{
  "detail": "수정한 상세 설명"
}

가격만 무료로 변경:

{
  "price": 0
}

2.3 커뮤니티 게시글

PUT /api/v2/admin/ai-characters/{characterId}/community-posts/{postId}

  • Content-Type: multipart/form-data
  • optional file part: postImage
  • JSON part: request
  • 수정 저장 비교 field: content, isCommentAvailable, isAdult
  • 수정 저장 금지 field: isFixed, isActive
  • isFixed 전환과 soft delete는 기존 전용 action payload를 유지한다.

내용만 변경:

{
  "content": "수정한 게시글 내용"
}

댓글 허용만 끄기:

{
  "isCommentAvailable": false
}

2.4 시리즈

PUT /api/v2/admin/ai-characters/{characterId}/series/{seriesId}

  • Content-Type: multipart/form-data
  • optional file part: image
  • JSON part: request
  • 비교 field: title, introduction, publishedDaysOfWeek, genreId, isAdult, state, writer, studio
  • 일반 수정 금지 field: isActive, create-only keyword

제목만 변경:

{
  "title": "달빛 상담 시리즈 수정"
}

작가를 삭제:

{
  "writer": null
}

2.5 FanTalk 답글

PUT /api/v2/admin/ai-characters/{characterId}/fan-talks/{fanTalkId}/replies/{replyId}

  • Content-Type: application/json
  • 비교 field: content
  • 일반 답글 수정 금지 field: isActive

답글 변경:

{
  "content": "수정한 답글입니다."
}

content가 기존 답글과 같으면 수정 button은 disabled이고 request를 보내지 않는다.

3. 응답과 오류

응답과 오류 계약은 변경하지 않는다.

기능 성공 data
캐릭터·오디오 콘텐츠·커뮤니티 게시글·시리즈 기존 null success data
FanTalk 답글 기존 FanTalkListItem update response
  • validation, 401, 403, 404, 406, 415, 500 처리는 정식 OpenAPI와 기존 공통 API client를 따른다.
  • 부분 request 도입을 이유로 새로운 status, errorProperty 또는 자동 retry를 만들지 않는다.

4. Contract 검증 예시

시나리오 필수 assertion
title만 변경 request key가 title 하나다.
detail만 변경 request key가 detail 하나다.
boolean을 false로 변경 해당 key와 false가 존재한다.
nullable field 삭제 해당 key와 null이 존재한다.
변경 후 원복 저장 disabled, mutation 0건이다.
파일만 변경 파일 part 1개, request {}다.
파일 미변경 파일 part가 없다.

5. 범위 밖 mutation 회귀 계약

다음 기존 요청은 payload 최적화 대상이 아니며 현재 contract를 유지한다.

  • 캐릭터·오디오 콘텐츠·시리즈 비활성화: { "isActive": false }
  • 커뮤니티 게시글 고정 전환: { "isFixed": boolean }
  • 커뮤니티 게시글 soft delete: 기존 { "isActive": false, "isFixed": false }
  • 시리즈 순서 변경: { "ids": number[] }
  • FanTalk 원글 삭제: body 없는 DELETE