myDocument/quantec/cs/quantecAllTask
DESKTOP-KUL8TT4\siina 4068ecc958 용어 업로드
2024-09-03 08:56:15 +09:00
..
README.md 용어 업로드 2024-09-03 08:56:15 +09:00

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)을 하나의 함수로 처리하는게 좋을듯 하다.

  1. 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{
  
  }