중앙대학교

[TastyNav] #1: 중앙대학교 맛집 앱 개발 시작!

카루-R 2024. 1. 17. 10:39
반응형

환영합니다, Rolling Ress의 카루입니다.

따로 언급은 안 했는데, 저는 현재 COMP 동아리에 소속되어 있습니다. 개인적으로 매우 만족하는 동아리 중 하나예요. 이 동아리에 들어올 때 좀 우여곡절이 있었는데(^^,,) 어쨌든 무사히 들어오게 되었습니다.

지금은 팀 프로젝트를 진행중이에요. 저희 팀은 중앙대학교 주변 맛집 앱을 만들고자 합니다. TastyNav는 개발 코드명이에요. 아직 앱 이름이 정해지지 않아서, 도메인이나 내부적으로는 TastyNav를 사용하고 있습니다.

  • 개발 언어: JavaScript (프론트: React.js with PWA, 백엔드: Node.js)

1) 자료조사

첫째로, 맛집과 메뉴 목록을 조사했습니다. 공유 엑셀 파일을 이용해서 정보를 취합했습니다. 맛집 이름, 대표메뉴, 메뉴 목록, 추천 인원수, 카테고리, 거리, 전화번호, 주소, WGS84 좌표, 영업시간 등 다양한 정보를 담고 있습니다.

2) DB 설계 및 데이터 업로드

1학기 강의에서 DB 관련 내용을 다루었는데, 정규화 개념을 새롭게 알게 되었습니다. 사실 DB는 단순히 데이터만 넣는다고 끝나는 게 아니죠. 어떤 거를 키(Key)로 설정할지, 나머지 행들과의 관계는 어떻게 정할지 등 생각보다 복잡한 관계가 얽혀있습니다. 일단 지금 설계한 DB는 제3정규형(3NF)을 만족합니다.

왼쪽이 Primary key이고, 오른쪽은 Relation입니다. 어차피 A -> A를 만족하니까 그냥 최소한의 칼럼명만 썼습니다. 대강 어떻게 테이블이 구성되어 있는지 이해가 되시죠? 하나는 식당 정보만, 하나는 메뉴 정보만 담고 있는 겁니다. 두 테이블에서 공통으로 식당이름을 저장하고 있으니, 나중에 이 점을 이용하여 자료를 조회하면 되겠죠. Relation 2의 PK는 (식당이름, 메뉴)지만 FK는 식당이름이 되겠군요.

SQL DB에 데이터를 삽입할 때는 INSERT INTO ~ 구문을 사용합니다. 그런데 이거 저희가 조사한 데이터셋이 좀 많아요. 그래서 엑셀 파일을 pandas에서 불러온 후, 전처리를 거쳐 자동으로 query를 작성해주는 프로그램을 따로 제작했습니다. 이러면 깔끔하게 쿼리가 만들어진 게 보이죠. 이걸 MSSQL DB에 날려주면 간단히 끝납니다.

3) 백엔드 API 제작

 

백엔드는 Node.js로 개발했습니다. 사실 Java + Spring이나 C# + ASP.NET을 할지 심각하게 고민을 많이 했는데, 그냥 Node.js로 했습니다. 사실 백엔드 스터디 때 이걸 배웠기 때문에, 이참에 써먹어봐야죠.

MSSQL DB와 직접 통신하는 방식으로 구현되었습니다. SQL Connection Pool을 이용해서 연결을 유지하고, 프론트에서 요청이 들어오면 JSON 형태로 반환하는 구조입니다. 자료가 없으면 404, 서버에서 처리 중 오류가 나면 500 코드를 함께 반환합니다. 프론트에서는 이 코드를 이용해서 요청이 성공했는지 확인할 수 있겠지요.

4) 프론트엔드 제작

ReactJS를 이용하여 프론트엔드를 개발했습니다. 맛집 '지도'니까 지도가 필요한데, 이 지도는 KakaoMap API를 이용했습니다. API 키를 발급받고, 리액트 프로젝트를 생성하여 지도를 만들어주었습니다. 지도 컴포넌트는 'KakaoMap.js'에서 관리하고 있습니다.

5) 프론트-백 API 통신 구현

프론트에서는 useEffect 함수 내에서 지도를 그립니다. 이때 search 파라미터에 훅을 걸어두었습니다. App.js에서 사용자가 검색창에 어떠한 단어를 입력하면, 입력된 단어의 변화를 감지하고 지도 그리기가 트리거됩니다. 그러면 내장되어있는 검색 기능이 동작합니다. 검색 결과에 맞는 맛집 목록만 받아 마커를 생성할 수 있습니다. 내부적으로는 SQL의 LIKE 구문을 이용합니다. 참고로 쿼리를 작성할 때는 JavaScript 내장 String Interpolation (`string${var}`)이 아닌, input() 메서드를 사용해야 합니다. 자칫 SQL Injection 공격에 취약해질 우려가 있습니다.

6) 서버에 올리기

원격지 서버에서는 Windows Server 2022를 사용중입니다. 꼭 필요한 포트만 열어두어야겠지요? 기본적으로는 모든 포트가 DenyAllInBound옵션에 의해 막혀있습니다. 여기서 HTTP로 통신할 80, 추후 HTTPS로 통신할 443 포트를 열어줍니다. 이 둘은 프론트에서 작동합니다. 백엔드 포트는 8080과 8443 포트를 사용하는데, 개발용으로 열어두겠습니다. 사실 뭐 사용자 정보를 저장하는 것도 아니고, 민감한 내용은 아니라서 열어두어도 그렇게까지 문제가 되지는 않을 거예요. 안전불감증...

방화벽에서도 해당 포트를 열어주어야 합니다. 아까 설정한 건 Azure 자체에서 서버로 들어가는 (외부 방화벽) 포트 설정이었고, 지금은 서버 자체에서 관리하는 (내부 방화벽) 포트입니다. 둘 다 열어주어야 정상적으로 동작합니다.

 

다음으로 "npm run build"를 입력하여 배포용 앱을 생성합니다. 보통 npm start 해서 로컬에서 테스트하는 경우가 많은데, 이걸 그대로 쓸 순 없습니다. 그것도 사실 Node 기반으로 돌아가는 거거든요. 여기서는 Windows Server에 내장된 IIS(Internet Information Service) 서버를 이용하도록 하겠습니다.

내장 기능이긴 한데 Add Roles 해서 따로 추가를 해줘야 동작합니다. 이후 IIS Manager에서 각종 설정을 마무리해주면 됩니다. 그리고 아까 빌드를 한 후 build 폴더가 생겼을텐데, 거길 서버의 루트 디렉터리로 설정해주면 끝납니다.

7) 도메인 연결하기

저는 내도메인.한국 사이트를 이용했습니다. 주의할 것은 '웹포워딩'이 아니라 'IP연결(A)'에 작성해야 한다는 겁니다. 혹시 서버가 IPv6를 쓴다면 AAAA에 작성해주세요. 여기에 Azure 서버의 외부 주소를 작성하면 도메인 연결이 완료됩니다. 저는 tastynav.kro.kr을 사용하겠습니다.

8) HTTPS 적용하기

ZeroSSL을 이용하여 인증서를 발급받겠습니다. Chrome 브라우저에서는 https 연결이 아니면 PWA 앱을 설치하지 못하게 합니다. (옵션 자체가 뜨지 않습니다) ZeroSSL에서 도메인을 입력한 뒤, CNAME 인증 또는 파일 업로드를 통해 도메인의 소유자임을 인증할 수 있습니다. 편한 방법으로 진행한 뒤, 인증서를 발급받으면 됩니다. 번들 crt, 서버 crt, 개인키 파일을 다운받습니다.

certutil -mergepfx certificate.crt certificate.pfx

CMD에서 위 명령어를 입력하여 crt, key 파일을 합쳐 pfx 파일을 만듭니다. ZeroSSL 기준 private.key로 이름이 되어 있을 텐데, 반드시 certificate.key로 이름을 바꾸어야 합니다.

완료되면 서버로 pfx 파일을 전달한 뒤, IIS 세팅에서 서버 인증서에 pfx 파일을 등록해주면 됩니다.

IIS 옵션으로 들어가서 Binding 옵션을 통해 80포트와 443 포트를 연결해주어야 합니다. 아까 발급받은 도메인을 입력해주세요. 그리고 인증서는 방금 등록한 인증서를 골라주시면 됩니다. 참고로 하위도메인의 경우 각각 다른 인증서를 발급받고, 등록해야 합니다.

백엔드에서 구동중인 Node.js 서버도 HTTPS를 적용하여 다시 빌드했습니다. 자꾸 Failed to fetch 오류가 나던데, 아마 HTTPS-HTTP Mixed 모드여서 문제가 생겼던 듯해요. 이거 해결하느라 며칠 밤을 샜는지.

9) 모바일 디바이스 테스트

제가 폰을 4개씩 들고 다니는 이유가 있습니다. 여러 상황에서 테스트를 해야 하거든요. 여튼, HTTPS 적용을 하고 난 뒤 PWA 설치 팝업이 성공적으로 떴습니다. 앱 설치가 끝나면 네이티브 앱처럼 부드럽게 동작합니다. 이제 본격적으로 UI를 다듬을 차례입니다.

반응형