# 다보리-Frontend 표준 개발자 매뉴얼 # 표준 쿼리 업데이트 서버 반영 방법 # main_api 계정 사용 방법
\[참고자료\] 1. [ussh를 통한 서버 접근](https://manual.dabory.com/books/frontend-tutorial/page/dabory-linux-ssh)
**1) Front 개발자들이 query를 추가 및 수정하여 반영해야 할 경우 2\) 혹은 특정한 이유로 weberp-go API 를 재시동해야 할 경우에** **아래와 같이 조치하여 반영할 수 있습니다. \*\* 특히 1)의 경우 query를 잘못 수정하면 전체 시스템이 다운될 수 도 있으므로 극히 주의하여야 합니다.** ```bash (1)맥북이나 git bash(윈도우)에서 해당서버의 main_api 계정으로 로그인 (ussh 사용법은 위 참고자료를 참조) ./ussh dbr02 main_api (2)로그인후 실행 command mode에서 shell script실행 main_api-query-gitpp-weberp-go-run ``` 위 명령어 실행시 - 해당 서버의 표준 query 폴더인 main\_api/weberp-queries를 gitpp해줍니다. - Redis Memory DB를 완전히 Flush하여 초기화합니다. - port-grab-killer 18080 명령어를 실행하여 18080 포트를 사용 중인 기존의 weberp-go 프로세스를 종료시킵니다. - weberp-go 실행 파일을 백그라운드에서 다시 실행하여 weberp-go API를 재시작합니다. 현재 개발서버가 아닌 운영서버인 경우 query의 첫번째 실행시에만 redis의 memory cache에 넣고 실행하고 이후 실행부터는 file을 읽어내지 않도록 속도를 개선하도록 되어있습니다. # 게시판의 사용과 커스터마이징 # 게시판의 종류와 사용방법 ### 게시판의 종류 ##### **1. 표준 게시판** - 공지형 게시판 - 공지사항 - 이벤트 - 영업문의 - 영업문의 - 배너/팝업 - FAQ(자주하는질문) - 이용약관 - 개인정보 보호정책 - 마케팅 수신 동의 - 전자금융 이용약관 - 교환환불 정책 - 소개형 게시판 - 회사소개 - 제품소개 - 특허/인증허 - 포트폴리오 - 뉴스 - 문의형 게시판 - 티켓-1대1문의 - 공개질문 - 1대1문의 --- ### **게시판 관리** ##### **- 게시판 구분(공지/소개/문의)** **[![image.png](https://manual.dabory.com/uploads/images/gallery/2024-06/scaled-1680-/o2Dimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-06/o2Dimage.png)** 모든 게시판에 대한 정보를 불러옵니다. 구분코드, PostCode, 상태, 종류설명, 카테고리 등이 포함되어 있습니다. 모든 게시판들은 psot\_type\_id를 통해 구분됩니다. ##### **- 공지형 게시판** [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-06/scaled-1680-/U6Himage.png)](https://manual.dabory.com/uploads/images/gallery/2024-06/U6Himage.png) 공지형 게시판의 자식 메뉴들이 노출됩니다. 각 메뉴에서는 해당되는 게시글들을 수정 /삭제 /복사 등 게시글 관리가 가능합니다. 공지형 게시판의 para\_name은 다음과 같습니다.
분류para\_name(조회)para\_name(등록)
공지사항notice-inputnotice
이벤트event-inputevent
배너/팝업
banner-input
banner
자주묻는 질문(FAQ)faq-inputfaq
이용약관policy-inputpolicy
개인정보 보호정책privacy-inputprivacy
전자금육 이용약관e-finance-inpute-finance
교환환불 정책refund-inputrefund
##### **- 소개형 게시판** [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-06/scaled-1680-/XXtimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-06/XXtimage.png) 소개형 게시판의 자식 메뉴들이 노출됩니다. 기능적인 부분은 위와 같습니다.
분류para\_name (조회)para\_name (등록)
회사소개intro-inputintro
제품소개production-inputproduction
특허/인증서
certificatate-input
certificatate
포트폴리오portfolio-inputportfolio
뉴스news-inputnews
##### **- 문의형 게시판** [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-06/scaled-1680-/ee2image.png)](https://manual.dabory.com/uploads/images/gallery/2024-06/ee2image.png) para\_name
분류para\_name (조회)para\_name (등록)
상품문의
item-inquiry-input
item-inquiry
상담 신청
contactus-input
contactus
1대1 문의
1to1-input
1to1
공개 질문
standard-input
standard
각 페이지에서 등록된 게시판들이 pro 페이지의 게시글로 노출됩니다. # 게시판을 Pro Page에 적용하는 방법

1대1문의 (문의형 게시판)을 pro page에 적용하기

##### **\[문의형 게시판 - 1대1 문의 적용하기 예제\]** #### **1. Controller 구성** `pro` 테마에 `Controller`를 구성합니다. `dabory/themes/pro/app/Http/Controller/etc` 디렉토리에 `OneToOneController.php`를 생성하고 메서드를 작성합니다. #### **- 외부 API 호출 설정** 백엔드 API를 호출하고 결과를 처리하기 위해 `App\Services\CallApiService`를 사용합니다. ``` class OneToOneController extends Controller {     private $callApiService;     public function __construct(CallApiService $callApiService)     {         $this->callApiService = $callApiService;     }     public function list()     {         $limit = (int)request('limit', 12);         $page = (int)request('page', 1);         $oneToOnePage = $this->callApiService->callApi([             'url' => 'list-type1-page', // api에 요청할 url 주소             'data' => [ // list-type1-page로 요청할 data                 'QueryVars' => [ // api 서버에서 Query를 식별할 수 있도록 구성한 요소들                     'QueryName' => 'pro:my-page/post-list', // pro/.../my-page/post-list/ 디렉토리 안의 쿼리 파일을 찾는다.                     'SimpleFilter' => "post_code='1to1'", // where 절에 추가                     'SubSimpleFilter' => "image_type = 'thumb'",                     'IsntPagination' => false // pagination 여부                 ],                 'ListType1Vars' => [                     'OrderBy' => request('sort', 'mx.created_on desc')                 ],                 'PageVars' => [                     'Limit' => $limit,                     'Offset' => ($page - 1) * $limit                 ]             ]         ]);     //    dump($oneToOnePage);         $oneToOnePage['Page'] = new LengthAwarePaginator($oneToOnePage['Page'], $oneToOnePage['PageVars']['QueryCnt'],             $limit, $page, ['path' => request()->url()]);         // dump($oneToOnePage);         return view('views.etc.1to1-list', compact('oneToOnePage'));     }     public function store()     {         $validator = Validator::make(request()->all(), [             'post_title' => 'required',             'post_contents' => 'required',             'pc1' => 'required',             'pc2' => 'required|email'         ]);         if ($validator->fails()) {             notify()->error(_e('Action failed'), 'Error', 'bottomRight');             return redirect()->back()                 ->withErrors($validator)                 ->withInput();         }         $response =  $this->callApiService->callApi([             'url' => 'post-act',             'data' => [                 'Page' => [                     [                         'Id' => 0,                         'PostTitle' => request('post_title'),                         'PostContents' => request('post_contents'),                         'PostTypeId' => 6,                         'Pc1' => request('pc1'),                         'Pc2' => request('pc2'),                         'Status' => '2',                         'MemberId' => session('member')['MemberId'],                     ]                 ]             ],         ]);         if ($this->callApiService->verifyApiError($response)) {             notify()->error($response['body'], 'Error', 'bottomRight');             return redirect()->back();         } //        notify()->success(_e('Action completed'), 'Success', 'bottomRight');         return redirect()->route('1to1.list');     }     public function show($id)     {         $listType1Book = $this->callApiService->callApi([             'url' => 'list-type1-book',             'data' => [                 'Book' => [                     [                         'QueryVars' => [                             'QueryName' => 'pro:my-page/post-details',                             'SimpleFilter' => "post_code='1to1' and mx.id = $id",                             'IsntPagination' => true,                         ],                         'PageVars' => [                             'Limit' => 1                         ]                     ],                     [                         'QueryVars' => [                             'QueryName' => 'pro:my-page/post-details-prenext',                             'SimpleFilter' => "mx.id = (select max(id) from pro_post where id < ${id} and post_type_id = 6)",                             'SubSimpleFilter' => "",                             'IsntPagination' => true,                         ],                         'PageVars' => [                             'Limit' => 1                         ]                     ],                     [                         'QueryVars' => [                             'QueryName' => 'pro:my-page/post-details-prenext',                             'SimpleFilter' => "mx.id = (select min(id) from pro_post where id > ${id} and post_type_id = 6)",                             'SubSimpleFilter' => "",                             'IsntPagination' => true,                         ],                         'PageVars' => [                             'Limit' => 1                         ]                     ],                 ]             ]         ]);     //    dd($listType1Book);         if ($this->callApiService->verifyApiError($listType1Book)) {             notify()->error($listType1Book['body'], 'Error', 'bottomRight');             return redirect()->back();         } //        dump($listType1Book);         return view('views.etc.1to1-details', compact('listType1Book'));     } } ```
1대1문의 구현을 위한 Controller 예시
이 구성으로 `list-type1-page` URL로 data가 요청되면, api 서버는 `weberp-queries`에서 해당 URL의 QueryVars에 작성해준 조건에 해당하는 SQL 파일을 찾고, 데이터로 쿼리 조건절을 구성하여 호출하고 반환합니다.
#### **응답 처리 및 View 반환** API로부터 응답을 받아 변수에 담고, View 페이지에서 필요한 데이터를 가공하거나 변환하여 반환합니다. View 페이지에서는 반환받은 배열 데이터를 통해 페이지 작업을 수행할 수 있습니다. #### **TEST** Controller와 view 페이지 작업이 완료되었다면 erp/pro 각각의 페이지에서 테스트를 진행합니다. 예제에서 진행했던 1대1문의 게시판을 확인해보겠습니다. pro 페이지에 만들어준 문의하기 게시판에서 문의글을 작성한 뒤 [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-07/scaled-1680-/aHOimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-07/aHOimage.png) erp 페이지로 이동하여 1대1문의 게시판을 확인합니다. [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-07/scaled-1680-/z5Iimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-07/z5Iimage.png) 위와같이 문의내용이 잘 들어왔습니다.
참고사항 erp에 게시판 설치하기 [erp 게시판 커스터마이징](https://manual.dabory.com/books/frontend/page/01386)
# 문의형 게시판 커스터마이징하기 # 공지형 게시판 커스터마이징하기 # 소개형 게시판 커스터마이징하기 # 게시판 커스터마이징 방법 [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-07/scaled-1680-/lZfimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-07/lZfimage.png) 게시판을 커스터마징 하기 위해서는 erp 게시판 구분 메뉴에서 게시판 구분 등록을 통해 새로운 커스터마징 게시판을 등록해야합니다. [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-07/scaled-1680-/7jcimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-07/7jcimage.png) 게시판 구분 등록 예시 [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-07/scaled-1680-/ogeimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-07/ogeimage.png) 게시판이 생성된 것을 확인합니다. [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-07/scaled-1680-/Espimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-07/Espimage.png) 생성해준 게시판을 사용자 메뉴에 따로 만들어주기 위해서 메뉴 확장과 API 관리 - 사용자 메뉴로 이동합니다. [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-07/scaled-1680-/pZIimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-07/pZIimage.png) 추가 버튼을 눌러 사용자 메뉴를 추가해줍니다. [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-07/scaled-1680-/nvoimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-07/nvoimage.png) 전체 캐시삭제를 해줘야 사용자 메뉴에 반영이 됩니다. [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-07/scaled-1680-/JFOimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-07/JFOimage.png) 새로운 사용자 메뉴가 추가됐습니다. 이제 상담내역 게시판의 crud를 구현해주기 위해서 erp의 파라메터를 만들어줍니다. 파라메터는 사용자 메뉴를 추가할때 입력했던 위치에 만들어줘야 합니다. 해당 위치로 이동하여 디렉토리를 생성하고 contatctus-custom-input.json 이라는 파라메터 파일을 생성해줍니다. 내용은 아래와 같습니다. ``` {     "//list-type-1": "simple and plain list by query of table join",     "General": {         "Title": "상담내역 관리",         "PageApi": "list-type1-page",         "ActApi": "post-act"     },     "QueryVars": {         "QueryName": "kbgolf::post/contactus-custom-input",         "FilterName": "",         "FilterValue": "",         "FilterDate": "mx.official_date",         "SimpleFilter": "pt.post_code = 'contactus-custom'"     },     "HeadSelectOptions": [         {             "Value": "xls-report",             "Caption": "(기존)엑셀 다운로드"         },         {             "Value": "custom-xls-report",             "Caption": "엑셀 다운로드",             "Component": "dummy",             "Parameter": "/list/list-type1/download/contactus-custom",             "ThemeDir": "/kbgolf/erp"         },         {             "Value": "new",             "Caption": "상담신청 등록"         },         {             "Value": "multi-delete",             "Caption": "상담신청 일괄 삭제"         }     ],     "//FormVars": "FormVars[0]-caption, FormVars[1]-searchPopup",     "FormVars": [         {             "ListButton": "조회",             "DateRange": "",             "DateNavi": "이전 | (오늘지정) | 이후",             "Date": "자료 등록일",             "From": "부터",             "To": "까지",             "FirstRange": "",             "SecondRange": "",             "ThirdRange": "",             "FourthRange": "",             "AddTotalLine": "",             "SelectPopup": "팝업 선택(라디오 버튼)",             "MultiPopup": "",             "ChartPopup": "",             "DownloadList": "",             "ShowOnlyClosed": "",             "Balance": "",             "OrderBy": "표시 순서",             "FilterOption": "검색 조건",             "SimpleOption": "상태별 검색"         }     ],     "FilterSelectOptions": [         {             "Value": "",             "Caption": "=검색 조건="         },         {             "Value": "mx.pc1",             "Caption": "신청자"         },         {             "Value": "mx.pc5",             "Caption": "회원권명"         },         {             "Value": "mx.pc3",             "Caption": "거래 구분"         },         {             "Value": "mx.pc4",             "Caption": "회원권 구분"         }     ],     "SimpleSelectOptions": [         {             "Value": "",             "Caption": "전체"         },         {             "Value": "mx.pc7='상담접수'",             "Caption": "상담접수"         },         {             "Value": "mx.pc7='상담완료'",             "Caption": "상담완료"         }     ],     "//ListType1RangeVars": "[0]-filter, [1]-component, [2]-parameter",     "ListType1RangeVars": [         {             "FirstRange": "",             "SecondRange": "",             "ThirdRange": "",             "FourthRange": ""         },         {             "FirstRange": "",             "SecondRange": "",             "ThirdRange": "",             "FourthRange": ""         },         {             "FirstRange": "",             "SecondRange": "",             "ThirdRange": "",             "FourthRange": ""         }     ],     "DateNaviOptions": [         {             "Value": "day",             "Caption": "일"         },         {             "Value": "week",             "Caption": "주"         },         {             "Value": "month",             "Caption": "월"         },         {             "Value": "quarterly",             "Caption": "분기"         },         {             "Value": "semiannual",             "Caption": "반기"         },         {             "Value": "year",             "Caption": "년"         },         {             "Value": "all",             "Caption": "전체"         }     ],     "SelectPopupOptions": [         {             "Caption": "상담신청 관리",             "Component": "kbgolf::popup.popup-form1.form-a.post.contactus-custom-form",             "Parameter": "kbgolf::/popup/popup-form1/form-a/post/contactus-custom"         }     ],     "// OrderByOptions": "OrderBy Options//첫번째 Value가 Default",     "OrderByOptions": [         {             "Value": "mx.created_on desc",             "Caption": "문의일자 역순"         },         {             "Value": "mx.created_on asc",             "Caption": "문의일자 순서"         }     ],     "//BalanceOptions": "Show OnlyBalaceRemained or All",     "BalanceOptions": [         {             "Value": "",             "Caption": "전체 보기"         },         {             "Value": "c10 > 0",             "Caption": "잔량있는 것만"         }     ],     "DisplayVars": {         "IsListFirst": true,         "IsExcelColumn": true,         "IsSelectPopupHidden": true,         "IsC1Popup": "1",         "InitLines": 10,         "HeadHeight": "140",         "BodyHeight": "570"     },     "ThumbContainerVars": {         "ListWidth": 60,         "ListHeight": 50     },     "// ListVars": "ListVars[0]-caption, ListVars[1]-size(px), ListVars[2]-align->right(number) left(left)",     "ListVars": [         {             "$Radio": "$Radio",             "$Check": "$Check",             "No": "번호",             "C1": "신청자",             "C2": "연락처",             "C3": "거래구분",             "C4": "회원권 구분",             "C5": "회원권명",             "C6": "희망가격",             "C7": "요청사항",             "C8": "상태"         },         {             "$Radio": "2",             "$Check": "2",             "No": "2",             "C1": "5",             "C2": "4",             "C3": "4",             "C4": "5",             "C5": "5",             "C6": "5",             "C7": "7",             "C8": "4"         },         {             "$Radio": "center",             "$Check": "center",             "No": "center",             "C1": "center",             "C2": "center",             "C3": "center",             "C4": "center",             "C5": "center",             "C6": "center",             "C7": "center",             "C8": "center"         }     ] } ```
이제 pro 페이지와 연동하여 상담내역을 관리할 수 있는 게시판이 구성됐습니다.
pro 페이지 적용은 아래 링크를 통해 체크할 수 있습니다.
참고사항 [pro 페이지 적용방법](https://manual.dabory.com/books/frontend/page/pro-page)
# 백엔드 설치 방법 > ## 설치전 준비사항 - 다보리 Git Server 사용자 등록 ([다보리 깃 서버 바로가기](http://git.daboryhost.com:10880/)) --- > ## 웹서버에 백엔드(main\_api) 설치하기 1\. 서버에 로그인합니다. 2\. home 디렉토리로 이동하여 백엔드를 설치해줄 디렉토리를 생성합니다. 예제에서는 main\_api로 지정했습니다. ```bash cd /home mkdir main_api ``` 3\. 생성해준 main\_api 디렉토리로 이동합니다. ```bash cd main_api ``` 4\. 다보리 git server에 mybin 레포지토리로 이동합니다. ([mybin 바로가기](http://git.daboryhost.com:10880/dabory/mybin)) 5\. HTTP url을 복사합니다. [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-08/scaled-1680-/ZVYimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-08/ZVYimage.png) 6\. git clone을 통해 mybin을 가져옵니다. ```bash git clone http://git.daboryhost.com:10880/dabory/mybin.git ``` 7\. mybin이 설치되었는지 확인합니다. 8\. 정상적으로 설치되었다면 다음 명령어를 통해 간편하게 설치할 수 있습니다. ``` ./init-weberp-go-install-in-main_api ``` 위 명령어 실행시 다보리 컴포저블의 백엔드 어플리케이션 패키지를 설치합니다. \* 만약 스크립트 파일이 실행되지 않는다면 아래 명령어를 통해 실행권한을 부여합니다. ```bash cd mybin chmod +x init-weberp-go-install-in-main_api ``` 다시 main\_api 디렉토리로 이동하여 명령어를 실행합니다. ```bash cd .. ./init-weberp-go-install-in-main_api ``` 9\. 설치가 완료되었다면 아래 디렉토리들이 존재하는지 확인합니다. (1). cache-key-pair (2). weberp-go (3). weberp-queries 10\. 설치가 완료되었습니다. 백엔드 앱을 실행하겠습니다. 아래 명령어를 통해 실행 스크립트 파일을 실행합니다. ``` ./mybin/without-update-weberp-go-run ``` [![image.png](https://manual.dabory.com/uploads/images/gallery/2024-08/scaled-1680-/fFMimage.png)](https://manual.dabory.com/uploads/images/gallery/2024-08/fFMimage.png) 11\. 백엔드 서버가 성공적으로 실행되었습니다. ##### 백엔드 설치항목 - cache-key-pair - wheberp-go - weberp-queries - mybin ##### 참고자료 - [cache-key-pair란?](https://manual.dabory.com/books/frontend/page/cache-key-pair) # cache-key-pair란? > ## cache-key-pair 다보리 컴포저블에서는 app 등록시 각각의 app별로 암호화된 key pair 값을 부여합니다. 이 key-pair 값들은 서버에 저장 되는데 만약 서버에 문제가 생겼을 경우를 대비하여 cache-key-pair 파일에 캐시된 key-pair 값이 저장됩니다. 더 자세한 사항은 아래 참고자료를 참고하시기 바랍니다. ##### 참고자료 - [다보리 rest api의 구성](https://manual.dabory.com/books/frontend-tutorial/chapter/2-restfull-api) -