Skip to content

Commit dd95026

Browse files
authored
Merge pull request #13 from BusanHackathon/feature/#4-diagnosis
feature: 진단하기 api 제작 및 스웨거 예시까지 추가
2 parents 9961afc + c256ad0 commit dd95026

21 files changed

Lines changed: 642 additions & 3 deletions

src/main/java/com/busan/config/security/SecurityConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
6868
// 공개 엔드포인트
6969
.requestMatchers(
7070
"/swagger", "/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**",
71-
"/h2-console/**"
71+
"/h2-console/**", "/api/**"
7272
).permitAll()
7373
.requestMatchers("/api/auth/**", "/login/**", "/oauth2/**").permitAll()
7474
.anyRequest().authenticated())
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package com.busan.controller;
2+
3+
import com.busan.dto.common.Response;
4+
import com.busan.dto.diagnosis.DiagnosisRequestDTO;
5+
import com.busan.dto.diagnosis.DiagnosisResponseDTO;
6+
import io.swagger.v3.oas.annotations.Operation;
7+
import io.swagger.v3.oas.annotations.media.Content;
8+
import io.swagger.v3.oas.annotations.media.ExampleObject;
9+
import io.swagger.v3.oas.annotations.media.Schema;
10+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
11+
import io.swagger.v3.oas.annotations.tags.Tag;
12+
import lombok.RequiredArgsConstructor;
13+
import org.springframework.http.ResponseEntity;
14+
import org.springframework.web.bind.annotation.*;
15+
16+
@Tag(name = "Diagnosis", description = "진단하기(합성 API)")
17+
@RestController
18+
@RequiredArgsConstructor
19+
@RequestMapping("/api")
20+
public class DiagnosisController {
21+
22+
private final com.busan.service.DiagnosisService diagnosisService;
23+
24+
/**
25+
* 진단하기 버튼 액션.
26+
* - 주소/상세주소/주택유형/전세금만 받아서
27+
* - 위험도 요약 + 임대인 + 신뢰도 + 임대인 매물 리스트를 한 번에 반환
28+
*/
29+
@Operation(
30+
summary = "진단하기",
31+
description = """
32+
주소/상세주소/주택유형/전세금으로 대상 매물을 식별하고,
33+
위험도 요약·임대인 정보·임대인 신뢰도·임대인 소유 매물 목록을 한 번에 반환합니다.
34+
"""
35+
)
36+
@ApiResponse(
37+
responseCode = "200",
38+
description = "성공",
39+
content = @Content(
40+
mediaType = "application/json",
41+
// 제네릭 Response<T>를 정확히 타입으로 매핑하기 어렵다면 example로 보여주는 게 가장 실용적입니다.
42+
examples = @ExampleObject(
43+
name = "성공 응답 예시",
44+
value = """
45+
{
46+
"data": {
47+
"riskSummary": {
48+
"score": 15,
49+
"grade": "위험",
50+
"factors": [
51+
{ "name": "전세가율", "percent": 20 },
52+
{ "name": "가격하락", "percent": 33 },
53+
{ "name": "미분양(재고)", "percent": 13 },
54+
{ "name": "정책/규제", "percent": 20 },
55+
{ "name": "법적 리스크", "percent": 13 }
56+
]
57+
},
58+
"landlord": {
59+
"landlordId": 1,
60+
"name": "홍길동",
61+
"normalizedKey": "부산-사업자번호-해시",
62+
"ownedCount": 1,
63+
"grade": "A",
64+
"createdAt": "2025-08-21T02:26:22.055226",
65+
"updatedAt": "2025-08-21T02:26:22.055226"
66+
},
67+
"landlordTrust": {
68+
"trustScore": 85,
69+
"subrogationCount": 0,
70+
"arrearsCount": 0,
71+
"litigationCount": 0,
72+
"ownedUnsoldCount": 2,
73+
"grade": "A"
74+
},
75+
"landlordPlaces": [
76+
{
77+
"placeId": 1,
78+
"label": "부산광역시 해운대구 센텀동로 45",
79+
"address": "부산광역시 해운대구 센텀동로 45",
80+
"addressDetail": "101동 1001호"
81+
}
82+
]
83+
},
84+
"status": "SUCCESS",
85+
"serverDateTime": "2025-08-21T02:28:11.398139",
86+
"errorCode": null,
87+
"errorMessage": null
88+
}
89+
"""
90+
)
91+
)
92+
)
93+
@PostMapping("/diagnosis")
94+
public ResponseEntity<Response<DiagnosisResponseDTO>> diagnose(@RequestBody DiagnosisRequestDTO req) {
95+
var dto = diagnosisService.diagnose(
96+
req.getAddress(),
97+
req.getAddressDetail(),
98+
req.getHouseType(),
99+
req.getDeposit()
100+
);
101+
return ResponseEntity.ok(Response.success(dto));
102+
}
103+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.busan.dto.diagnosis;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
import lombok.NoArgsConstructor;
6+
import lombok.Setter;
7+
import com.busan.entity.enums.HouseType;
8+
import io.swagger.v3.oas.annotations.media.Schema;
9+
10+
@Getter
11+
@Setter
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Schema(description = "진단하기 요청 DTO")
15+
public class DiagnosisRequestDTO {
16+
17+
@Schema(description = "도로명/지번 주소", example = "부산광역시 해운대구 센텀동로 45")
18+
private String address;
19+
20+
@Schema(description = "상세 주소", example = "101동 1001호")
21+
private String addressDetail;
22+
23+
@Schema(
24+
description = "주택 유형",
25+
example = "OFFICETEL",
26+
allowableValues = {"APT", "OFFICETEL", "VILLA", "ONE_ROOM", "ETC"}
27+
)
28+
private HouseType houseType;
29+
30+
@Schema(description = "전세 보증금 (원 단위)", example = "50000000")
31+
private Long deposit;
32+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.busan.dto.diagnosis;
2+
3+
import com.busan.dto.landlord.LandlordCardDTO;
4+
import com.busan.dto.landlord.LandlordTrustDTO;
5+
import com.busan.dto.place.PlaceSimpleDTO;
6+
import com.busan.dto.risk.RiskSummaryDTO;
7+
import lombok.*;
8+
9+
import java.util.List;
10+
11+
/** “진단하기” 한 번 호출로 내려주는 합성 응답 */
12+
@Getter
13+
@Setter
14+
@NoArgsConstructor
15+
@AllArgsConstructor
16+
public class DiagnosisResponseDTO {
17+
private RiskSummaryDTO riskSummary; // 전세 계약 최종 위험 요약
18+
private LandlordCardDTO landlord; // 임대인 카드(기본 정보 요약)
19+
private LandlordTrustDTO landlordTrust; // 임대인 신뢰도 상세
20+
private List<PlaceSimpleDTO> landlordPlaces; // 임대인 소유 매물 리스트(일부)
21+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.busan.dto.landlord;
2+
3+
import lombok.*;
4+
5+
import java.time.LocalDateTime;
6+
7+
/** 좌상단 임대인 카드(이름/등급/보유채수 등) */
8+
@Getter @Setter @NoArgsConstructor @AllArgsConstructor
9+
public class LandlordCardDTO {
10+
private Long landlordId;
11+
private String name;
12+
private String normalizedKey;
13+
private int ownedCount; // 다주택자 N채
14+
private String grade; // "A" "B" "C"
15+
private LocalDateTime createdAt;
16+
private LocalDateTime updatedAt;
17+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.busan.dto.landlord;
2+
3+
import lombok.*;
4+
5+
@Getter
6+
@Setter
7+
@NoArgsConstructor
8+
@AllArgsConstructor
9+
public class LandlordTrustDTO {
10+
private long trustScore; // 신뢰도 원점수
11+
private long subrogationCount; // 대위변제
12+
private long arrearsCount; // 체납/미납
13+
private long litigationCount; // 분쟁/소송
14+
private long ownedUnsoldCount; // 보유 미분양
15+
private String grade; // "A/B/C" 등
16+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.busan.dto.place;
2+
3+
import lombok.*;
4+
5+
@Getter
6+
@Setter
7+
@NoArgsConstructor
8+
@AllArgsConstructor
9+
public class PlaceSimpleDTO {
10+
private Long placeId;
11+
private String label; // 프론트 표시용 간단 라벨(건물이름/동 등)
12+
private String address;
13+
private String addressDetail;
14+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.busan.dto.risk;
2+
3+
import lombok.*;
4+
5+
@Getter
6+
@Setter
7+
@NoArgsConstructor
8+
@AllArgsConstructor
9+
public class KeyFactorDTO {
10+
private String name; // "전세가율"
11+
private int percent; // 0~100
12+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.busan.dto.risk;
2+
3+
import lombok.*;
4+
5+
import java.util.List;
6+
7+
/** 게이지 + 핵심 위험 요인 섹션 */
8+
@Getter
9+
@Setter
10+
@NoArgsConstructor
11+
@AllArgsConstructor
12+
public class RiskSummaryDTO {
13+
private int score; // 0~100
14+
private String grade; // "양호" / "주의" / "위험"
15+
private List<KeyFactorDTO> factors;// 우측 리스트용 (요인명+기여도%)
16+
}
Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,35 @@
11
package com.busan.entity;
22

3-
public class Checklist {
4-
}
3+
import jakarta.persistence.*;
4+
import lombok.*;
5+
6+
@Entity
7+
@Table(name = "checklist")
8+
@Getter
9+
@NoArgsConstructor
10+
@AllArgsConstructor
11+
@Builder
12+
public class Checklist extends BaseTimeEntity {
13+
@Id
14+
@GeneratedValue(strategy = GenerationType.IDENTITY)
15+
@Column(name = "checkId")
16+
private Long checkId;
17+
18+
/** 작성자 */
19+
@ManyToOne(fetch = FetchType.LAZY)
20+
@JoinColumn(name = "userId", nullable = false) // 이미지 표기 'id'가 모호해서 명확히 user_id로 둠
21+
private Users user;
22+
23+
/** 대상 장소 */
24+
@ManyToOne(fetch = FetchType.LAZY)
25+
@JoinColumn(name = "placeId", nullable = true)
26+
private Place place;
27+
28+
/** 생성된 PDF 경로 */
29+
@Column(name = "pdfUrl", nullable = false, length = 255)
30+
private String pdfUrl;
31+
32+
/** 체크리스트 JSON */
33+
@Column(name = "checklistJson", nullable = false, columnDefinition = "json")
34+
private String checklistJson;
35+
}

0 commit comments

Comments
 (0)