.. | ||
README.md |
PBP-CS 모든 프로세스 모음
개발 도중 프로세스 및 코드에 대한 이해도가 낮은 이유로 개발이 어려움을 느끼며 차후 개발에서 개발 속도 및 변경 부작용을 없애고 이해도를 높이고자 이 문서를 작성함
2024-08-29 (현 하나증권 중심)
공병훈 교수{style="font-style:italic"}는 플랫폼이란 "서로 연결된 관계를 맺으며 가치를 만드는 체계"라는 표현을 사용하였다. 상호의존적인 관계를 형성하며 서로 다른 그룹들간의 상호작요을 쉽게 하여 가치를 창조한다. 플랫폼에 대한 자세한 내용은 다음 링크로 확인하면 좋다. https://brunch.co.kr/@mobility/62
Login -> Assets
[로그인]페이지에서 [내 자산]으로 화면이 넘아갈때의 프로세스를 아래 기술한다.
flowchart LR
Login --> Assets
- Login
---
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는 전방위용 접근 증권사 코드 라고한다...
if (sccoFnstCd) {
localStorage.setItem(accessKey, sccoFnstCd.toString());
localStorage.setItem(everywhereKey, sccoFnstCd.toString());
} else {
localStorage.setItem(accessKey, '');
localStorage.setItem(everywhereKey, '');
}
ISSUE: 간헐적 백엔드에 270값 안 넘오는 현상 발견됨
- onConfirmLogin 함수에서는 LoginTask의 onConfirm에 함수 제공.
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"}
classDiagram
class LoginTask{
counselSeq?: number;
onConfirm?(bool: boolean): void; // 로그 인 완료
onBack?(): void; // 화면뒤로
isTest?: boolean;
isMTS?: boolean;
----------default set------
isTest = false, isMTS = false
}
---
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' <br> && !loginFail <br> && !isTest <br> && !isNewUser
LoginTask --> ReSignupProcess : 2) loginFail <br> && !isTest
LoginTask --> SignupProcess : 3) isNewUser
PinNumberLoginTask --> LoginTask : 4) onConfirmLogin() <br> 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)을 하나의 함수로 처리하는게 좋을듯 하다.
- localStorage의 'KEY'를 가져와서
getUser
함수 실행
PinNumberLoginTask로 로그인이 되었을때
const onConfirmLogin = async () => {
const user = localStorage.getItem(KEY);
if (user) {
const decodeUser = decodeAES(user);
await getUser(decodeUser);
} else {
setAlertModal({
title: '로그인 실패',
content: (
<>
아이디가 없습니다. 회원가입을 안하셨다면 회원가입을 하시거나 <br /> 사용 기기를 변경하셨다면 <br /> 본인
인증을 해주신 후 <br /> 로그인을 시도 해주세요.
</>
)
});
}
};
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의 내용에 많은 정보가 기록되어 있는 것을 알 수 있음
export const getUserInfoApi = async (obj: IUserInfoInput): Promise<IUserInfoOutput> => {
return api.get<IUserInfoOutput>('/customer', {customerId: obj.customerId});
};
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;
}
정치영팀장의 계정으로 접속하였을때 아래의 값을 출력함
{
"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를 전달한다.
flowchart LR
node_1("LoginTask")
node_2("Login")
node_1 --"onConfirm={true}"--> node_2
Login에 있는 onConfirmLogin을 실행함으로써 /assets으로 route하게됨
- Assets
---
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 <br>Component
Assets *-- RequestReplyTask : isOpenRequestReply = true <br>Component
- 해당 페이지에서 정상적인 경로로 접근했는지 체크함.
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;
};
classDiagram
class AssetMain {
}
class BottomModal{
}
class PosNegNumber{
}