세계관의 완성본에 고정된 꿈별 이야기·인접 연결 문장을 날짜순으로 읽어 한 장의 이미지를 만든다. 선택 목록 편집, 원문 수정, 새 이야기 생성, 세계관 부분 반영, 꿈 삭제만으로 AI를 호출하지 않는다. 개별 꿈 이미지의 API·저장 행·과금 출처와 분리하고 이미지 Provider, S3, 실행 자원, 크레딧 원장, 파일 정리 워커는 재사용한다.
완성본에 꿈이 2개 이상이면 생성할 수 있다. 최초 세계관 완성본 생성의 최소 꿈 수 2개 계약은 유지한다. 삭제로 0~1개가 된 세계관도 폴더와 기존 이미지는 유지하지만, 신규 생성·재생성은 WORLD_IMAGE_409_1로 거절한다. 없는 꿈을 추정하거나 과거 삭제 원문으로 생성하지 않는다.
생성 중·실패 시 마지막 성공 이미지를 유지한다. 꿈 삭제도 세계관 이미지를 지우지 않으며 sourceDeleted=true를 제공한다. 세계관 폴더 자체를 삭제하면 이미지 DB 기록·출처 식별자를 제거하고 파일 정리를 예약한다. 이미 확정한 이미지 비용은 꿈/세계관 삭제로 반환하지 않는다.
온보딩을 완료한 Bearer 인증을 사용한다. 본인 소유만 접근하고 응답은 Cache-Control:no-store다. 다른 사용자의 세계관과 없는 세계관은 같은 404다.
| 메서드 | 경로 | 용도 |
|---|---|---|
| POST | /api/v1/worlds/{worldId}/image |
생성·명시적 재생성 |
| GET | /api/v1/worlds/{worldId}/image |
상태·마지막 성공 메타데이터 |
| GET | /api/v1/worlds/{worldId}/image/download-url |
마지막 성공 이미지의 최대 5분 HTTPS URL |
생성 요청 예시의 값은 형식 설명용이다. compositionRevision은 최신 세계관 완성본 조회 값이다. 폴더 revision 또는 생성 작업 jobVersion으로 대체하지 않는다.
{"compositionRevision":1,"style":"watercolor","mood":null,"regenerate":false}style/mood는 기존 /api/v1/image-options의 허용 키를 사용한다. 다른 구성/옵션으로 바꾸거나 명시적으로 다시 만들려면 regenerate=true, GET 이미지 응답의 최신 imageVersion을 전달한다. 재생성에는 현재 세계관의 compositionRevision을 전달한다.
개별 이미지와 같은 비동기 실행 계약이다. 새 요청의 HTTP 응답은 검증·업로드·DB 완료를 기다린 뒤 200을 반환한다. 동일 입력의 이미 진행 중인 요청은 추가 호출 없이 202/PROCESSING을 반환한다. 영속 접수 대기열을 추가한 즉시-202 API가 아니다. 호출 한도를 초과하면 IMAGE_503_2다. HTTP 연결 종료가 내부 완료 처리를 취소하지 않는다. 제공자 POST는 자동 재전송하지 않는다.
같은 구성·표현 옵션의 기존 성공 결과는 무료 재사용한다. 이 경우 기능/과금이 비활성화되어도 조회·재사용할 수 있다. 구성이 바뀐 기존 이미지는 GET으로 볼 수 있지만 regenerate=false인 POST로 조용히 새로 생성하지 않는다(WORLD_IMAGE_409_3). 동일 재생성의 완료 후 옛 imageVersion을 재전송하면 409다.
compositionRevision: 현재/마지막 생성 시도의 입력 구성 버전.resultCompositionRevision: 화면에 표시할 마지막 성공 이미지의 입력 구성 버전. 성공이 없으면 null.compositionChanged: 마지막 성공 이미지(없으면 현재 시도)의 구성 버전과 현재 세계관 구성이 다름.sourceChanged: 보존 이미지가 사용한 이야기의 입력 버전과 현재 꿈 원문·감정 버전이 다름.sourceDeleted: 보존 이미지의 출처 꿈이 삭제됨. “삭제 전 구성으로 생성된 이미지” 안내를 표시한다. 현재 완성본에서 이미 빠진 꿈도 이미지 출처에 남아 있었다면 표시한다.hasPreviousResult: 현재 시도가 진행/실패 중이지만 표시할 이전 성공 파일이 있음. false인 COMPLETED 결과도 정상 성공 파일을 가진다.style/mood는 현재 시도,resultStyle/resultMood는 마지막 성공 이미지의 옵션이다.
원문 수정 안내는 “수정 전 기록으로 생성된 이미지”, 부분 반영 등 구성 변경 안내는 “변경 전 세계관으로 생성된 이미지”로 표현할 수 있다. 안내 UI는 프론트에서 구현한다. GET/다운로드는 AI 호출·크레딧 차감이 없다. 원본 수정 때문에 기존 세계관 이야기를 최신 버전으로 임의 교체하지 않는다.
유료 시도는 WORLD_IMAGE_GENERATION과 WORLD_IMAGE_REGENERATION에 설정된 양을 사용한다. 기본값은 최초3·이후 재생성1이며 첫 재생성 성공1회는 무료다. 무료 시도에는 잔액을 요구하지 않는다. 유료 잔액 부족·단가 미설정·Provider/스토리지 미준비·큰 입력은 외부 호출 전에 거절한다.
사용자 행 잠금 안에서 시도와 예약을 함께 저장하고 잠금을 놓은 뒤 외부 IO를 실행한다. 성공 파일 공개와 사용 확정은 같은 트랜잭션이다. 실패·구성 변경·삭제·만료·결제 사용 보류는 새 성공을 공개하지 않고 예약을 해제한다. DB 저장 실패도 새 결과·사용 확정을 롤백하고 이전 성공을 유지한다. 제공자에게 이미 발생한 외부 비용을 취소한다는 뜻은 아니다.
이야기·연결 원문은 생성 요청 중에만 입력으로 사용한다. 출처 테이블은 꿈 ID·이야기 버전 ID·AI 입력 버전·연결 ID만 저장하며 본문을 복제하지 않는다. 꿈 삭제 시 보존 이미지의 삭제 안내를 남기고 해당 출처 식별자도 제거한다.
이미지 생성 도중 원본 꿈 수정은 허용한다. 고정된 세계관 완성본 자체가 바뀌지 않았다면 생성할 수 있고, sourceChanged로 알려준다. 도중에 완성본 교체·부분 반영·꿈 삭제가 일어나 입력 구성이 바뀌면 새 결과를 공개하지 않는다. 진행 중인 세계관 생성/부분 반영 동안 새 이미지 시도는 WORLD_IMAGE_409_4다. 이전 성공 조회·재사용은 계속 가능하다.
기존 이미지 복구 워커가 세계관 이미지의 2분 lease 만료도 제한된 배치로 처리한다. 재시작 후 AI를 재호출하지 않고 예약을 해제한다. 시도별 PNG/JPEG 정리 대상도 기록하여 늦은 완료가 결과를 복구하지 못하게 한다.
MONGLE_WORLD_IMAGE_ENABLED: 신규 시도 허용, 기본 true. 실제 호출에는 기존 Provider/S3/크레딧 활성화와 각 비용 설정이 모두 필요하다.MONGLE_WORLD_IMAGE_MAX_INPUT_CHARACTERS: 세계관 이야기·연결의 JSON 입력 상한, 기본 24000, 허용 1000~24000. 큰 입력을 자동 AI 요약하거나 잘라내지 않고 WORLD_IMAGE_400_1로 거절한다. 최종 Provider 프롬프트의 기존 32000자 상한도 유지한다.MONGLE_CREDIT_WORLD_IMAGE_GENERATION,MONGLE_CREDIT_WORLD_IMAGE_REGENERATION: 신규 시도 비용. 기본값은 각각 3, 1이며 세계관별 첫 재생성 성공 1회는 무료다.- 기존 이미지 동시 호출/결과 처리 풀·Provider timeout·이미지 복구/정리 워커 설정을 공유한다. 개별 꿈 이미지와 세계관 이미지를 합쳐 동일 실행 한도를 적용한다.
전용 객체 키는 world-images/{userId}/{imageId}/{attemptId}.png|jpg다. S3 키 검증과 IAM 허용 경로에 이 접두사를 추가한다. 권한 예시를 참고한다. 버킷 공개 권한은 추가하지 않는다.
새 DB는 schema-initial.sql, 현재 31개 테이블의 기존 DB는 앱·모든 워커 중지와 백업 후 db/migrations/20261026-world-images.sql을 적용한다. world_images·world_image_sources를 추가하여 총 33개 테이블이 된다. IF NOT EXISTS는 기존 잘못된 테이블을 자동 수정하지 않으므로 Hibernate validate와 실제 컬럼/인덱스를 확인한다. 앱이 스키마를 자동 변경하지 않는다.
재생성 성공으로 교체된 파일, 폴더 삭제 파일, 만료/보상 삭제 실패 파일은 기존 정리 워커에 전달한다. 워커는 현재 세계관 성공 파일과 유효한 시도 객체를 보호한다. 개별 꿈 삭제로 보존 세계관 이미지를 정리 대상으로 등록하지 않는다. 실제 파일 정리는 S3와 정리 워커 활성화가 필요하며 DB 삭제 응답이 파일 삭제 완료를 뜻하지 않는다. 버킷 과거 객체 버전·영속 기록 전에 프로세스가 종료된 미참조 객체의 대조 회수는 기존 운영 책임을 유지한다.
통합 테스트에서 완성본/선택 목록 분리, 날짜순 입력, 유료 생성·재생성, 무료 재사용·중복, 결과 보존, 구성 변경·꿈/폴더 삭제·만료·DB 실패의 정합성과 HTTP 인증·소유권·입력·Swagger를 확인한다. 공유 Provider는 로컬 HTTP로 세계관 전용 프롬프트를 검증한다. 실제 OpenAI 이미지 품질·API 비용, AWS 파일 처리 및 운영 DB 적용은 별도 운영 검증이다.
2026-10-26, Java 21에서 전체 689개 테스트(실패/오류/스킵 0)와 bootJar 빌드가 통과했다. 신규 세계관 이미지 통합 17개·Provider HTTP 2개·마이그레이션 1개 및 S3 전용 경로 검증을 포함한다. Python 배포 검증 스크립트 구문·IAM JSON·git diff --check도 확인했다. 로컬 MySQL 실행 파일이 없어 네이티브 MySQL/RDS 검증은 이번 작업에서 실행하지 않았다.
새 이미지 생성·재생성·실패 재시도는 선택 목록이나 후보 목록이 아닌 완성본의 실제 출처에 서로 다른 꿈이 2개 이상 있어야 한다. 0~1개이면 외부 호출·시도 변경·크레딧 예약 전에 HTTP409 WORLD_IMAGE_409_1로 거절한다. 기존 완료 결과 재사용·상태 조회·다운로드는 종전 조건을 유지한다.
A·B 이미지 생성 뒤 B를 삭제하면 기존 이미지는 보존하고 sourceDeleted/compositionChanged를 안내한다. 남은 A만으로 새 이미지를 만들지는 않는다. 다른 꿈을 추가하고 완성본을 2개 이상으로 갱신하면 다시 생성할 수 있으며, 세계관의 무료 재생성 이력은 초기화하지 않는다. freeRegenerationAvailable/nextRegenerationCost는 이력·가격 안내이며 최소 출처 조건까지 보장하는 실행 허가가 아니다.
DB 구조·Flyway SQL·운영 기능 플래그 변경은 없다.
2026-10-29 검증: 일반 테스트 774개, 임시 MySQL 8.4.11 테스트 30개, 배포 스크립트 테스트 44개와 bootJar 빌드가 통과했다. 세계관 이미지 통합 테스트 28개에 최소 출처·거절 시 무변경·복구 후 무료 이력 유지·권한 경계를 포함하며, 실제 MySQL에서도 삭제 후 차단과 복구 후 무료→유료 흐름을 검증했다. 외부 OpenAI/S3 호출과 운영 환경 검증은 포함하지 않는다.
공통 정책에 따라 최초 생성 3크레딧, 세계관별 첫 재생성 성공 1회 무료, 이후 1크레딧이다. 응답은 freeRegenerationAvailable, nextRegenerationCost를 포함한다. 구성 교체·부분 반영·꿈 삭제는 무료 이력을 초기화하지 않는다. 무료 시도도 기존 만료·중복·결제 보류·이전 결과 보존 규칙을 따른다. 최신 신규/기존 DB는 Flyway로 생성/업데이트하며 이미지 정책은 V3로 적용한다. 앞의 날짜별 SQL 안내는 V1 이전 과거 참고용이다.