123 lines
6.1 KiB
Plaintext
123 lines
6.1 KiB
Plaintext
sequenceDiagram
|
|
actor 법인관리자
|
|
participant Portal as Portal UI
|
|
participant UserManFacade
|
|
participant UserInvitationRepo as UserInvitation Repository
|
|
participant MessageService as Message Handler
|
|
participant Email as Email System
|
|
actor 초대받은사용자
|
|
participant AuthHandler as PortalAuthenticationSuccessHandler
|
|
participant IndexController
|
|
participant MainPage as 메인 페이지 (index.html)
|
|
participant UserRegisterController
|
|
participant UserRegisterFacade
|
|
participant PortalUserRepo as PortalUser Repository
|
|
participant PortalOrgRepo as PortalOrg Repository
|
|
|
|
%% ========================================
|
|
%% 1. 초대 발송
|
|
%% ========================================
|
|
법인관리자->>Portal: 사용자 이메일 입력<br/>초대 요청
|
|
Portal->>UserManFacade: sendInvitation(sender, emailAddr)
|
|
|
|
UserManFacade->>PortalUserRepo: findByEmailAddr(emailAddr)
|
|
alt 사용자가 없거나 이미 법인 사용자
|
|
UserManFacade-->>Portal: 에러 반환
|
|
Portal-->>법인관리자: 초대 불가 알림
|
|
else 일반 사용자 ROLE_USER 또는 비회원
|
|
UserManFacade->>UserManFacade: generateEightCharToken()<br/>예: K7MNPQ2R
|
|
UserManFacade->>UserInvitationRepo: save(UserInvitation)<br/>status: PENDING<br/>expiresOn: 7일 후
|
|
UserManFacade->>MessageService: publishEvent(UserInvitationEvent)
|
|
MessageService->>Email: 초대 이메일 발송<br/>(법인명, 관리자명, 토큰)
|
|
UserManFacade-->>Portal: 초대 완료
|
|
Portal-->>법인관리자: 초대 성공 알림
|
|
end
|
|
|
|
Email->>초대받은사용자: 초대 이메일 수신
|
|
|
|
%% ========================================
|
|
%% 2-A. 로그인 상태에서 이메일 링크 클릭 (바로 수락 페이지)
|
|
%% ========================================
|
|
alt 로그인 상태에서 이메일 링크 클릭
|
|
초대받은사용자->>Portal: 이메일 링크 클릭<br/>/signup/decision?invitation=TOKEN
|
|
Portal->>UserRegisterController: showDecisionPage(invitationToken)
|
|
UserRegisterController->>UserInvitationRepo: findByToken(decodedToken)
|
|
UserRegisterController-->>Portal: 약관 동의 페이지
|
|
Portal-->>초대받은사용자: 초대 수락/거절 화면<br/>(바로 표시, 팝업 없음)
|
|
Note over 초대받은사용자: 6. 초대 수락/거절 처리로 이동
|
|
end
|
|
|
|
%% ========================================
|
|
%% 2-B. 로그인 (기존 회원 또는 신규 가입 후)
|
|
%% ========================================
|
|
alt 기존 회원 (비로그인 상태)
|
|
초대받은사용자->>Portal: 로그인
|
|
else 비회원이 일반 회원가입 후
|
|
초대받은사용자->>Portal: 회원가입 (ROLE_USER)
|
|
초대받은사용자->>Portal: 로그인
|
|
end
|
|
|
|
%% ========================================
|
|
%% 3. 로그인 성공 처리 (AuthenticationSuccessHandler)
|
|
%% ========================================
|
|
Portal->>AuthHandler: onAuthenticationSuccess()
|
|
AuthHandler->>AuthHandler: 이메일 인증, 휴면계정,<br/>비밀번호 만료 체크
|
|
|
|
AuthHandler->>UserInvitationRepo: findFirstByInvitationEmailAndStatus<br/>(loginId, PENDING)
|
|
|
|
alt PENDING 초대 없음
|
|
AuthHandler->>Portal: redirect to /
|
|
Portal-->>초대받은사용자: 메인 페이지 (팝업 없음)
|
|
else PENDING 초대 있음 & 만료 안됨
|
|
AuthHandler->>PortalOrgRepo: findById(invitation.orgId)
|
|
PortalOrgRepo-->>AuthHandler: PortalOrg (기관명)
|
|
AuthHandler->>AuthHandler: session.setAttribute<br/>("pendingInvitation", true)<br/>("pendingInvitationToken", token)<br/>("pendingInvitationOrgName", orgName)
|
|
AuthHandler->>Portal: redirect to /
|
|
end
|
|
|
|
%% ========================================
|
|
%% 4. 메인 페이지 팝업 표시
|
|
%% ========================================
|
|
Portal->>IndexController: GET /
|
|
IndexController->>MainPage: render index.html
|
|
|
|
MainPage->>MainPage: 세션에서 pendingInvitation 확인
|
|
|
|
alt pendingInvitation == true
|
|
MainPage-->>초대받은사용자: 팝업 표시<br/>"[기관명]에서 초대가 도착했습니다.<br/>초대를 확인하시겠습니까?"
|
|
end
|
|
|
|
%% ========================================
|
|
%% 5. 사용자 팝업 선택
|
|
%% ========================================
|
|
alt 팝업에서 "확인" 클릭
|
|
초대받은사용자->>Portal: /signup/decision?invitation=TOKEN
|
|
Portal->>UserRegisterController: showDecisionPage(invitationToken)
|
|
UserRegisterController->>UserInvitationRepo: findByToken(decodedToken)
|
|
UserRegisterController-->>Portal: 약관 동의 페이지
|
|
Portal-->>초대받은사용자: 초대 수락/거절 화면
|
|
else 팝업에서 "취소" 클릭
|
|
Note over 초대받은사용자,MainPage: 메인 페이지 유지<br/>다음 로그인 시 팝업 재표시
|
|
end
|
|
|
|
%% ========================================
|
|
%% 6. 초대 수락/거절 처리
|
|
%% ========================================
|
|
초대받은사용자->>Portal: 수락 or 거절 선택
|
|
Portal->>UserRegisterController: processInvitation(action)
|
|
UserRegisterController->>UserRegisterFacade: processInvitation(action, invitation)
|
|
|
|
alt 수락
|
|
UserRegisterFacade->>PortalUserRepo: findByEmailAddr()
|
|
UserRegisterFacade->>PortalUserRepo: updateUserToCorpUser()<br/>(PortalOrg 변경<br/>ROLE_CORP_USER 전환)
|
|
UserRegisterFacade->>UserInvitationRepo: save(invitation)<br/>status: COMPLETED<br/>completeDate: now()
|
|
UserRegisterFacade-->>Portal: 수락 성공
|
|
Portal-->>초대받은사용자: 성공 메시지<br/>로그아웃 후 재로그인 안내
|
|
Note over 초대받은사용자: 다음 로그인 시<br/>PENDING 초대 없음 → 팝업 안 뜸
|
|
else 거절
|
|
UserRegisterFacade->>UserInvitationRepo: save(invitation)<br/>status: REJECTED<br/>completeDate: now()
|
|
UserRegisterFacade-->>Portal: 거절 처리 완료
|
|
Portal-->>초대받은사용자: 거절 완료 메시지
|
|
Note over 초대받은사용자: 다음 로그인 시<br/>REJECTED 상태 → 팝업 안 뜸
|
|
end
|