Skip to content

Commit b57add6

Browse files
[FEAT]: 시나리오 Controller & DTO 작성 (#16)
* [Refactor] constraintsJson -> generationContext 변수명변경 * [Refactor] scenario entity 컬럼 ë�변경 * [Feat] 시나리오 DTO작성 * [Feat] 시나리오 controller 작성
1 parent 009fb36 commit b57add6

File tree

10 files changed

+322
-18
lines changed

10 files changed

+322
-18
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@ db.txt
44
log.txt
55

66
# Claude Code
7-
CLAUDE.md
7+
CLAUDE.md
8+
9+
# DB
10+
db_dev.mv.db
Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,100 @@
11
package com.back.domain.scenario.controller;
22

3+
import com.back.domain.scenario.dto.*;
4+
import com.back.domain.scenario.entity.ScenarioStatus;
35
import com.back.domain.scenario.service.ScenarioService;
6+
import com.back.global.common.ApiResponse;
7+
import io.swagger.v3.oas.annotations.Operation;
8+
import io.swagger.v3.oas.annotations.Parameter;
9+
import io.swagger.v3.oas.annotations.tags.Tag;
10+
import jakarta.validation.Valid;
411
import lombok.RequiredArgsConstructor;
5-
import org.springframework.web.bind.annotation.RequestMapping;
6-
import org.springframework.web.bind.annotation.RestController;
12+
import org.springframework.http.HttpStatus;
13+
import org.springframework.web.bind.annotation.*;
14+
import java.security.Principal;
15+
import java.time.LocalDateTime;
16+
import java.util.List;
717

818
/**
919
* 시나리오 관련 API 요청을 처리하는 컨트롤러.
1020
* 시나리오 추출, 상세 조회, 비교 등의 기능을 제공합니다.
1121
*/
22+
@Tag(name = "Scenario", description = "시나리오 관련 API")
1223
@RestController
1324
@RequestMapping("/api/v1/scenarios")
1425
@RequiredArgsConstructor
1526
public class ScenarioController {
1627

1728
private final ScenarioService scenarioService;
1829

30+
@PostMapping
31+
@Operation(summary = "시나리오 생성", description = "DecisionLine을 기반으로 AI 시나리오를 생성합니다.")
32+
public ApiResponse<Long> createScenario(
33+
@Valid @RequestBody ScenarioCreateRequest request,
34+
Principal principal
35+
) {
36+
// Mock: 실제로는 scenarioService.createScenario(request, principal) 호출
37+
return ApiResponse.success(1001L, "시나리오 생성 요청이 접수되었습니다.", HttpStatus.CREATED);
38+
}
39+
40+
@GetMapping("/{scenarioId}/status")
41+
@Operation(summary = "시나리오 상태 조회", description = "시나리오 생성 진행 상태를 조회합니다.")
42+
public ApiResponse<ScenarioStatusResponse> getScenarioStatus(
43+
@Parameter(description = "시나리오 ID") @PathVariable Long scenarioId
44+
) {
45+
// Mock
46+
ScenarioStatusResponse mockResponse = new ScenarioStatusResponse(
47+
scenarioId,
48+
ScenarioStatus.PROCESSING,
49+
"AI가 시나리오를 생성 중입니다..."
50+
);
51+
return ApiResponse.success(mockResponse, "상태를 성공적으로 조회했습니다.");
52+
}
53+
54+
@GetMapping("/info/{scenarioId}")
55+
@Operation(summary = "시나리오 상세 조회", description = "완성된 시나리오의 상세 정보를 조회합니다.")
56+
public ApiResponse<ScenarioDetailResponse> getScenarioDetail(
57+
@Parameter(description = "시나리오 ID") @PathVariable Long scenarioId
58+
) {
59+
// Mock: 실제로는 큰 DTO라서 null로 처리하거나 간단한 Mock 생성
60+
return ApiResponse.success(null, "시나리오 상세 정보를 성공적으로 조회했습니다.");
61+
}
62+
63+
@GetMapping("/{scenarioId}/timeline")
64+
@Operation(summary = "시나리오 타임라인 조회", description = "시나리오의 선택 경로를 시간순으로 조회합니다.")
65+
public ApiResponse<TimelineResponse> getScenarioTimeline(
66+
@Parameter(description = "시나리오 ID") @PathVariable Long scenarioId
67+
) {
68+
// Mock 타임라인 생성
69+
List<TimelineResponse.TimelineEvent> mockEvents = List.of(
70+
new TimelineResponse.TimelineEvent(2020, "창업 도전"),
71+
new TimelineResponse.TimelineEvent(2022, "해외 진출"),
72+
new TimelineResponse.TimelineEvent(2025, "상장 성공")
73+
);
74+
TimelineResponse mockResponse = new TimelineResponse(scenarioId, mockEvents);
75+
return ApiResponse.success(mockResponse, "타임라인을 성공적으로 조회했습니다.");
76+
}
77+
78+
@GetMapping("/baselines")
79+
@Operation(summary = "베이스라인 목록 조회", description = "사용자의 베이스라인 목록을 조회합니다.")
80+
public ApiResponse<List<BaselineListResponse>> getBaselines(
81+
Principal principal
82+
) {
83+
// Mock 베이스라인 목록
84+
List<BaselineListResponse> mockBaselines = List.of(
85+
new BaselineListResponse(1001L, "대학 졸업 이후", List.of("교육", "진로"), LocalDateTime.now()),
86+
new BaselineListResponse(1002L, "미국 대학 이후", List.of("해외", "교육"), LocalDateTime.now())
87+
);
88+
return ApiResponse.success(mockBaselines, "베이스라인 목록을 성공적으로 조회했습니다.");
89+
}
90+
91+
@GetMapping("/compare/{baseId}/{compareId}")
92+
@Operation(summary = "시나리오 비교 분석 결과 조회", description = "두 시나리오를 비교 분석 결과를 조회합니다.")
93+
public ApiResponse<ScenarioCompareResponse> compareScenarios(
94+
@Parameter(description = "기준 시나리오 ID") @PathVariable Long baseId,
95+
@Parameter(description = "비교 시나리오 ID") @PathVariable Long compareId
96+
) {
97+
// Mock: 복잡한 DTO라서 null 처리
98+
return ApiResponse.success(null, "시나리오 비교를 성공적으로 조회했습니다.");
99+
}
19100
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.back.domain.scenario.dto;
2+
3+
import com.back.domain.node.entity.BaseLine;
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
6+
import java.time.LocalDateTime;
7+
import java.util.List;
8+
9+
/**
10+
* 베이스라인 목록 조회 응답 DTO.
11+
* 사용자의 현재 삶 시작점들을 목록으로 제공합니다.
12+
*/
13+
14+
public record BaselineListResponse(
15+
@Schema(description = "베이스라인 ID", example = "1001")
16+
Long baselineId,
17+
18+
@Schema(description = "베이스라인 제목", example = "대학 졸업 후 진로 선택")
19+
String title,
20+
21+
@Schema(description = "베이스라인 관련 태그", example = "[\"교육\", \"진로\", \"취업\"]")
22+
List<String> tags,
23+
24+
@Schema(description = "베이스라인 생성일", example = "2024-09-17T14:30:00")
25+
LocalDateTime createdDate
26+
) {
27+
/**
28+
* BaseLine 엔티티로부터 BaselineListResponse를 생성합니다.
29+
* @param baseLine BaseLine 엔티티
30+
* @param tags 관련 태그 목록
31+
* @return BaselineListResponse
32+
*/
33+
34+
public static BaselineListResponse from(BaseLine baseLine, List<String> tags) {
35+
throw new UnsupportedOperationException("구현 예정");
36+
}
37+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.back.domain.scenario.dto;
2+
3+
import com.back.domain.scenario.entity.Scenario;
4+
import com.back.domain.scenario.entity.SceneCompare;
5+
import com.back.domain.scenario.entity.SceneType;
6+
import com.back.domain.scenario.entity.Type;
7+
import io.swagger.v3.oas.annotations.media.Schema;
8+
9+
import java.util.List;
10+
11+
/** │ │
12+
* 두 시나리오 간의 비교 분석 결과를 담는 응답 DTO. │ │
13+
* 기준 시나리오와 비교 시나리오의 5개 지표별 점수 비교와 AI 분석 결과를 제공합니다. │ ││ │
14+
*/
15+
16+
public record ScenarioCompareResponse(
17+
@Schema(description = "비교 기준이 되는 시나리오 ID", example = "1001")
18+
Long baseScenarioId,
19+
20+
@Schema(description = "비교 대상 시나리오 ID", example = "1002")
21+
Long compareScenarioId,
22+
23+
@Schema(description = "AI가 생성한 두 시나리오의 종합 비교 분석", example = "평행우주에서는 창업을 선택하여 더 높은 경제적 성과와 성취감을 얻었지만, 초기 불안정성과 스트레스가 증가했습니다. 전반적으로 위험을 감수한 만큼 더 큰 보상을 얻은 결과를 보여줍니다.")
24+
String overallAnalysis,
25+
26+
@Schema(description = "5개 지표별 상세 비교 결과", example = "[{\"type\":\"경제\",\"baseScore\":65,\"compareScore\":85,\"analysis\":\"창업 성공으로 20점 향상\"}]")
27+
List<IndicatorComparison> indicators
28+
) {
29+
30+
public record IndicatorComparison(
31+
@Schema(description = "비교 지표 유형", example = "경제")
32+
Type type,
33+
34+
@Schema(description = "기준 시나리오의 해당 지표 점수", example = "65")
35+
int baseScore,
36+
37+
@Schema(description = "비교 시나리오의 해당 지표 점수", example = "85")
38+
int compareScore,
39+
40+
@Schema(description = "해당 지표에 대한 AI 비교 분석", example = "창업 성공으로 인한 수익 증가와 자산 형성으로 경제 지표가 크게 향상되었습니다.")
41+
String analysis
42+
) {}
43+
44+
public static ScenarioCompareResponse from(
45+
Scenario baseScenario,
46+
Scenario compareScenario,
47+
List<SceneCompare> compareResults,
48+
List<SceneType> baseIndicators,
49+
List<SceneType> compareIndicators
50+
) {
51+
throw new UnsupportedOperationException("구현 예정");
52+
}
53+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.back.domain.scenario.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import jakarta.validation.constraints.NotNull;
5+
6+
/**
7+
* 시나리오 생성 요청 DTO.
8+
* DecisionLine을 기반으로 AI 시나리오 생성을 요청합니다.
9+
*/
10+
11+
public record ScenarioCreateRequest(
12+
@Schema(description = "시나리오 생성의 기반이 될 대체선택 라인 ID", example = "1001")
13+
@NotNull(message = "대체선택 라인 ID는 필수입니다.")
14+
Long decisionLineId
15+
) {
16+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.back.domain.scenario.dto;
2+
3+
import com.back.domain.scenario.entity.ScenarioStatus;
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
import java.time.LocalDateTime;
6+
import java.util.List;
7+
8+
/**
9+
* 시나리오 상세 조회 응답 DTO.
10+
* AI가 생성한 시나리오의 모든 상세 정보와 5개 지표 분석 결과를 포함합니다.
11+
*/
12+
13+
public record ScenarioDetailResponse(
14+
@Schema(description = "시나리오 ID", example = "1001")
15+
Long scenarioId,
16+
17+
@Schema(description = "시나리오 생성 상태", example = "COMPLETED")
18+
ScenarioStatus status,
19+
20+
@Schema(description = "시나리오 최종 직업", example = "AI 연구원")
21+
String job,
22+
23+
@Schema(description = "시나리오 지표 점수 총합", example = "500")
24+
int total,
25+
26+
@Schema(description = "시나리오 결과 요약", example = "당신은 성공적인 AI 연구자가 되어 학계와 업계에서 인정받으며, 균형 잡힌 삶을 살고 있습니다.")
27+
String summary,
28+
29+
@Schema(description = "시나리오 결과 상세", example = "10년 후, 당신은 세계적으로 인정받는 AI 연구소의 수석 연구원이 되었습니다. 혁신적인 연구 성과로 다수의 논문을 발표하며, 안정적인 수입과 함께 의미 있는 일을 하고 있습니다. 또한 규칙적인 운동과 취미 생활로 건강하고 행복한 일상을 유지하고 있습니다.")
30+
String description,
31+
32+
@Schema(description = "시나리오 결과 이미지 URL", example = "https://example.com/scenario-images/successful-researcher.jpg")
33+
String img,
34+
35+
@Schema(description = "시나리오 생성일자", example = "2024-01-15T14:30:00")
36+
LocalDateTime createdDate,
37+
38+
@Schema(description = "시나리오 결과 지표 정보", example = "[{\"type\":\"경제\",\"point\":85,\"analysis\":\"안정적인 연구직 수입\"}, {\"type\":\"행복\",\"point\":90,\"analysis\":\"의미 있는 일을 통한 성취감\"}]")
39+
List<ScenarioTypeDto> indicators
40+
) {
41+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.back.domain.scenario.dto;
2+
3+
import com.back.domain.scenario.entity.ScenarioStatus;
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
6+
/**
7+
* 시나리오 생성 상태 조회 응답 DTO.
8+
* 폴링 방식의 실시간 상태 확인을 위한 경량화된 응답 구조입니다.
9+
*/
10+
11+
public record ScenarioStatusResponse(
12+
@Schema(description = "시나리오 ID", example = "1001")
13+
Long scenarioId,
14+
15+
@Schema(description = "시나리오 생성 상태", example = "PROCESSING")
16+
ScenarioStatus status,
17+
18+
@Schema(description = "상태별 안내 메시지", example = "AI가 대체선택 라인을 분석 중입니다...")
19+
String message
20+
) {
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.back.domain.scenario.dto;
2+
3+
import com.back.domain.scenario.entity.Type;
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
6+
/**
7+
* 시나리오 지표별 분석 결과 DTO.
8+
* 경제, 행복, 관계, 직업, 건강 각 지표의 점수와 상세 분석을 포함합니다.
9+
*/
10+
11+
public record ScenarioTypeDto(
12+
@Schema(description = "시나리오 결과 지표 유형", example = "경제")
13+
Type type,
14+
15+
@Schema(description = "시나리오 결과 지표 유형별 점수", example = "50")
16+
int point,
17+
18+
@Schema(description = "시나리오 결과 지표 유형별 분석", example = "연구 성과로 인한 안정적인 수입과 지속적인 성장 기회를 확보했습니다.")
19+
String analysis
20+
) {
21+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.back.domain.scenario.dto;
2+
3+
import com.back.domain.node.entity.DecisionNode;
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
import java.util.List;
6+
7+
/**
8+
* 시나리오의 타임라인 정보를 담는 응답 DTO.
9+
* DecisionLine의 DecisionNode들을 시간순으로 정렬한 이벤트 목록을 제공합니다.
10+
* 비교 화면에서는 이 API를 두 번 호출하여 클라이언트에서 조합합니다.
11+
*/
12+
13+
public record TimelineResponse(
14+
@Schema(description = "타임라인이 속한 시나리오 ID", example = "1001")
15+
Long scenarioId,
16+
17+
@Schema(description = "시간순으로 정렬된 타임라인 이벤트 목록", example = "[{\\\"year\\\":2020,\\\"title\\\":\\\"창업 도전\\\"},{\\\"year\\\":2022,\\\"title\\\":\\\"해외 진출\\\"},{\\\"year\\\":2025,\\\"title\\\":\\\"상장 성공\\\"}]")
18+
List<TimelineEvent> events
19+
) {
20+
public record TimelineEvent(
21+
@Schema(description = "이벤트 발생 연도", example = "2022")
22+
int year,
23+
24+
@Schema(description = "AI가 생성한 이벤트 제목 (3-5단어)\", example = \"해외 진출 성공")
25+
String title
26+
) {}
27+
28+
/**
29+
* Scenario의 DecisionLine으로부터 TimelineResponse를 생성합니다.
30+
* @param scenarioId 시나리오 ID
31+
* @param decisionNodes DecisionLine의 DecisionNode 목록 (시간순 정렬됨)
32+
* @return TimelineResponse
33+
*/
34+
35+
public static TimelineResponse from(Long scenarioId, List<DecisionNode> decisionNodes) {
36+
throw new UnsupportedOperationException("구현 예정");
37+
}
38+
}

0 commit comments

Comments
 (0)