Skip to content

CapstoneDesignPlatform/backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

93 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ› οΈ Capdi Backend

기업진단 μš©μ—­κ±°λž˜ ν”Œλž«νΌ λ°±μ—”λ“œ μ„œλ²„


πŸ“¦ νŒ¨ν‚€μ§€ ꡬ쑰

com.capdi.backend
β”œβ”€β”€ domain
β”‚   β”œβ”€β”€ {도메인λͺ…}
β”‚   β”‚   β”œβ”€β”€ controller
β”‚   β”‚   β”œβ”€β”€ service
β”‚   β”‚   β”œβ”€β”€ repository
β”‚   β”‚   β”œβ”€β”€ entity
β”‚   β”‚   └── dto
└── global          ← 곡톡 μ„€μ • 및 μœ ν‹Έ

πŸ“ 넀이밍 μ»¨λ²€μ…˜

λŒ€μƒ κ·œμΉ™ μ˜ˆμ‹œ
클래슀 PascalCase UserService
λ©”μ„œλ“œ / λ³€μˆ˜ camelCase createUser
μƒμˆ˜ UPPER_SNAKE_CASE MAX_RETRY_COUNT
ν…Œμ΄λΈ”λͺ… snake_case λ³΅μˆ˜ν˜• users, expert_profiles
컬럼λͺ… snake_case created_at, business_number
URL kebab-case /job-posts, /expert-profiles
Enum κ°’ UPPER_SNAKE_CASE PENDING, APPROVED

πŸ“ μ½”λ“œ μ»¨λ²€μ…˜

Entity

  • λͺ¨λ“  EntityλŠ” BaseTimeEntity 상속 (createdAt, updatedAt μžλ™ 관리)
  • @Setter μ‚¬μš© κΈˆμ§€ β†’ κ°’ λ³€κ²½ μ‹œ 도메인 λ©”μ„œλ“œ μΆ”κ°€
  • @NoArgsConstructor(access = AccessLevel.PROTECTED) μ‚¬μš©
  • String λŒ€μ‹  Enum μ‚¬μš© (@Enumerated(EnumType.STRING))
  • @Builder.Default 둜 κΈ°λ³Έκ°’ μ§€μ •
// βœ… μ˜¬λ°”λ₯Έ μ˜ˆμ‹œ
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Builder
public class User extends BaseTimeEntity {

    @Enumerated(EnumType.STRING)
    @Builder.Default
    private UserStatus status = UserStatus.ACTIVE;
}
// ❌ 잘λͺ»λœ μ˜ˆμ‹œ
@Entity
@Getter
@Setter                              // κΈˆμ§€
public class User {
    private String status;           // String λŒ€μ‹  Enum μ‚¬μš©
    private LocalDateTime createdAt; // BaseTimeEntity μƒμ†μœΌλ‘œ λŒ€μ²΄
}

DTO

  • Request DTO β†’ @Valid + Bean Validation μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš©
  • Response DTO β†’ @Builder + from() 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œ μ‚¬μš©
  • ν΄λΌμ΄μ–ΈνŠΈλ‘œλΆ€ν„° λ°›μœΌλ©΄ μ•ˆ λ˜λŠ” 값은 Request DTOμ—μ„œ μ œμ™Έ (예: status, verificationStatus)
  • λΉ„λ°€λ²ˆν˜ΈλŠ” password 둜 λ°›κ³ , Serviceμ—μ„œ μ•”ν˜Έν™” ν›„ μ €μž₯ (passwordHash 직접 μˆ˜μ‹  κΈˆμ§€)
// βœ… Request DTO
@Getter
public class UserCreateRequest {

    @NotBlank(message = "이메일은 ν•„μˆ˜μž…λ‹ˆλ‹€.")
    @Email
    private String email;

    @NotBlank
    @Size(min = 8)
    private String password; // 평문 μˆ˜μ‹ , Serviceμ—μ„œ μ•”ν˜Έν™”
}

// βœ… Response DTO
@Getter
@Builder
public class UserResponse {
    public static UserResponse from(User user) { ... }
}

Controller

  • λͺ¨λ“  API 응닡은 ResponseEntity<ApiResponse<T>> ν˜•νƒœλ‘œ λ°˜ν™˜
  • @RequestBody κ°€ μžˆλŠ” 경우 λ°˜λ“œμ‹œ @Valid ν•¨κ»˜ μ‚¬μš©
// βœ… μ˜¬λ°”λ₯Έ μ˜ˆμ‹œ
@PostMapping
public ResponseEntity<ApiResponse<UserResponse>> createUser(
        @RequestBody @Valid UserCreateRequest request) {
    return ResponseEntity.ok(ApiResponse.ok("μ‚¬μš©μžκ°€ μƒμ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.", userService.createUser(request)));
}

@GetMapping("/{id}")
public ResponseEntity<ApiResponse<UserResponse>> getUser(@PathVariable Long id) {
    return ResponseEntity.ok(ApiResponse.ok(userService.getUser(id)));
}

Service

  • 클래슀 λ ˆλ²¨μ— @Transactional(readOnly = true) μ„ μ–Έ
  • μ“°κΈ° μž‘μ—… λ©”μ„œλ“œμ—λ§Œ @Transactional 별도 μ„ μ–Έ
  • IllegalArgumentException λŒ€μ‹  CustomException(ErrorCode.XXX) μ‚¬μš©
// βœ… μ˜¬λ°”λ₯Έ μ˜ˆμ‹œ
@Service
@Transactional(readOnly = true)
public class UserService {

    @Transactional
    public UserResponse createUser(UserCreateRequest request) { ... }

    public UserResponse getUser(Long id) {
        return userRepository.findById(id)
                .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
    }
}

μ˜ˆμ™Έ 처리

  • λͺ¨λ“  λΉ„μ¦ˆλ‹ˆμŠ€ μ˜ˆμ™ΈλŠ” CustomException μ‚¬μš©
  • μ—λŸ¬ μ½”λ“œλŠ” ErrorCode enum에 등둝 ν›„ μ‚¬μš©
  • GlobalExceptionHandler μ—μ„œ 일괄 처리
// βœ… ErrorCode 등둝
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” μ‚¬μš©μžμž…λ‹ˆλ‹€."),

// βœ… μ˜ˆμ™Έ λ°œμƒ
throw new CustomException(ErrorCode.USER_NOT_FOUND);

API 응닡 ν˜•μ‹

// 성곡
{
  "success": true,
  "message": "μš”μ²­μ΄ μ„±κ³΅ν–ˆμŠ΅λ‹ˆλ‹€.",
  "data": { ... }
}

// μ‹€νŒ¨
{
  "success": false,
  "message": "μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” μ‚¬μš©μžμž…λ‹ˆλ‹€.",
  "data": null
}

🌿 브랜치 μ „λž΅

main     ─── 배포 브랜치
dev      ─── 개발 톡합 브랜치
feat/*   ─── κΈ°λŠ₯ 개발     (예: feat/user-auth)
fix/*    ─── 버그 μˆ˜μ •     (예: fix/bid-price-validation)

βœ‰οΈ 컀밋 λ©”μ‹œμ§€

νƒ€μž… μ„€λͺ…
feat μƒˆλ‘œμš΄ κΈ°λŠ₯ 개발
fix 버그 μˆ˜μ •
refactor μ½”λ“œ λ¦¬νŒ©ν† λ§
chore λΉŒλ“œ, μ„€μ •, μ˜μ‘΄μ„± λ“±
docs λ¬Έμ„œ μž‘μ„± / μˆ˜μ •
test ν…ŒμŠ€νŠΈ μ½”λ“œ μž‘μ„±
feat: μ‚¬μš©μž 둜그인 API κ΅¬ν˜„
fix: μž…μ°° κΈˆμ•‘ μœ νš¨μ„± 검사 였λ₯˜ μˆ˜μ •
refactor: UserService νŠΈλžœμž­μ…˜ 뢄리
chore: build.gradle μ˜μ‘΄μ„± μΆ”κ°€
docs: README μ½”λ“œ μ»¨λ²€μ…˜ μž‘μ„±

🎫 이슈 μ»¨λ²€μ…˜

라벨 νƒ€μž…

라벨 μ„€λͺ… μ˜ˆμ‹œ
feat μƒˆλ‘œμš΄ κΈ°λŠ₯ 개발 μ‚¬μš©μž 둜그인 API κ΅¬ν˜„
fix 버그 μˆ˜μ • μž…μ°° κΈˆμ•‘ μœ νš¨μ„± 검사 였λ₯˜
refactor μ½”λ“œ λ¦¬νŒ©ν† λ§ UserService νŠΈλžœμž­μ…˜ 뢄리
chore λΉŒλ“œ, μ„€μ •, μ˜μ‘΄μ„± λ“± build.gradle μ˜μ‘΄μ„± μΆ”κ°€
docs λ¬Έμ„œ μž‘μ„± / μˆ˜μ • README μ½”λ“œ μ»¨λ²€μ…˜ μž‘μ„±
test ν…ŒμŠ€νŠΈ μ½”λ“œ μž‘μ„± UserService λ‹¨μœ„ ν…ŒμŠ€νŠΈ μΆ”κ°€

이슈 제λͺ©

[feat] μ‚¬μš©μž 둜그인 API κ΅¬ν˜„
[fix] μž…μ°° κΈˆμ•‘ μœ νš¨μ„± 검사 였λ₯˜ μˆ˜μ •
[refactor] UserService νŠΈλžœμž­μ…˜ 뢄리

이슈 λ³Έλ¬Έ ν…œν”Œλ¦Ώ

## πŸ“‹ μž‘μ—… κ°œμš”

이 μ΄μŠˆμ—μ„œ 무엇을 κ΅¬ν˜„/μˆ˜μ •ν•˜λŠ”μ§€ κ°„λž΅νžˆ μ„€λͺ…

## βœ… μž‘μ—… λ‚΄μš©

* μ„ΈλΆ€ μž‘μ—… 1
* μ„ΈλΆ€ μž‘μ—… 2
* μ„ΈλΆ€ μž‘μ—… 3

## πŸ”— κ΄€λ ¨ 이슈

* closes #이슈번호 (μžˆλŠ” 경우)

## πŸ“Ž μ°Έκ³  사항

API λͺ…μ„Έ, ERD, λ””μžμΈ 링크 λ“± μ°Έκ³ ν•  λ‚΄μš© (μ—†μœΌλ©΄ μƒλž΅)

πŸ”€ PR κ·œμΉ™

  • PR 제λͺ©μ€ 이슈 제λͺ©κ³Ό λ™μΌν•˜κ²Œ μž‘μ„±
  • PR 본문에 closes #이슈번호 λͺ…μ‹œ β†’ μžλ™ 이슈 λ‹«κΈ° ν™œμ„±ν™”
  • PR은 λ°˜λ“œμ‹œ dev 브랜치둜 λ¨Έμ§€

브랜치 ↔ 이슈 μ—°κ²°

브랜치λͺ…에 이슈 번호λ₯Ό 포함해 좔적을 μš©μ΄ν•˜κ²Œ ν•œλ‹€.

feat/{이슈번호}-{μž‘μ—…λͺ…}
fix/{이슈번호}-{μž‘μ—…λͺ…}

μ˜ˆμ‹œ)
feat/23-user-login
fix/47-bid-price-validation

About

backend project

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors