Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
### mcp ###
.mcp.json

### claude ###
CLAUDE.md
.claude/settings.local.json
.claude/check-mcp-updates.sh
.claude/*.log
.claude/transcripts/

### gradle ###
HELP.md
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public enum BaseResponseStatus implements BaseResponseStatusInterface {
PASSWORD_NOT_MATCH(HttpStatus.BAD_REQUEST, false, 2025, "입력하신 비밀번호가 일치하지 않습니다. 다시 확인해주세요."),
NO_EXIST_USER_STATISTICS(HttpStatus.NOT_FOUND, false, 2026, "존재하지 않는 유저 통계입니다."),
INVALID_USER_TYPE(HttpStatus.BAD_REQUEST, false, 2027, "유효하지 않은 유저 타입입니다. 다시 확인해주세요."),
NO_AUTHORITY_TO_SEARCH_USER(HttpStatus.FORBIDDEN, false, 2028, "해당 타입의 유저를 조회할 권한이 없습니다."),
NO_AUTHORITY_TO_SEARCH_USER(HttpStatus.FORBIDDEN, false, 2028, "해당 유저를 조회할 권한이 없습니다."),

/**
* 3000: admin service error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
import greenfirst.be.global.common.enums.common.UserType;
import greenfirst.be.global.common.response.base.BaseResponse;
import greenfirst.be.global.common.security.CustomUserDetails;
import greenfirst.be.user.adapter.in.web.response.UserProfileResponse;
import greenfirst.be.user.adapter.in.web.response.UserSimpleDataListResponse;
import greenfirst.be.user.application.dto.in.GetUserByUuidInDto;
import greenfirst.be.user.application.dto.in.GetUserSimpleDataListInDto;
import greenfirst.be.user.application.dto.out.UserDataListOutDto;
import greenfirst.be.user.application.service.GetUserDataService;
import greenfirst.be.user.domain.model.Users;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import lombok.RequiredArgsConstructor;
Expand All @@ -18,12 +21,10 @@
import org.springframework.lang.Nullable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.UUID;


@Slf4j
Expand All @@ -41,6 +42,8 @@ public class GetUserDataController {
/**
* 유저 데이터 조회 컨트롤러
* 1. (admin/agency) 전체 유저 목록 조회
* 2. (common) 본인 프로필 조회
* 3. (admin/agency) 다른 유저 프로필 조회
*/

// 1. (admin/agency) 유저 목록 조회/검색
Expand Down Expand Up @@ -75,4 +78,49 @@ public BaseResponse<UserSimpleDataListResponse> getUserList(
return new BaseResponse<>(response);
}


// 2. (common) 본인 프로필 조회
@Operation(summary = "본인 프로필 조회", description = "로그인한 사용자 본인의 프로필 정보를 조회합니다", tags = { "User - Admin", "User - Agency", "User - Partner", "User - User" })
@GetMapping("/profile/my")
@SecurityRequirement(name = "Bearer Auth")
public BaseResponse<UserProfileResponse> getMyProfile(@AuthenticationPrincipal CustomUserDetails authentication) {

// 본인 프로필 조회
Users user = getUserDataService.getByUserUuid(authentication.getUserUuid());

// mapping
UserProfileResponse response = modelMapper.map(user, UserProfileResponse.class);

// result
return new BaseResponse<>(response);
}


// 3. (admin/agency) 다른 유저 프로필 조회
@Operation(summary = "(관리자/대리점) 유저 프로필 조회", description = "UUID로 특정 사용자의 프로필 정보를 조회합니다 (권한 검증 포함)", tags = { "User - Admin", "User - Agency" })
@GetMapping("/profile/{userUuid}")
@PreAuthorize("hasAnyAuthority('ADMIN', 'AGENCY')")
@SecurityRequirement(name = "Bearer Auth")
public BaseResponse<UserProfileResponse> getUserProfileByUuid(
@AuthenticationPrincipal CustomUserDetails authentication,
@PathVariable UUID userUuid
) {

// mapping
GetUserByUuidInDto inDto = GetUserByUuidInDto.builder()
.requestorType(authentication.getUserType())
.requestorUuid(authentication.getUserUuid())
.targetUserUuid(userUuid)
.build();

// 유저 프로필 조회
Users user = getUserDataService.getUserByUuidWithAuthorityCheck(inDto);

// mapping
UserProfileResponse response = modelMapper.map(user, UserProfileResponse.class);

// result
return new BaseResponse<>(response);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


Expand All @@ -37,13 +39,61 @@ public class PartnerAuthController {

/**
* 파트너 인증 컨트롤러
* 1. (personal partner) 개인 파트너 회원가입
* 2. (corp partner) 기업 파트너 회원가입
* 3. (personal partner) 개인 파트너 로그인
* 4. (corp partner) 기업 파트너 로그인
* 1. 아이디 중복 확인 (기업 파트너 회원가입시 사용)
* 2. 휴대폰번호 중복 확인
* 3. (personal partner) 개인 파트너 회원가입
* 4. (corp partner) 기업 파트너 회원가입
* 5. (personal partner) 개인 파트너 로그인
* 6. (corp partner) 기업 파트너 로그인
*/

// 1. (personal partner) 개인 파트너 회원가입
// 1. 아이디 중복 확인 (기업 파트너 회원가입시 사용)
/**
* API 설명: 기업 파트너 회원가입 시 로그인 아이디의 중복 여부를 확인합니다.
*
* 목표:
* - 입력받은 로그인 아이디가 이미 존재하는지 확인
* - 중복 여부를 boolean으로 반환
*
* 응답값:
* {
* "duplicateStatus": boolean // true: 중복됨, false: 사용 가능
* }
*/
@Operation(summary = "아이디 중복 확인", description = "기업 파트너 회원가입 시 로그인 아이디 중복 여부 확인")
@GetMapping("/validation/login-id")
public BaseResponse<Object> checkLoginIdDuplicate(
@RequestParam String userLoginId
) {
// TODO: 아이디 중복 확인 로직 구현
return null;
}


// 2. 휴대폰번호 중복 확인
/**
* API 설명: 회원가입 시 휴대폰번호의 중복 여부를 확인합니다.
*
* 목표:
* - 입력받은 휴대폰번호가 이미 등록되어 있는지 확인
* - 중복 여부를 boolean으로 반환
*
* 응답값:
* {
* "duplicateStatus": boolean // true: 중복됨, false: 사용 가능
* }
*/
@Operation(summary = "휴대폰번호 중복 확인", description = "회원가입 시 휴대폰번호 중복 여부 확인")
@GetMapping("/validation/phone-number")
public BaseResponse<Object> checkPhoneNumberDuplicate(
@RequestParam String userPhoneNumber
) {
// TODO: 휴대폰번호 중복 확인 로직 구현
return null;
}


// 3. (personal partner) 개인 파트너 회원가입
@Operation(summary = "(개인 파트너) 개인 파트너 회원가입", description = "개인 파트너 회원가입")
@PostMapping("/personal/signup")
public BaseResponse<Void> signUpPersonalPartner(@RequestBody PersonalPartnerSignUpRequest request) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package greenfirst.be.user.adapter.in.web.controller;


import greenfirst.be.global.common.response.base.BaseResponse;
import greenfirst.be.global.common.security.CustomUserDetails;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@Tag(name = "User - Management")
@Slf4j
@RestController
@RequestMapping("/api/v1/user")
@RequiredArgsConstructor
public class UserManagementController {

// service
// private final UserManagementService userManagementService;
// util
// private final ModelMapper modelMapper;


/**
* 유저 관리 컨트롤러
* 1. 프로필 수정
* 2. 비밀번호 찾기
* 3. 비밀번호 변경
* 4. 회원 탈퇴
*/

// 1. 프로필 수정
/**
* API 설명: 로그인한 사용자의 프로필 정보를 수정합니다.
*
* 목표:
* - 사용자 인증 정보(JWT)를 통해 본인 확인
* - 사용자 이름, 주소, 사업자 정보 등 프로필 정보 수정
* - 수정 완료 후 성공 응답 반환
*
* 응답값: 없음
*/
@Operation(summary = "프로필 수정", description = "로그인한 사용자의 프로필 정보를 수정합니다")
@PutMapping("/profile")
@SecurityRequirement(name = "Bearer Auth")
public BaseResponse<Void> updateProfile(
@RequestBody Object request, // TODO: UpdateProfileRequest 생성 필요
@AuthenticationPrincipal CustomUserDetails authentication
) {
// TODO: 프로필 수정 로직 구현
return null;
}


// 2. 비밀번호 찾기
/**
* API 설명: 사용자의 비밀번호를 찾기(재설정) 요청을 처리합니다.
*
* 목표:
* - 사용자 이름과 휴대폰 번호로 본인 확인
* - 임시 비밀번호 생성 또는 비밀번호 재설정 링크 전송
* - SMS/이메일을 통해 임시 비밀번호 또는 재설정 링크 전송
* - 성공 응답 반환
*
* 응답값: 없음
*
* 참고:
* - 이 API는 인증이 필요하지 않음 (비로그인 상태에서 사용)
* - 보안을 위해 사용자 존재 여부를 직접적으로 노출하지 않음
*/
@Operation(summary = "비밀번호 찾기", description = "사용자 정보로 비밀번호 재설정을 요청합니다")
@PostMapping("/password/reset")
public BaseResponse<Void> findPassword(
@RequestBody Object request // TODO: FindPasswordRequest 생성 필요 (userName, userPhoneNumber)
) {
// TODO: 비밀번호 찾기 로직 구현
return null;
}


// 3. 비밀번호 변경
/**
* API 설명: 로그인한 사용자의 비밀번호를 변경합니다.
*
* 목표:
* - 사용자 인증 정보(JWT)를 통해 본인 확인
* - 현재 비밀번호 검증 후 새로운 비밀번호로 변경
* - 비밀번호 암호화 후 저장
* - 변경 완료 후 성공 응답 반환
*
* 응답값: 없음
*/
@Operation(summary = "비밀번호 변경", description = "로그인한 사용자의 비밀번호를 변경합니다")
@PutMapping("/password")
@SecurityRequirement(name = "Bearer Auth")
public BaseResponse<Void> changePassword(
@RequestBody Object request, // TODO: ChangePasswordRequest 생성 필요
@AuthenticationPrincipal CustomUserDetails authentication
) {
// TODO: 비밀번호 변경 로직 구현
return null;
}


// 4. 회원 탈퇴
/**
* API 설명: 로그인한 사용자의 계정을 탈퇴(삭제) 처리합니다.
*
* 목표:
* - 사용자 인증 정보(JWT)를 통해 본인 확인
* - 회원 탈퇴 전 비밀번호 재확인 (보안)
* - 계정 삭제 또는 비활성화 처리
* - 관련 데이터 처리 (소프트 삭제 또는 익명화)
* - 탈퇴 완료 후 성공 응답 반환
*
* 응답값: 없음
*/
@Operation(summary = "회원 탈퇴", description = "로그인한 사용자의 계정을 탈퇴 처리합니다")
@DeleteMapping("/account")
@SecurityRequirement(name = "Bearer Auth")
public BaseResponse<Void> deleteAccount(
@RequestBody Object request, // TODO: DeleteAccountRequest 생성 필요 (비밀번호 확인용)
@AuthenticationPrincipal CustomUserDetails authentication
) {
// TODO: 회원 탈퇴 로직 구현
return null;
}

}
Loading