Files
eapim-portal/kjb-docs/mermaid/invite-sequence.mermaid
T
2025-11-25 14:29:22 +09:00

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