Skip to content

Commit 305c0cf

Browse files
authored
[Feat] #29 프로필 및 온보딩 API 구현
프로필 조회·수정과 온보딩 임시저장·완료 API를 구현했습니다. - 프로필 조회 및 수정 - 온보딩 단계별 부분 임시저장 및 조회 - 관심 직무, 대표 직무, 희망 지역 관리 - 필수 입력값 검증 및 온보딩 완료 처리 - 부분 임시저장 시 기존 데이터 유지 - 프로필 및 온보딩 통합 테스트 추가 - 최신 develop 병합 및 JpaConfig 충돌 해결 Closes #29
2 parents 5f63267 + 99054ba commit 305c0cf

18 files changed

Lines changed: 959 additions & 5 deletions
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.leets7th.job_is_be.domain.user.controller;
2+
3+
import com.leets7th.job_is_be.domain.user.dto.ProfileDraftRequest;
4+
import com.leets7th.job_is_be.domain.user.dto.ProfileDraftResponse;
5+
import com.leets7th.job_is_be.domain.user.dto.ProfileResponse;
6+
import com.leets7th.job_is_be.domain.user.dto.ProfileUpdateRequest;
7+
import com.leets7th.job_is_be.domain.user.service.ProfileService;
8+
import com.leets7th.job_is_be.global.response.ApiResponse;
9+
import com.leets7th.job_is_be.global.status.SuccessStatus;
10+
import org.springframework.http.ResponseEntity;
11+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
12+
import org.springframework.security.oauth2.jwt.Jwt;
13+
import org.springframework.web.bind.annotation.GetMapping;
14+
import org.springframework.web.bind.annotation.PutMapping;
15+
import org.springframework.web.bind.annotation.PostMapping;
16+
import org.springframework.web.bind.annotation.PatchMapping;
17+
import org.springframework.web.bind.annotation.RequestBody;
18+
import org.springframework.web.bind.annotation.RequestMapping;
19+
import org.springframework.web.bind.annotation.RestController;
20+
21+
@RestController
22+
@RequestMapping("/api/profile")
23+
public class ProfileController {
24+
25+
private final ProfileService profileService;
26+
27+
public ProfileController(ProfileService profileService) {
28+
this.profileService = profileService;
29+
}
30+
31+
@GetMapping
32+
public ResponseEntity<ApiResponse<ProfileResponse>> getProfile(
33+
@AuthenticationPrincipal Jwt jwt
34+
) {
35+
return ApiResponse.success(
36+
SuccessStatus.PROFILE_GET_SUCCESS,
37+
profileService.getProfile(userId(jwt))
38+
);
39+
}
40+
41+
@PatchMapping
42+
public ResponseEntity<ApiResponse<ProfileResponse>> updateProfile(
43+
@AuthenticationPrincipal Jwt jwt,
44+
@RequestBody ProfileUpdateRequest request
45+
) {
46+
return ApiResponse.success(
47+
SuccessStatus.PROFILE_UPDATE_SUCCESS,
48+
profileService.updateProfile(userId(jwt), request)
49+
);
50+
}
51+
52+
@GetMapping("/draft")
53+
public ResponseEntity<ApiResponse<ProfileDraftResponse>> getDraft(
54+
@AuthenticationPrincipal Jwt jwt
55+
) {
56+
return ApiResponse.success(
57+
SuccessStatus.PROFILE_DRAFT_GET_SUCCESS,
58+
profileService.getDraft(userId(jwt))
59+
);
60+
}
61+
62+
@PutMapping("/draft")
63+
public ResponseEntity<ApiResponse<ProfileDraftResponse>> saveDraft(
64+
@AuthenticationPrincipal Jwt jwt,
65+
@RequestBody ProfileDraftRequest request
66+
) {
67+
return ApiResponse.success(
68+
SuccessStatus.PROFILE_DRAFT_SAVE_SUCCESS,
69+
profileService.saveDraft(userId(jwt), request)
70+
);
71+
}
72+
73+
@PostMapping("/onboarding/complete")
74+
public ResponseEntity<ApiResponse<Void>> completeOnboarding(
75+
@AuthenticationPrincipal Jwt jwt
76+
) {
77+
profileService.completeOnboarding(userId(jwt));
78+
return ApiResponse.success(SuccessStatus.PROFILE_ONBOARDING_COMPLETE_SUCCESS);
79+
}
80+
81+
private Long userId(Jwt jwt) {
82+
return Long.valueOf(jwt.getSubject());
83+
}
84+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.leets7th.job_is_be.domain.user.dto;
2+
3+
import com.leets7th.job_is_be.domain.user.enums.CareerLevel;
4+
import com.leets7th.job_is_be.domain.user.enums.OnboardingStep;
5+
6+
import java.util.List;
7+
8+
public record ProfileDraftRequest(
9+
OnboardingStep onboardingStep,
10+
List<Long> jobCategoryIds,
11+
Long primaryJobCategoryId,
12+
Long regionId,
13+
CareerLevel careerLevel,
14+
List<String> preferenceNotes,
15+
List<String> excludeKeywords,
16+
List<String> techStacks
17+
) {
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.leets7th.job_is_be.domain.user.dto;
2+
3+
import com.leets7th.job_is_be.domain.user.enums.CareerLevel;
4+
import com.leets7th.job_is_be.domain.user.enums.OnboardingStep;
5+
6+
import java.util.List;
7+
8+
public record ProfileDraftResponse(
9+
OnboardingStep onboardingStep,
10+
List<ProfileJobCategoryResponse> jobCategories,
11+
ProfileRegionResponse region,
12+
CareerLevel careerLevel,
13+
List<String> preferenceNotes,
14+
List<String> excludeKeywords,
15+
List<String> techStacks,
16+
boolean jobTestCompleted
17+
) {
18+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.leets7th.job_is_be.domain.user.dto;
2+
3+
public record ProfileJobCategoryResponse(
4+
Long id,
5+
String name,
6+
boolean primary
7+
) {
8+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.leets7th.job_is_be.domain.user.dto;
2+
3+
public record ProfileRegionResponse(Long id, String name) {
4+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.leets7th.job_is_be.domain.user.dto;
2+
3+
import com.leets7th.job_is_be.domain.user.enums.CareerLevel;
4+
5+
import java.time.LocalDateTime;
6+
import java.util.List;
7+
8+
public record ProfileResponse(
9+
Long userId,
10+
List<ProfileJobCategoryResponse> jobCategories,
11+
ProfileRegionResponse region,
12+
CareerLevel careerLevel,
13+
List<String> preferenceNotes,
14+
List<String> excludeKeywords,
15+
List<String> techStacks,
16+
boolean jobTestCompleted,
17+
boolean onboardingCompleted,
18+
LocalDateTime onboardingCompletedAt
19+
) {
20+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.leets7th.job_is_be.domain.user.dto;
2+
3+
import com.leets7th.job_is_be.domain.user.enums.CareerLevel;
4+
5+
import java.util.List;
6+
7+
public record ProfileUpdateRequest(
8+
List<Long> jobCategoryIds,
9+
Long primaryJobCategoryId,
10+
Long regionId,
11+
CareerLevel careerLevel,
12+
List<String> preferenceNotes,
13+
List<String> excludeKeywords,
14+
List<String> techStacks
15+
) {
16+
}

src/main/java/com/leets7th/job_is_be/domain/user/entity/UserJobCategory.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@
1313
* 사용자 관심 직무/직군
1414
*/
1515
@Entity
16-
@Table(name = "user_job_categories")
16+
@Table(
17+
name = "user_job_categories",
18+
uniqueConstraints = @UniqueConstraint(
19+
name = "uk_user_job_categories_user_category",
20+
columnNames = {"user_id", "job_category_id"}
21+
)
22+
)
1723
@Getter
1824
@NoArgsConstructor(access = AccessLevel.PROTECTED)
1925
public class UserJobCategory extends BaseEntity {

src/main/java/com/leets7th/job_is_be/domain/user/entity/UserProfile.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
import com.leets7th.job_is_be.domain.user.enums.CareerLevel;
5+
import com.leets7th.job_is_be.domain.user.enums.OnboardingStep;
56
import com.leets7th.job_is_be.global.base.BaseEntity;
67
import jakarta.persistence.*;
78
import lombok.AccessLevel;
@@ -31,9 +32,13 @@ public class UserProfile extends BaseEntity {
3132
private User user;
3233

3334
@Enumerated(EnumType.STRING)
34-
@Column(name = "career_level", nullable = false, length = 20)
35+
@Column(name = "career_level", length = 20)
3536
private CareerLevel careerLevel;
3637

38+
@Enumerated(EnumType.STRING)
39+
@Column(name = "onboarding_step", length = 20)
40+
private OnboardingStep onboardingStep;
41+
3742
@Column(name = "preference_note", length = 500)
3843
private String preferenceNote; // 선호 조건 텍스트 (재택 우선 등)
3944

@@ -58,10 +63,11 @@ public class UserProfile extends BaseEntity {
5863
private LocalDateTime onboardingCompletedAt;
5964

6065
@Builder
61-
public UserProfile(User user, CareerLevel careerLevel, String preferenceNote,
62-
String excludeKeywords, String techStack) {
66+
public UserProfile(User user, CareerLevel careerLevel, OnboardingStep onboardingStep,
67+
String preferenceNote, String excludeKeywords, String techStack) {
6368
this.user = user;
6469
this.careerLevel = careerLevel;
70+
this.onboardingStep = onboardingStep;
6571
this.preferenceNote = preferenceNote;
6672
this.excludeKeywords = excludeKeywords;
6773
this.techStack = techStack;
@@ -74,6 +80,36 @@ public void completeOnboarding(LocalDateTime now) {
7480
this.onboardingCompletedAt = now;
7581
}
7682

83+
public void updateDraft(
84+
CareerLevel careerLevel,
85+
OnboardingStep onboardingStep,
86+
String preferenceNote,
87+
String excludeKeywords,
88+
String techStack
89+
) {
90+
this.careerLevel = careerLevel;
91+
this.onboardingStep = onboardingStep;
92+
this.preferenceNote = preferenceNote;
93+
this.excludeKeywords = excludeKeywords;
94+
this.techStack = techStack;
95+
}
96+
97+
public void updateProfile(
98+
CareerLevel careerLevel,
99+
String preferenceNote,
100+
String excludeKeywords,
101+
String techStack
102+
) {
103+
this.careerLevel = careerLevel;
104+
this.preferenceNote = preferenceNote;
105+
this.excludeKeywords = excludeKeywords;
106+
this.techStack = techStack;
107+
}
108+
109+
public void moveOnboardingStep(OnboardingStep onboardingStep) {
110+
this.onboardingStep = onboardingStep;
111+
}
112+
77113
public void completeJobTest(LocalDateTime now) {
78114
this.jobTestCompleted = true;
79115
this.jobTestCompletedAt = now;

src/main/java/com/leets7th/job_is_be/domain/user/entity/UserRegion.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@
1313
* 사용자 희망 지역
1414
*/
1515
@Entity
16-
@Table(name = "user_regions")
16+
@Table(
17+
name = "user_regions",
18+
uniqueConstraints = @UniqueConstraint(
19+
name = "uk_user_regions_user",
20+
columnNames = "user_id"
21+
)
22+
)
1723
@Getter
1824
@NoArgsConstructor(access = AccessLevel.PROTECTED)
1925
public class UserRegion extends BaseEntity {

0 commit comments

Comments
 (0)