# PBP-CS 모든 프로세스 모음 > 개발 도중 프로세스 및 코드에 대한 이해도가 낮은 이유로 개발이 어려움을 느끼며 차후 개발에서 개발 속도 및 변경 부작용을 없애고 이해도를 높이고자 이 문서를 작성함

### 2024-08-29 (현 하나증권 중심) **공병훈 교수**{style="font-style:italic"}는 플랫폼이란 "서로 연결된 관계를 맺으며 가치를 만드는 체계"라는 표현을 사용하였다. 상호의존적인 관계를 형성하며 서로 다른 그룹들간의 상호작요을 쉽게 하여 가치를 창조한다. 플랫폼에 대한 자세한 내용은 다음 링크로 확인하면 좋다.


## Login -> Assets > [로그인]페이지에서 [내 자산]으로 화면이 넘아갈때의 프로세스를 아래 기술한다. ```mermaid flowchart LR Login --> Assets ``` ### - Login ```mermaid --- title: src/app/login/page.tsx --- classDiagram direction LR class Login{ param: ref, sccofnstcd } class LoginTask{ onConfirm?(bool: boolean): void; // 로그 인 완료 } class CookieInfo{ } class Spinner{ } Login *-- LoginTask : Component Login *-- CookieInfo : Component Login *-- Spinner : Component Login <-- LoginTask : onConfirmLogin ```

- 로그인 페이지에서 URL파라미터 증권사코드 sccoFnstCd값 받아서 처리
<예)"270 (하나증권)">
그리고 증권사코드를 localStorage에 저장 저장하는 키는 각 2개임
accessKey, everywhereKey
accessKey는 웹뷰용 접근 증권사 코드, everywhereKey는 전방위용 접근 증권사 코드 라고한다... ```javascript if (sccoFnstCd) { localStorage.setItem(accessKey, sccoFnstCd.toString()); localStorage.setItem(everywhereKey, sccoFnstCd.toString()); } else { localStorage.setItem(accessKey, ''); localStorage.setItem(everywhereKey, ''); } ``` > ISSUE: 간헐적 백엔드에 270값 안 넘오는 현상 발견됨 - onConfirmLogin 함수에서는 LoginTask의 onConfirm에 함수 제공.

```javascript const onConfirmLogin = () => { if (ref !== null && ref !== undefined && ref !== '') { router.push(ref); return; } router.push('/assets'); } ``` 위의 onConfirmLogin에서 브라우저 url param의 ref를 받아서 유무 처리 후 route 처리. ** 결론적으로 Login 페이지에서 sccoFnstCd(증권사코드)를 localStorage 처리, route처리 하는 기능. {style="color:red"}

```mermaid classDiagram class LoginTask{ counselSeq?: number; onConfirm?(bool: boolean): void; // 로그 인 완료 onBack?(): void; // 화면뒤로 isTest?: boolean; isMTS?: boolean; ----------default set------ isTest = false, isMTS = false } ```

```mermaid --- title: src/components/task/login/LoginTask.tsx --- classDiagram direction LR class LoginTask{ } class AlertModal{ } class PinNumberLoginTask{ onConfirm(): void; onBack(): void; onLoginFail(bool: boolean, idx: number): void; isMTS: boolean; } class ReSignupProcess{ onConfirm, onClose, isDeviceChange = false, FailCount, isPasswordInput = false } class SignupProcess{ counselSequence?: string; onConfirm?(loginCustomerId: string): void; onClose?(): void; onBack?(): void; } LoginTask --> PinNumberLoginTask : 1) defaultLoginOption === 'pinnumber'
&& !loginFail
&& !isTest
&& !isNewUser LoginTask --> ReSignupProcess : 2) loginFail
&& !isTest LoginTask --> SignupProcess : 3) isNewUser PinNumberLoginTask --> LoginTask : 4) onConfirmLogin()
onLoginFail() ```

- isTest가 왜 존재 하는지? (true로 변경시 빈화면 나오게 됨) - defaultLoginOption = process.env.NEXT_PUBLIC_DEFAULT_LOGIN_VIEW
# 간편비밀번호 사용 여부 pinnumber or password
NEXT_PUBLIC_DEFAULT_LOGIN_VIEW=pinnumber | password
현재는 pinnumber - 위의 1), 2), 3)을 하나의 함수로 처리하는게 좋을듯 하다. 4) localStorage의 'KEY'를 가져와서 `getUser` 함수 실행


#### PinNumberLoginTask로 로그인이 되었을때 ```javascript const onConfirmLogin = async () => { const user = localStorage.getItem(KEY); if (user) { const decodeUser = decodeAES(user); await getUser(decodeUser); } else { setAlertModal({ title: '로그인 실패', content: ( <> 아이디가 없습니다. 회원가입을 안하셨다면 회원가입을 하시거나
사용 기기를 변경하셨다면
본인 인증을 해주신 후
로그인을 시도 해주세요. ) }); } }; ``` ```javascript const getUser = useCallback( async (customerId: string) => { setIsLoading(true); const customer = await getUserInfoApi({ customerId, sccoFnstCd: '', role: '' }); setIsLoading(false); if (isEmptyString(customer.userId)) { const msg = `LocalStorage에 아이디가 존재하고, 간편비밀번호 로그인에 성공했지만, DB에 회원정보가 없음(${customerId})`; commonRecordingLog(recoilFrontEndLog, 'LoginTask', 'api', msg); setAlertModal({ title: '로그인 실패', content: '회원정보를 가져올 수 없습니다.\n회원가입을 다시 해주세요.' }); } else { await fetch('/api/setSessions', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({customerId: customer.userId, sccoFnstCd}) }); if (fristLoginValue === null || fristLoginValue === undefined) { if (customer.pushStatusDate !== null && customer.pushStatusDate !== undefined) { if (customer.pushStatus === '01') { setToastMessage([ { id: getUniqueKey(), text: `${moment(customer.pushStatusDate).format( 'YYYY.MM.DD HH:mm' )} 이벤트*혜택 알림 수신에 동의하셨습니다.`, bottom: 70 } ]); } else { setToastMessage([ { id: getUniqueKey(), text: `${moment(customer.pushStatusDate).format( 'YYYY.MM.DD HH:mm' )} 이벤트*혜택 알림 수신에 거부하셨습니다.`, bottom: 70 } ]); } } localStorage.setItem(firstLoginKey, 'Y'); } setLoginState(customer); setUserId(customerId || ''); const encodeId = encodeAES(customerId); localStorage.setItem(KEY, encodeId); onConfirm?.(true); } }, [ setIsLoading, recoilFrontEndLog, setAlertModal, sccoFnstCd, fristLoginValue, setLoginState, setUserId, KEY, onConfirm, firstLoginKey, setToastMessage ] ); ```

getUserInfoApi API를 호출함 getUserInfo의 내용에 많은 정보가 기록되어 있는 것을 알 수 있음 ```javascript export const getUserInfoApi = async (obj: IUserInfoInput): Promise => { return api.get('/customer', {customerId: obj.customerId}); }; ``` ```javascript export interface IUserInfoInput { customerId?: string; sccoFnstCd: string; ci?: string; userId?: string; role: string; } export interface IUserInfoOutput { sccoFnstCd: string; // * 23.11.10 ADD yeong securitiesName: string; // * 23.11.10 ADD yeong userId: string; ci: string; di: string; password: string; mobileNumber: string; birth: string; gender: number; email: string; osType?: string; osPlatform?: string; roles?: string; token?: string; appVersion?: string; userLevel?: string; userName: string; nickName?: string; activeStep: string; joinDate?: string; lastDate?: string; authCode?: string; passwordErrorCount: number; passwordDate: string; investmentPropensity: InvestmentPropensity; // * 23.11.10 ADD yeong customerStatusCode: string; // * 23.11.10 ADD yeong pushStatus: string; // 01 등록, 02 해제 pushStatusDate: string; } ```

정치영팀장의 계정으로 접속하였을때 아래의 값을 출력함 ```json { "securitiesName": "하나증권", "userId": "5000001008", "userName": "정치영", "mobileNumber": "01051670729", "birth": "19790417", "gender": 1, "email": null, "sccoCustomerIdentifyId": null, "remarks": null, "passwordErrorCount": 0, "passwordDate": "2024-08-21 10:51:34", "activeStep": "20", "investmentPropensity": { "investmentPropensityCode": "1", "investmentPropensity": "공격투자형", "lastSurveyDate": "20240826", "remainingDateCount": 361, "validYn": "Y", "todayTryCount": 0 }, "pushStatus": "01", "pushStatusDate": "2024-08-13 14:28:51" } ``` - getUserInfoApi의 결과 값을 /api/setSessions로 전달하여 내용을 저장 - getUser함수에서 성공하면 LoginTask의 onConfirm을 Login의 onConfirmLogin으로 true를 전달한다. ```mermaid flowchart LR node_1("LoginTask") node_2("Login") node_1 --"onConfirm={true}"--> node_2 ``` Login에 있는 onConfirmLogin을 실행함으로써 /assets으로 route하게됨

### - Assets ```mermaid --- title: src/app/assets/page.tsx --- classDiagram direction LR class Assets{ } class AssetMain{ } class Spinner{ } class CookieInfo{ } class Navigation{ value: number; } class RequestReplyTask{ } Assets *-- AssetMain : Component Assets *-- Spinner : Component Assets *-- CookieInfo : Component Assets *-- AssetMain : Component Assets *-- Navigation : isOpenNavigation = true
Component Assets *-- RequestReplyTask : isOpenRequestReply = true
Component ```

- 해당 페이지에서 정상적인 경로로 접근했는지 체크함. ```javascript useEffect(() => { // 정상적인 경로로 접근했는지 체크 // 증권사 접근 시 네비게이션 Open, 일반 브라우저 접근 시(랜딩 포함) 네비게이션 Close. const isCorrectAccess = chkCorrectAccess(); setIsOpenNavigation(isCorrectAccess || isStandalone); }, []); // src/util/functions.ts // 정상적인 경로로 접근했는지 체크 export const chkCorrectAccess = () => { const companyCodeKey = process.env.NEXT_PUBLIC_ACCESS_COMPANY as string; const companyCode = localStorage.getItem(companyCodeKey); const found = PARTNER_LIST.find((item) => item.companyCode === companyCode); if (found) return true; return false; }; ``` ```mermaid classDiagram class AssetMain { } class BottomModal{ } class PosNegNumber{ } ```