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