회원가입

AUTH-JOIN · /join

실제 화면 열기 ↗
기능
7
API 호출
1
가드레일
6
id 가 테스트 이름
구현 단계
10 / 10
완료인증 · 회원wvctesol-auth :8081클라이언트 컴포넌트268

개발 스펙

이 화면에서 할 수 있어야 하는 것 (2)

  • 아이디 중복확인 후 가입한다.
  • 약관에 동의한다.

비즈니스 규칙 (2)

  • 아이디는 중복될 수 없다.
  • 비밀번호는 영문 · 숫자 · 특수문자를 섞어 8~20자.
    근거: studentInformation.php 비밀번호 안내 문구

API (2)

메서드경로권한모듈 · 설명
GET/api/identity/members/check-duplicate공개
아이디 중복 확인.
domains:identity:identity-web
POST/api/identity/members공개
회원 가입.
domains:identity:identity-web
409 DUPLICATE_LOGIN_ID
400 WEAK_PASSWORD

가드레일 (6) — id 가 곧 테스트 이름이다

id반드시 만족해야 하는 것등급
signup-no-duplicate-under-race
같은 아이디로 동시에 가입해도 하나만 만들어져야 한다.
"있는지 확인 → 넣기" 사이에 다른 요청이 끼면 둘 다 통과한다. 막기 전에는 동시 2건이면 100%, 10건이면 10개가 그대로 만들어졌다. 중복이 생기면 그 아이디는 로그인도 비밀번호 재설정도 500 이 되어 계정이 통째로 잠겼다.
critical
signup-account-usable-after-race
경합을 겪은 계정도 로그인·비밀번호 재설정이 되어야 한다.
유니크 제약이 없어 이론상 중복이 남을 수 있다. 그때 예외를 던지면 계정이 잠긴다 — 먼저 만들어진 것으로 동작하고 경고를 남긴다.
critical
signup-sequential-duplicate-rejected
순차로 같은 아이디를 넣어도 거절돼야 한다.
high
join-duplicate-blocked
중복확인을 통과해도 가입 시점에 다시 검사해야 한다(경합 방지).
high
join-password-hashed
비밀번호가 평문으로 저장되면 안 된다.
critical
join-no-entitlement-on-signup
가입만으로 수강권 플래그가 켜지면 안 된다.
critical

구현 계획 (10/10)

  1. lockForSignUp 포트 — 같은 아이디의 가입을 한 줄로 세운다identity-domain
  2. pg_advisory_xact_lock(hashtext(id)) — 표를 잠그지 않고 이름 하나에만identity-infrastructure
  3. 중복 확인 전에 잠근다identity-app
  4. findAllByLoginIdOrderByIdAsc — 중복이 있어도 먼저 만들어진 것으로 동작identity-infrastructure
  5. SignUpCommand · PasswordPolicy · save 포트identity-domain
  6. SignUpUseCase — 저장 직전 중복 재검사identity-app
  7. 레거시 NOT NULL 컬럼 40개 초기값 · forSignUp 팩토리identity-infrastructure
  8. /api/identity/members/check-duplicate 구현identity-web
  9. /api/identity/members 구현identity-web
  10. Next.js 를 BFF 로 전환 — Prisma 직접 접근 제거wvctesol

서버 사이드 구현 계획 — 자바 객체별 요구사항 (4/4)

객체모듈책임 · 지켜야 할 것
PasswordPolicy
class
identity-domain
비밀번호 규칙. 원본 안내 문구 그대로 영문·숫자·특수문자 혼합 8~20자.
  • 정책을 도메인에 둔다 — 컨트롤러 검증(@Size)만으로는 유스케이스를 직접 부를 때 뚫린다.
  • 특수문자 집합은 원본 안내와 같다: ~!@#$%^&*()_+=
SignUpUseCase
service
identity-app
가입 처리.
  • 중복확인을 통과했어도 저장 직전에 다시 검사한다 — 그 사이 같은 아이디가 들어올 수 있다.
  • 평문 비밀번호는 이 계층에서 끝난다. 아래로는 해시만 내려간다.
  • @Transactional 로 묶는다. 트랜잭션 경계는 app 계층이 잡는다.
MemberJpaEntity.forSignUp
entity
identity-infrastructure
가입용 엔티티 생성.
  • member 에는 NOT NULL 인데 DB 기본값이 없는 컬럼이 40개다. 스키마를 바꾸지 않기로 했으므로 자바 필드 초기값으로 채운다.
  • 기존에 매핑돼 있던 컬럼도 초기값을 빠뜨리면 안 된다 — lecture_start 누락으로 실제로 INSERT 가 터졌다.
  • 수강 자격 플래그는 모두 N 으로 시작한다. 가입만으로 열리면 안 된다.
  • id 는 DB serial 이 매긴다. @GeneratedValue(IDENTITY).
SignUpRequest
record
identity-web
가입 요청 DTO.
  • 연락처는 숫자만 남겨 커맨드로 넘긴다. 원본도 하이픈 없이 저장한다.
  • 형식 검증만 한다. 비밀번호 강도는 도메인이 판단한다.

테스트 방법 (6)

가드레일종류확인 방법
signup-no-duplicate-under-racee2e동시 10건 → 201 하나 · 409 아홉
signup-account-usable-after-racee2e동시 5건 뒤 로그인·비밀번호 재설정이 된다
signup-sequential-duplicate-rejectede2e두 번째 가입 → DUPLICATE_LOGIN_ID
join-duplicate-blockede2e같은 loginId 로 가입 요청을 동시에 2회 → 하나만 성공, 나머지 409
join-password-hashede2e가입 후 member.pw 가 평문과 다르고 bcrypt 접두($2)로 시작
join-no-entitlement-on-signupe2e가입 직후 pay_yn 등 수강권 플래그가 모두 N

스냅샷

AUTH-JOIN 스냅샷

기능 목록 (7)

데이터
  • ·API 조회/api/identity/auth/find-id
입력
  • ·1개
  • ·제출 버튼1개
  • ·입력 필드8개
액션
  • ·서버 액션join
인증
  • ·세션 확인
  • ·로그인/로그아웃 호출

화면 이동

← 이 화면으로 오는 곳
이 화면에서 가는 곳 →

연결

API
  • /api/identity/auth/find-id
소스
src/app/join/page.tsx