Skip to content

Conversation

@plan11plan
Copy link

📌 Summary

  • 배경: '설계는 내가, 구현은 AI가'라는 역할 분리를 전제로, 기능 요구사항을 받았을 때 어떤 변환 과정을 거쳐야 AI가 정확히 구현할 수 있는 프롬프트가 되는가? 이 변환 과정을 탐색했다.
  • 목표: 요구사항을 AI 실행 프롬프트로 구조화하는 방법을 4가지 시도를 통해 알아보고, 회원 도메인(회원가입/내 정보 조회/비밀번호 변경) 3개 API를 TDD로 구현한다.
  • 결과: 4번의 시도를 거쳐 회원 기능을 구현 완료. "구현보다 계층 책임 정의와 검증 스코프 정의가 더 중요하다"는 깨달음을 얻었으나, AI 협업의 최적 방식은 아직 미해결 과제로 남아 있다.

🧭 Context & Decision

문제 정의

  • 현재 동작/제약: 기능 요구사항(회원가입, 내 정보 조회, 비밀번호 변경)을 AI에게 전달하여 TDD로 구현해야 하는 상황. 그런데 요구사항을 어떻게 변환해야 AI가 내 의도대로 구현하는가? 가 불명확했다.
  • 문제(또는 리스크): 요구사항을 그대로 던지면 AI가 설계까지 다 해버려서 내 설계 의도가 사라진다. 반대로 설계를 전부 문서화하면 직접 코딩하는 것과 비용이 같다.
  • 성공 기준(완료 정의): 요구사항 → AI 프롬프트 변환 과정에서 "개발자가 설계 주도권을 유지하면서도 AI에게 효과적으로 위임할 수 있는 방식"을 찾는다.

선택지와 결정 — 4번의 시도

시도 1: 요구사항을 그대로 전달

  • 방식: "회원가입 기능을 TDD로 개발해줘"
  • 결과: AI가 설계 + 구현 모두 수행. 내 설계도, 내 의도도 없었다.
  • 교훈: 요구사항 ≠ 프롬프트. 요구사항을 그대로 전달하면 AI에게 설계 주도권을 넘기는 것이다.

시도 2: AI가 설계 → 내가 결정

  • 방식: AI에게 설계 보고서를 작성하게 하고, 내가 읽고 결정
  • 결과: AI가 너무 복잡한 설계를 제시. 문서를 읽는 데 시간이 많이 들었고 전부 읽을 수도 없었다. 내 의도가 담긴 설계라고 느껴지지 않았다.
  • 교훈: AI의 설계를 검토하는 것과 내가 설계하는 것은 다르다. 남의 설계를 읽는 것은 내 역량이 되지 않는다.

시도 3: 내가 설계 문서 작성 → AI 피드백

  • 방식: 객체와 메시지 정의, 검증 및 예외 케이스를 직접 문서로 정리하고 AI에게 피드백 요청
  • 결과:
    • 좋았던 점: 내 설계 틀 안에서 AI가 엣지 케이스와 잠재적 문제를 해상도 높게 알려줬다. 레이어별 해야 할 것/하지 말아야 할 것을 먼저 정의해야 한다는 것을 배웠다.
    • 문제점: 도메인부터 API까지 수도코드로 문서화하고 있었는데, "이럴 거면 그냥 코드로 작성하는 게 더 내 의도가 담긴 게 아닌가?" 라는 의문이 들었다.
  • 교훈: 설계 의도 전달은 문서보다 코드가 더 정확할 수 있다. 단, 요구사항 규칙뿐 아니라 개발 규칙(레이어 책임, 검증 스코프)을 명확히 해야 한다.

시도 4: 내가 시범 구현 → AI가 스타일 참고하여 나머지 구현 (최종 선택)

  • 방식: 회원가입 기능을 TDD로 도메인~API까지 직접 구현하고, "이 스타일대로 나머지 기능을 구현하라"고 지시
  • 결과: AI가 내 코드 스타일을 참고하여 A~Z를 만들어냈다. 왜 그렇게 만들었는지 물어보며 AI의 설계 사고를 배우는 방식으로 진행했다.
  • 문제점: 한 번에 모든 코드를 20분간 생성하여 양이 방대. 나는 코드 확인과 테스트 통과 여부만 확인하고 있었다.
  • 교훈: 시범 구현이 가장 명확한 프롬프트였지만, AI의 작업 단위를 더 작게 쪼개야 리뷰와 개입이 가능하다.

트레이드오프

  • 시도 3의 "설계 문서 + AI 피드백"이 설계 역량 성장에는 가장 좋지만, 비용이 크다
  • 시도 4의 "시범 구현 + 스타일 위임"이 실행 속도는 가장 빠르지만, 내 개입 여지가 줄어든다
  • 최적 방식은 아직 미해결: 이 둘의 균형점을 찾는 것이 다음 과제

미해결 고민

  • AI를 파트너로 협업하는 방식을 아직 깨닫지 못했다
  • "처음부터 완벽한 설계 → AI 구현"이 아니라, 개발자가 직접 TDD 하면서 궁금하거나 막히거나 노가다인 과정을 AI에게 맡기는 것이 원래 기대된 방식이었을까?
  • 더 이상 구현은 중요하지 않다고 체감했다. 개발 환경 이해, 계층 책임 정의, 검증 스코프 정의가 더 중요하다.

🏗️ Design Overview

변경 범위

  • 영향 받는 모듈/도메인: apps/commerce-api (메인 변경), modules/jpa (테스트 픽스처)
  • 신규 추가:
    • 도메인: UserModel, LoginId, Password, Name, BirthDate, Email, UserRepository, UserService, AuthenticationService
    • 인프라: PasswordEncoder, BCryptPasswordEncoderImpl, UserRepositoryImpl, UserJpaRepository
    • API: UserV1Controller, UserV1Dto, UserV1ApiSpec
    • 테스트: 단위 7개, 통합 1개, E2E 1개, 시나리오 1개
    • HTTP 테스트: http/commerce-api/user-v1.http (26개 케이스)
  • 제거/대체: 없음

주요 컴포넌트 책임

컴포넌트 책임
UserModel JPA 엔티티. 5개 값 객체를 Embedded로 보유. 생성자에서 null 검증
LoginId 4-12자, 영문+숫자만 허용. 생성 시 검증
Password 8-16자, 대소문자+숫자+특수문자 필수. 생년월일 포함 금지, 동일 비밀번호 재사용 금지. fromEncoded() 팩토리로 암호화된 값 로딩
Name 2-10자. getMaskedName()으로 마지막 글자 * 마스킹
BirthDate 과거 날짜만 허용. toDateString()으로 yyyyMMdd 변환
Email 이메일 정규식 패턴 검증
UserService 회원가입(중복 체크 + 암호화 + 저장), 내 정보 조회, 비밀번호 변경
AuthenticationService 헤더 기반 인증. LoginId 조회 후 BCrypt.matches()로 비밀번호 검증
BCryptPasswordEncoderImpl PasswordEncoder 인터페이스 구현. Spring Security BCrypt 위임
UserRepositoryImpl UserRepository 도메인 인터페이스를 JPA로 구현하는 어댑터
UserV1Controller 3개 API 엔드포인트. DTO 변환 및 인증 처리

🔁 Flow Diagram

회원가입 Flow

sequenceDiagram
  autonumber
  participant Client
  participant Controller
  participant UserService
  participant PasswordEncoder
  participant Repository
  participant DB

  Client->>Controller: POST /api/v1/users/signup (JSON body)
  Controller->>Controller: DTO 검증 + 값 객체 생성
  Controller->>UserService: signup(loginId, password, name, birthDate, email)
  UserService->>Repository: find(loginId) - 중복 체크
  Repository->>DB: SELECT by login_id
  DB-->>Repository: Optional.empty()
  UserService->>UserService: password.validateNotContainBirthday(birthDate)
  UserService->>PasswordEncoder: encode(rawPassword)
  PasswordEncoder-->>UserService: BCrypt 해시값
  UserService->>Repository: save(UserModel)
  Repository->>DB: INSERT
  UserService-->>Controller: UserModel
  Controller-->>Client: ApiResponse<SignupResponse> (이름 마스킹)
Loading

내 정보 조회 Flow

sequenceDiagram
  autonumber
  participant Client
  participant Controller
  participant AuthService
  participant UserService
  participant DB

  Client->>Controller: GET /api/v1/users/me (X-Loopers-LoginId, X-Loopers-LoginPw)
  Controller->>AuthService: authenticate(loginId, password)
  AuthService->>DB: find(LoginId) + BCrypt.matches()
  AuthService-->>Controller: UserModel (인증 성공)
  Controller->>UserService: getMyInfo(loginId)
  UserService->>DB: find(LoginId)
  UserService-->>Controller: UserModel
  Controller-->>Client: ApiResponse<MyInfoResponse> (이름 마스킹)
Loading

비밀번호 변경 Flow

sequenceDiagram
  autonumber
  participant Client
  participant Controller
  participant AuthService
  participant UserService
  participant PasswordEncoder
  participant DB

  Client->>Controller: PATCH /api/v1/users/password (헤더 + JSON body)
  Controller->>AuthService: authenticate(loginId, headerPassword)
  AuthService-->>Controller: 인증 성공
  Controller->>UserService: changePassword(loginId, currentPw, newPw)
  UserService->>DB: find(LoginId)
  UserService->>PasswordEncoder: matches(currentPw, storedPw) - 현재 비밀번호 확인
  UserService->>PasswordEncoder: matches(newPw, storedPw) - 동일 비밀번호 재사용 방지
  UserService->>UserService: newPassword.validateNotContainBirthday(birthDate)
  UserService->>PasswordEncoder: encode(newPw)
  UserService->>DB: save(UserModel)
  UserService-->>Controller: void
  Controller-->>Client: ApiResponse ("비밀번호가 성공적으로 변경되었습니다.")
Loading

🧪 테스트 전략

레이어 테스트 유형 클래스 수 주요 검증 항목
Domain (값 객체) Unit 5 생성 검증, 경계값, 포맷
Domain (엔티티) Unit 1 (UserModel) 생성자 null 검증
Domain (서비스) Unit (Mock) 1 (AuthenticationService) 인증 성공/실패
Service Integration 1 (UserServiceIntegrationTest) DB 연동, 암호화, 트랜잭션
API E2E 1 (UserV1ApiE2ETest, 20개 케이스) HTTP 상태코드, 검증, 인증
전체 Scenario 1 (UserV1ApiScenarioTest) 가입→조회→변경→재조회→이전PW실패
image

hanyoung-kurly and others added 29 commits February 2, 2026 01:26
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- PasswordEncoder 인터페이스 및 BCrypt 구현체 추가
- Password.fromEncoded() 메서드 추가
- UserService에서 회원가입 시 패스워드 암호화
- AuthenticationService에서 암호화된 패스워드 비교
- 관련 테스트 코드 수정

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- UserService에서 비밀번호 변경 시 암호화된 비밀번호와 비교
- 새 비밀번호도 암호화하여 저장
- UserModel.changePassword는 단순 필드 변경만 수행
- UserModelTest의 비밀번호 관련 테스트 제거 (로직이 UserService로 이동)
- UserServiceIntegrationTest 암호화를 고려한 검증으로 수정

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 6, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants