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