오늘은 리액트 node js express 를 사용하여 MySQL 을 연동할것이다. 근데 오늘 몸상태가 최악..ㅠ 

 

1. 프로젝트 생성 

나는 vscode와 웹스톰을 번갈아가면서 쓴다 ㅎ 이번에는 vscode 로 진행을 하였다.~

터미널 창을 킨후

npx create-react-app simple-react-board --template typescript

로 실행하면 파일이 생성되면

 

각종 파일들에 들어가서 다 변경해주고

필요한 모듈을 설치해준다.

npm i react react-dom typescript

npm i @types/react @types/react-dom @types/node

 

tsconfig.json 에 들어가서 

변경 나는 es6를 사용할거니깐!

 

이제 서버 프로젝트를 새로 생성해준다.

서버 프로젝트로 폴더 이동 후

npm init -y

생성 된걸 확인했으면 이제 관련 모듈들을 설치해주자

 

npm install express body-parser mysql
npm install nodemon

nodemon은 서버 코드가 수정됐을때 자동으로 서버를 재시작해주는 모듈

 

index.js 를 하나 만들어주고

const express = require('express');
const app = express();
const PORT = process.env.port || 8000;

app.listen(PORT, ()=>{
console.log(`running on port ${PORT}`);
});

 

node index.js  를 치면 실행

 

실행된게 보이면 성공

 

패키지json 에 스크립트에 코드추가

"start": "node index.js",

"dev": "nodemon index.js"

 

터미널에서 컨트롤 c 로 서버를 끄고 아래 명령어로 실행시킨다.

npm run dev

 

이렇게 나오면 성공~

데이터베이스 연동을 위해 index.js 수정

위로 변경 후 로컬호스트를 킨다.

/ 으로 첫 화면인 홈으로 진입시 seccess 적어둔게 잘뜬건 보인다 제대로 연동이 되었는지 확인을 한다!

Workbench 로 들어가서 쿼리를 실행해서 /으로 진입시 1값을 잘넣고 있는지 확인하자.

 

쿼리문 작성해서 보면 아주 잘넣어지고있다~

 

다음에는 클라이언트 프로젝트에서 axios 를 사용해보겟다 ~

오늘은 Mysql 을 설치하고 mysqlworkbench 를 사용하여 연결해보는 일을 해볼거다!

리액트에서 express 를 이용해서 디비에 연결 할거라서 ㅎ 선작업한다.

 

homebrew  를 사용하여 mysql 을 설치 할거다.

터미널창을 킨후 

brew install mysql 

 

설치가 끝나면 제대로 설치 되었는지 버전 확인

mysql -V

 

설치완료 되면 

mysql.server start

 

서버실행이 제대로 되었으면 위처럼 동작

 

이번에는 터미널로만 관리하기 힘드니깐 툴도 깔아주기로하자!

MySQLWorkbench 를 설치 해준다.

https://dev.mysql.com/downloads/workbench/

 

MySQL :: Download MySQL Workbench

Select Operating System: Select Operating System… Microsoft Windows Ubuntu Linux Red Hat Enterprise Linux / Oracle Linux Fedora macOS Source Code Select OS Version: All Windows (x86, 64-bit) Recommended Download: Other Downloads: Windows (x86, 64-bit), M

dev.mysql.com

위에 주소로 접속 다운로드 하고 mysql 을 설치한 터미널로 다시 돌아가서

 

mysql_secure_installation 를 친다.

 

치고나면 아래와같은 화면이 뜬다.

 

비밀번호 복잡성 유무에 대한 질문이다. 나는 안복잡한 비번 쓸거니깐 ! no!

 

비번 치라고 나오면 치고

그뒤에 질문들은 생략~

 

이제 접속시도

 mysql -u root -p 

명령어 치면 비번 입력하라는 창나옴 비번치면 입력 완료

위에서 설치한 데이터베이스 클라이언트 를 킨다.

 

잘연결되어있당!~

이전 글 링크

https://asdf1326.tistory.com/4

 

NUXT Vue 타입스크립트를 이용한 카카오페이 연동 1탄

회사에서 카카오페이를 사용자사이트에 연결해달라는 요청이 들어왔다~ 카카오페이를 연동하는 방법에 대해서 간략하게 일기를 쓸예정이다! 카카오페이 개발 참고페이지 - 카카오페이 개발API

asdf1326.tistory.com

 

이전에 이제 승인요청 부분을 진행하여 이어가도록 하겟당.

kakaopay/index.vue 로돌아와서 로직을 처리해주자!

<template>
  <div>

  </div>
</template>
<script lang="ts">
import {Component, Vue} from "nuxt-property-decorator";
import ServerUrlDefines from '~/common/defines/serverUrlDefines';
import PurchaseRequestType, {PurchaseResultType} from "~/common/type/purchaseInfoType";
import {PaymentAgentType} from "~/common/type/paymentAgentType";
import {siteStore} from "~/store";
import {KakaoPayCompleteRequestDtoUtils} from "~/common/api/service/payment/kakaopay/dto/kakaoPayCompleteDto";
import {kakaoPayApi} from "~/common/api/service/payment/kakaopay/KakaoPayApi";
import {kakaoPayReadyUtils} from "~/common/api/service/payment/kakaopay/dto/kakaoPayReadyDto";
import NotificationStoreUtils from "~/store/utils/NotificationStoreUtils";

export class KakaoPayIndexUtils {
  static KeyOrderNo = 'orderNumber';
  static keyTid = 'tid';
  static KeyPurchaseResult = 'naverPayPurchaseResult';

  static setOrderNo(orderNo: string): void {
    sessionStorage.setItem(this.KeyOrderNo, orderNo);
  }

  static removeOrderNo(): void {
    sessionStorage.removeItem(this.KeyOrderNo);
  }

  static getOrderNo(): string | null {
    return sessionStorage.getItem(this.KeyOrderNo);
  }

  static payType(payType: string): void{
    sessionStorage.setItem('payType',payType);
  }

  static getPayType(): string | null{
    return sessionStorage.getItem('payType');
  }

  static setTid(tid: string): void{
    sessionStorage.setItem(this.keyTid,tid);
  }

  static getTid(): string | null{
    return sessionStorage.getItem(this.keyTid);
  }

  static removeTid(): void {
    sessionStorage.removeItem(this.keyTid);
  }

  static setPurchaseResult(request: PurchaseRequestType): void {
    sessionStorage.setItem(this.KeyPurchaseResult, JSON.stringify(request));
  }

  static removePurchaseResult(): void {
    sessionStorage.removeItem(this.KeyPurchaseResult);
  }

  static getPurchaseResult(): PurchaseRequestType | null {
    const jsonString = sessionStorage.getItem(this.KeyPurchaseResult);

    return jsonString ? JSON.parse(jsonString) : null;
  }

}

@Component({ name: 'kakaopay' })
export default class extends Vue {
  orderNo: string | null = null;
  tid: string | null = null;
  purchaseRequest: PurchaseRequestType | null = null;
  pgtoken: string | null = '';
  payType: string | null = null;

  mounted(): void {
    const query: string = window.location.search;
    const param = new URLSearchParams(query);
    const pgtoken = param.get('pg_token');

    this.pgtoken = pgtoken;

    this.orderNo = KakaoPayIndexUtils.getOrderNo();
    KakaoPayIndexUtils.removeOrderNo();

    this.tid = KakaoPayIndexUtils.getTid();
    KakaoPayIndexUtils.removeTid();

    this.purchaseRequest = KakaoPayIndexUtils.getPurchaseResult();
    KakaoPayIndexUtils.removePurchaseResult();

    this.payType = KakaoPayIndexUtils.getPayType();


    this.completePayment();
  }

  async completePayment(): Promise<void> {
    const completeRequest = KakaoPayCompleteRequestDtoUtils.createDto(this.tid, this.orderNo!, this.pgtoken!, this.payType!);

    try {
      sessionStorage.removeItem('payBack');
      const response = await kakaoPayApi.KakaoPayComplete(completeRequest);

      const purchaseResult = new PurchaseResultType(this.orderNo!, PaymentAgentType.KakaoPay, this.purchaseRequest!);

      siteStore.updatePurchaseResult(purchaseResult);


      siteStore.setPurchaseRequest(this.purchaseRequest!);

      await this.$router.push('/buy/complete');
    } catch (e) {
      const error = e as Error;
      console.log(error.message);
      const errMsg = error.message.substring(error.message.indexOf('-')+1, error.message.indexOf('-')+4);
      sessionStorage.removeItem('payBack');
      if(errMsg && error.message.includes('code')){
        alert(kakaoPayReadyUtils.errMessage(errMsg));
        const backPage =  sessionStorage.getItem('buyBackPage');
        location.href = `${ServerUrlDefines.wwwServer}${backPage}`;
      }else{
        alert(error.message);
        const backPage =  sessionStorage.getItem('buyBackPage');
        location.href = `${ServerUrlDefines.wwwServer}${backPage}`;
      }

    }
  }

}

</script>

 

카카오페이 index.vue 에는 카카오페이로 백엔드가 요청할때 필요한 값들을 셋팅하여 던져준다~

직접 결제 요청을 진행하면 스므스 하게 잘진행이된다. 이것으로 코인에 개발일기 끄읏~

 

 

 

회사에서 카카오페이를 사용자사이트에 연결해달라는 요청이 들어왔다~

카카오페이를 연동하는 방법에 대해서 간략하게 일기를 쓸예정이다!

 

카카오페이 개발 참고페이지

- 카카오페이 개발API : https://developers.kakao.com/docs/latest/ko/kakaopay/common
- 카카오페이 데모 : https://developers.kakao.com/demo/pay/index
- 응답코드 : https://developers.kakao.com/docs/latest/ko/reference/rest-api-reference

 

필요한 디렉터리 파일

pages/buy/kakaopay/failPage.vue // 카카오페이 실패일 경우

pages/buy/kakaopay/index.vue // 승인요청에 대한 처리 로직, 클래스 등 필요한 로직 처리

pages/buy/index.vue // 결제페이지

 

api 로직 디렉터리

common/api/service/payment/kakaopay/KakaoPayApi.ts // 카카오페이 api 로직

common/api/service/payment/kakaopay/dto/kakaoPayReadyDto.ts // 카카오페이 준비 dto 

common/api/service/payment/kakaopay/dto/kakaoPayCompleteDto.ts // 카카오페이 승인요청완료 dto

 

부수적으로 필요한 ts파일은 생략하겟습니당.!

 

먼저 결제 페이지인 pages/buy/index.ts 에서

주문대기 생성을 하여 order 쪽 백엔드쪽에서 요청을 실행하고 나면 주문번호가 생성이 된다.

그후에 카카오페이를 선택 했을 시에 일어나는 로직을 만들도록 하자!

 

buy/index.ts 에서 결제방법은 컴포넌트로 새로 만들어서 분기처리해준다.

components/views/buy/PaymentMethod.vue 에 결제방법 UI를 생성 시켜준다.

카카오페이에서 제공하는 이미지를 사용하여 해당 UI를 만들어준다.

회사 기획서에 맞게 페이에이전트타입으로 분리하여 그려준다.

대략 이런식으로 만든 후

 

pages/buy/index.vue 로 이동한다.

대기주문을 생성이 완료된후 로직을 탈수있게 코드를 짜준다.

 

proceedPayment 함수를 호출하면 아래와 같은 코드를 삽입

proceedPayment 안에 중간 내용 페이먼트 에이전트 타입에 따른 실행 코드 생성

setorderno를 만든이유는 카카오페이는 자신들의 페이지로 이동을 하고있다.

그러면 페이지간 이동이 일어나서 전에 내가 store 에서 저장했던 내용들이 날라간다.

그래서 그앞단인 buy 페이지에서 미리 세션스토리지에 값을 가지고 있기로 해서 위와 같이 만들었다.

 

카카오페이에서는 리다이렉트 url을 3개를 받고있는 이유이다.  아래 카카오페이에서 보여주는 예시를 보면

요런식으로 응답값을 준다. 위에 값은 우리회사 백엔드 개발자가 준다고 하니 나는 거기에 맞는 처리를 진행하였다.

하이브리드 웹이라서 웹뷰로 모바일까지 진행하고있다보니 안드로이드나 ios에 대한 처리는 따로 하지않았다!

회사 규격에 맞게 셋팅에 맞게 하면 된다고 보여진다.

 

kakaoPayReadyDto.ts



export interface kakaoPayReadyResponseDto{
  tid: string;
  // eslint-disable-next-line camelcase
  next_redirect_pc_url: string;
  // eslint-disable-next-line camelcase
  next_redirect_app_url:string;
  nextRedirectMobileUrl: string;
  createdAt: string;
}

export interface kakaoPayApproveRequestDto{
  tid: string;
  orderId: string;
  pgTocken: string;
  totalAmount: number;
}

export interface  kakaoPayReadyRequestDto {
  orderNumber: string;
  goodsName: string | undefined;
  buyerName: string;
  buyerPhone: string;
  paymentAmount: string;
  paymentMethod: string;
  paymentAgentType: string;
  approvalUrl: string;
  cancelUrl: string | null;
  failUrl:string | null;
  quantity: number;
  buyerEmail: string;
  pointAmount: string;
  couponNumber: string | null ;
}

export class kakaoPayReadyUtils {
  static createDto(
    orderNumber: string,
    goodsName: string,
    buyerName: string,
    buyerPhone: string,
    paymentAmount: string,
    paymentMethod: string,
    paymentAgentType: string,
    approvalUrl: string,
    cancelUrl: string | null,
    failUrl: string | null,
    quantity: number,
    buyerEmail: string,
    pointAmount: number,
    couponNumber: string | null ,
                   ) : kakaoPayReadyRequestDto{
      return {
        orderNumber,
        goodsName,
        buyerName,
        buyerPhone,
        paymentAmount,
        paymentMethod,
        paymentAgentType,
        approvalUrl,
        cancelUrl,
        failUrl,
        quantity,
        buyerEmail,
        pointAmount: pointAmount > 0 ? String(pointAmount) : '',
        couponNumber,
      };
  }

  static errMessage(errMsg: string){
    let newStr = '';
    switch (errMsg) {
      case '400':
        newStr  = '요청한 파라미터값이 잘못되었습니다.';
        break;
      case '701':
        newStr  = '결제 인증이 완료되지 않았습니다.';
        break;
      case '702':
        newStr = '이미 결제 완료된 결제건 입니다.';
        break;
      case '703':
        newStr = '결제 포인트 금액이 잘못됐습니다.';
        break;
      case '704':
        newStr = '결제 금액이 잘못됐습니다.';
        break;
      case '705':
        newStr = '지원하지 않는 결제 수단입니다.';
        break;
      case '706':
        newStr = '주문번호와 다른 값으로 API 출했습니다.';
        break;
      case '707':
        newStr = '결제 준비 API에서 요청한 partner_user_id와 다른 값으로 결제승인 API 호출 했습니다.';
        break;
      case '708':
        newStr = '잘못된 pg_token로 결제승인 API를 호출했습니다.';
        break;
      case '710':
        newStr = '결제 취소 API 호출 시 취소 요청 금액을 취소 가능액보다 큰 금액으로 요청했습니다.';
        break;
      case '721':
        newStr = 'TID가 존재하지 않습니다.';
        break;
      case '722':
        newStr = '금액 정보가 잘못된 경우';
        break;
      case '723':
        newStr = '결제 만료 시간이 지났습니디.';
        break;
      case '724':
        newStr = '단건 결제 금액이 잘못되었습니다.';
        break;
      case '725':
        newStr = '총 결제 금액이 잘못되었습니다.';
        break;
      case '726':
        newStr = '주문 정보가 잘못되었습니다.';
        break;
      case '730':
        newStr = '가맹점 앱 정보가 잘못되었습니다.';
        break;
      case '731':
        newStr = 'CID 가 잘못됐습니다.';
        break;
      case '732':
        newStr = 'GID 가 잘못됐습니다.';
        break;
      case '733':
        newStr = 'CID_SECRET이 잘못됐습니다.';
        break;
      case '750':
        newStr = 'SID가 존재하지 않습니다.';
        break;
      case '751':
        newStr = '비활성화된 SID로 정기결제 API를 호출했습니다.';
        break;
      case '752':
        newStr = 'SID가 월 최대 사용 회수를 초과했습니다.';
        break;
      case '753':
        newStr = '정기 결제 API 호출 시 partner_user_id가 SID를 발급받았던 최초 결제 준비 API에서 요청한 값과 다릅니다.';
        break;
      case '761':
        newStr = '입력한 전화번호가 카카오톡에 가입하지 않았습니다.';
        break;
      case '780':
        newStr = '결제 승인 API 호출 실패';
        break;
      case '781':
        newStr = '결제 취소 API 호출 실패';
        break;
      case '782':
        newStr = '정기 결제 API 호출 실패';
        break;
      case '783':
        newStr = '승인 요청을 할 수 없는 상태에서 결제 승인 API를 호출';
        break;
      case '784':
        newStr = '취소 요청을 할 수 없는 상태에서 결제 취소 API를 호출';
        break;
      case '785':
        newStr = '결제와 취소를 중복으로 요청';
        break;
      case '797':
        newStr = '1회 결제 한도 금액을 초과했습니다.';
        break;
      case '798':
        newStr = '허용되지 않는 IP를 사용하셧습니다.';
        break;
      case '799':
        newStr = '등록된 웹사이트 도메인의 설정과 요청 도메인이 다릅니다.';
        break;
    }
    return newStr;
  }
}

 

kakaoPayApi.ts

 

카카오페이 요청 dto를 만들어주고 try 문에 다가

pc 일떄와 모바일때를 분리하여 백엔드에서 던져주는 url로 카카오페이로 페이지 이동을 시킨다~

 

사용자 페이지로 이동하여 현재까지 잘되었는지 테스트를 해본다!

아래는 카카오페이지 이동 후 화면이다.

위에 창도 잘뜨는건 확인 했으니 네트워크를 열어서 요청값들이 잘넘어갔는지도 확인을해준다.

 

내가 셋팅한것처럼 완료,실패,사용자취소 url 도 잘 셋팅이 되어서 넘어가있다!

사용자 취소 부분도 잘되는지 확인 해보자

우리 회사 기획서 상 결제페이지에 남아있지않도록하고 (중복결제에대한 문제점을 생각하셔서 그렇게 한것같다.) 매장이나 상품페이지로

이동하도록 기획을 하셧다.

 

위에 얼럿은 미리 내가 코딩을 해서 페이지 이동시 시스템 얼럿창이 뜨도록 설계를 하였다.

자 이제 승인요청 완료 부분이다!

 

kakaoPayCompleteDto.ts

export interface KakaoCompleteRequestDto {
  tid: string | null;
  orderNumber: string;
  pgToken: string;
  payType: string;
  paymentMethod: string;
}

export class KakaoPayCompleteRequestDtoUtils {
  static createDto(tidNo: string | null, orderNum: string, pgTokenStr: string, payTypeStr: string): KakaoCompleteRequestDto {
    return {
      orderNumber: orderNum,
      tid: tidNo,
      pgToken: pgTokenStr,
      payType: payTypeStr,
      paymentMethod: 'KAKAOPAY'
    };
  }
}

export interface KakaoCompleteResponseDto {
  data: {
    aid: string;
    tid: string;
    cid: string;
    // eslint-disable-next-line camelcase
    partner_order_id: string;
    // eslint-disable-next-line camelcase
    partner_user_id: string;
    // eslint-disable-next-line camelcase
    payment_method_type: string;
    amount:{
      total: number;
      // eslint-disable-next-line camelcase
      tax_free: number;
      vat: number;
      point: number;
      discount: number;
      // eslint-disable-next-line camelcase
      green_deposit: number;
    };
    cardInfo:{
      // eslint-disable-next-line camelcase
      purchase_corp: string;
      // eslint-disable-next-line camelcase
      purchase_corp_code: string;
      // eslint-disable-next-line camelcase
      issuer_corp: string;
      // eslint-disable-next-line camelcase
      issuer_corp_code: string;
      // eslint-disable-next-line camelcase
      kakaopay_purchase_corp: string;
      // eslint-disable-next-line camelcase
      kakaopay_purchase_corp_code: string;
      // eslint-disable-next-line camelcase
      kakaopay_issuer_corp: string;
      // eslint-disable-next-line camelcase
      kakaopay_issuer_corp_code: string;
      bin:string;
      // eslint-disable-next-line camelcase
      card_type: string;
      // eslint-disable-next-line camelcase
      install_month: string;
      // eslint-disable-next-line camelcase
      approved_id: string;
      // eslint-disable-next-line camelcase
      card_mid: string;
      // eslint-disable-next-line camelcase
      interest_free_install: string;
      // eslint-disable-next-line camelcase
      card_item_code: string;
    };
  }
}

 

 

2탄에서 계속!

이번에 마케팅 팀에서.. 또 일거리를 맹글어주셧다..ㅎㅎ 처음 접해보는 백그라운드 알림! 전화가 오면 클라이언트쪽에서 백엔드에서 던져주는 값으로 브라우저에서 알림창,모달창을 띄어주는 일이다! 기존에 있던 소스들에서 유지보수겸으로 추가하는거라서 소스가 지저분해서 꽤나 예를 먹은 .... ㅠ 나중에 리팩토링하거나.. 수정을 좀 해줘야할것같다..

 

일단 첫작업으로는 파이어베이스 npm 을 설치를 해준다. 

현재 관리자에서는 vue 2 를 사용하여 여기에 맞는 npm 모듈을 설치! 파이어베이스가 말이 좀 많던데 node 13버전에서도 무리없이 돌아가긴한다 ㅎ

 

파이어베이스 모듈이 필요하다!

npm i@firebase/messaging 

으로 설치 해준다

 

설치 후 백그라운드 js 를 사용하기 위한 js 파일을 생성 (백그라운드 js 가 궁금하면 구글링하면 자세하게 설명이 나온다~fcm 동작원리도 아주 자세하게 나온다~ 궁금하면 검색!~개발자는 언제나 검색~ㅋㅎ)

public 폴더안에 firebase-messaging-sw.js 파일을 생성해준다.

 

생성 후에 파이어베이스 필요한 정보 삽입 회사 api 키니깐 ㅎ 가려놓깅(아래에서 자세하게 설명)

자 이렇게 셋팅하고 위에 키는 아래에 파이어베이스 콘솔창에서 따오자

프로젝트 설정에 들어가서 일반 클릭후
내앱에서 sdk 설정 및 구성에서 파이어베이스콘피그 복사 후 내가 사용 용도에 맞게 넣어준다.

일단 우리회사는 vue2 로 진행중이고.. 노드 버전도 좀 하위버전을 사용중이라서 여러가지 시도했지만 잘안먹혀서 나는아래방식대로 진행하였다

 

내코드는




 
firebase.initializeApp({
...파이어베이스 콘솔에서 복사해온값 붙여넣기
})

class CustomPushEvent extends Event {
constructor(data) {
super('push');

Object.assign(this, data);
this.custom = true;
}
}


 
요런식으로 구성을 하였다.
백그라운드에서 사용할 메시징 처리인데 꽤나 애먹었다.. 처음써보는 백그라운드에서 도는 정적 js 에 익숙치 않아서 ㅠ(import 가 불러오질못했다.. 아주 미치는줄...)
 
셋팅도 완료했으니 실질적으로 사용할 곳으로 이동하여 코드 작성해준다.
로그인시 알림요청 권한 처리와 백엔드로 요청을 보내는 코드를 작성했다.
이미 완성이 된 코드에서 유지보수성 처리라서 좀 꽤나 애를 먹었다....

위에 부분도 파이어베이스 공식 사이트에서 대략 흟어보면서.. 감으로 작업을 하였다.

로그인 쪽 뷰에서는 이런식으로 코드를 작성하여 로그인 할때 파이어베이스에서 받은 fcm 토큰을 백엔드에게 전달해준다.

로그인을 하면! 이렇게 허용하라는알림창이 뜬다~

이렇게 백엔드 요청 파라미터값들도 잘들어가있다~

 

현재 우리 사이트에 적용한 원리는 전화로 해당되는 매장에 전화 시 백쪽에서 받아서 파이어베이스 토큰을 가지고있는 pc 로 값을 전달하여 

클라이언트에서 해당 값을 알림창으로 보여주고 화면이 켜져있는경우에는 연락처로 조회가 되게 하는 화면이다.

 

일단 우리 회사에 맞게 화면이 켜있으면 모달창이 어디서든 떠야 하기때문에 App.vue와 헤더.vue에 추가적인 소스를 추가하기로했다.

라이프 사이클 마운티드에다가 아래 코드를 작성

app.vue
app.vue

이벤트 버스 사용시 beforedestroy 를 사용 안하면 이벤트 가 계속 살아있어서 여러번 호출을 하기 때문에 작성 해준다~.

 

메서드 안에

app.vue navigator.serviceWorker

요로코롬 작성해준다. 나는 또 이벤트 버스를 사용하여 topNav.vue 에 값을 넘겨줄것이다.!

백에서는 이지콜등 회선을 연결하여 테스트할수있는 휴대기기를 주셧당 이걸로 테스트를 진행할것이다!

관리자에서 미리 셋팅 한 번호로 내 휴대전화기로 전화를 걸면 테스트를 할수있는 상황이다. 하지만 이지콜이랑 무슨 계약건때문에 개발에서 테스트를 진행이 무리가 있어서 포스트맨으로 다시 테스트 진행...

 

헤더쪽 분리 컴포넌트인 topNav.vue 에서 코드는 아래와 같이 정의를 한다. app.vue 에서 이벤트를 수신을 받으면 동작할수있게 이벤트 버스로 동작하게 한다.

topNav.vue
topnav.vue

전개발자가 쓰고 있는 템플릿에 맞게 모달창을 띄우고 닫고를 설정해주고 매장관리자가 아닌 권한이 있는사람은 못보도록 막아둔다.

이벤트 버스를 여러군데쓰면 찾기도 힘들고 어렵지만.. 서로다른 곳에 위치한 컴포넌트여서 일단은 대략적으로 사용 이벤트버스는 되도록이면 안쓰는게 가독성도 좋아지고 유지보수성도 향상되지만 나는 일단 어쩔 수 없이 진행! 다음에 전개발자가 만들고간 코드 전체적으로 리팩토링 할때 그때 수정하도록...하겠다. 이렇게 하여 프론트 소스는 완료!

포스트맨을 열어서 테스트를 진행한다.!

 

포스트맨에서 보낼 바디값을 셋팅한후 보내기를 하면!

포그라운드 상태에서는 예약하기 모달창이 뜨고

백그라운드 상태에서는 알림창이 열린다!

 

이것으로 코인의 개발일기 끄읏

현재 vue 3 + 타입스크립트 + 넉스트를 사용하여 사용자 페이지를 만들었다. 

영업팀에서 제안이 하나 들어왔다. 현재 우리 사용자사이트와 saas 모드로 제공 가능한 홈페이지를 분리시켜달라고!

하나의 소스로 각각의 페이지로 보여야하는 사이트를 제공하기 위해서 ...

패키지 json 에서 스크립트 부분을 수정하였다

 

 

요런식으로 node_env 셋팅 후 ! yarn 으로 실행 시 분리하여 배포도 가능하게 만들기 위해서 

 빌드 쪽도 추가 해준다.

기존의 나는 vue2로 관리자를 유지보수 하는 개념으로만 수정하여 타입스크립트와 넉스트에 익숙하지 않았지만 

클라이언트 쪽 언어는 구글링 하면 거의 대부분 이해가 쏙쏙 간다 ㅎㅎ(아마도 리액트 하신분들은 더쉬울것이다. 스토어 개념, es6, 웹팩 등등 만있으면 다 똑같은듯 싶다! 최근에 리액트 공부도하는중인데 리덕스 next 쿼리.js 재밌댜..어렵지만..)

추가로.. 윈도우 쪽에서만 작업을 하다보니 npm 이 익숙했지만 이번에 새로 mac에서 작업을 시작하여 yarn 을 사용하여 프로젝트를 진행하여 비슷무리? 해서 이것도 그닥 어렵지 않았다! 

 

saas 로 실행 시킬경우 이런식으로 셋팅을 하여 쓰면 된다!

ts 파일로 분리시켜서 저장시켜준다음
쓰고싶은곳에서는 이런식으로 불러와서 사용한다.

 

무리없이 진행하다가 관리자에서 셋팅한 값들이 api 호출 하여 돔이 그려지기 전 인 시점인 process.server 에서 실행하여 꼭 가져와야하는 데이터들이 있엇다 사이트 색상이라던지 디스플레이에 뿌려줄 정보라든지 등등 화면이 깜박거리면서 다른색으로 변경되는걸 방지 하기 위해서 store/index.ts 에서 스토어에 정보를 셋팅 해준뒤 가져다 쓰는 식으로 변경을 해야했다.

코드가 살짝 지저분하다! 아직 준비중이라서..ㅎㅎ일단 되는걸 확인해야한다!

요런식으로 대강 작성해주고 가장 중요한부분!

개발쪽과 운영쪽에서에 환경은 틀리다.

지금 개발쪽은 회사 자체내에 서버를 구축해서 사용중이다. 리눅스에 vm 을 뛰운후 거기서 nginx 를 사용하여 개발서버에서 테스트를 진행중이다.  운영쪽은 azure 클라우드를 사용중이다!! 

 

실제로 저장된 스토어를 사용하기 위하여 셋팅을 준비한다!

async asyncData(context: Context) {

나는 컴포넌트 데이터를 로드하기전에 뿌려줄 데이터라서 asyncData 를 사용하였다!

reqRootDomain = DnsUtils.rootDomain(saasStore.contextDataUrl);

요런식으로 값을 담고!~ 

await SaasStoreUtils.siteNameAct(reqRootDomain, context);

이렇게 호출을 하였다!

 

문제가 하나있었다. !.. 운영과 개발에 배포후 실행한결과 개발서버는 너무 잘됐지만 운영서버에서 

해당에러가 뜬다.. 난해했다.. 왜이러지 왜이러지 하면서 계속 프론트 소스에서만 잘못이 있겟거니 하면서 서버 미들웨어에서 호출하는등..엄청난 삽질했지만 동일한 에러가 계속 떳다.. 왜이러누...하다가 애저 쪽에서 로그(애저 접속 컨테이너 클릭 로그 클릭~)를 보니

넉스트서버init 은 내가찍었고..

context.req.headers.host

 에서 127.0.0.1 이 찍힌후 그뒤에는 설정한 도메인명이 마구마구 찍혓다..

문제점이 프론트소스가 아니라 애저에서 뭔가 던지는 느낌?! 엄청난 삽질과 백엔드 개발자분에 도움으로찾아낸결과

내가 이해하기로는 애저에서 확인용으로 127.0.0.1을 던져서 정상적인 사이트인가에대한 여부를 체크하는것같았다! 정확하진 않지만..

프론트 소스도 젠킨스에 설정후 ci/cd로 애저에 컨테이너로 띄우고있는 형태라서 조금 더 힘들었다!

프론트개발자지만.. 애저 공부좀 해야겠다.. 애저를 모르니 ㅠㅠ 엄청난 삽질을 ....

추후에..! 백엔드 개발도 할거긴 하니깐! 애저공부도 틈틈히 해야겠당!

 

이렇게 이해한후 실험으로 127.0.0.1 에대한 예외처리를 하거나 하면 되지만!~ 나는

딱히 예외처리가 필요없어서 127.0.0.1 이들어올시 백엔드 api 를 호출을 안하였더니 

성공적!으로 운영에서도 실행이 되었다~ 운영과 개발쪽에서는 이런식으로 다차이가 나므로 프론트쪽에서만 문제점을 찾지 말고 클라우드쪽 로그도 유심히 보는게 좋을듯 싶다~ 이상으로 강코인의 개발일기 끄읏!~

+ Recent posts