국궁앱 <활로> 개발기

서주·2024년 7월 14일
post-thumbnail

2023년 3월부터 12월 24일(입대 2일 전🥵)까지 약 10개월 간 국궁 앱을 만들었다.
배포하고 바로 입대해버려서 7개월이 좀 지난 시점에 앱 개발 과정에서의 어려움과 개선 사항을 정리해보고자 한다.

개발 동기

취미로 활을 쏜다. 활을 쏘며 앱에 기록을 하는데 시중의 국궁앱은 사용이 불편해 새로운 앱이 있으면 하는 바람이 있었다.
2022년 2분기에 컴공, 디자인과 선배랑 국궁 앱 개발 논의를 했으나 바쁜 일정으로 무산되었다.
그리고 2023년 3월, 휴학도 한 겸 국궁 앱을 혼자 만들어보기로 결심했다!

개발 준비

리액트 네이티브 서적을 구매하고 두 달동안 클론코딩하며 공부했다.

5월부터 국궁 앱의 기본적인 기능, 레이아웃만 정해놓고 애자일하게 개발을 시작했다.

기존의 국궁 앱들의 문제점은 다음과 같다.

  • 올드한 디자인
  • 시수기록의 불편한 ux
  • 커뮤니티 기능의 부재
  • 애플 네이티브 앱의 부재

기존 국궁앱과 차별을 두기 위해 위 기능들의 구현에 방점을 찍었다.

커뮤니티와 시수기록을 주 기능으로 하고, 에브리타임의 디자인을 벤치마킹하고자 하였다.

메인 컬러는
여기
에서 도움을 많이 받았다.

메인 컬러와 기본적인 레이아웃을 정했다.

시수기록, 커뮤니티를 구현하려면 사용자 데이터를 처리할 서버와 db가 필요했다.

firebase를 통해 단순하게 개발하고자 했으나 처음부터 직접 구현해보고 싶어 express를 사용하기로 하였다. (firebase 찍먹한 거 코딩학원 강사할 때 요긴하게 써먹었다 )

express로 restAPI를 구현하고, mariaDB를 사용하기로 했다.
(MYSQL은 상업적 이용 시 문제가 생길 수 있다고 들었다)

express와 mariadb를 처음 사용해보았다. 리액트 네이티브에 적용하기 전에 React + express + mariaDB를 사용한 CRUD게시판을 만들어 보았다.

개발 시작

express와 mariadb를 어느 정도 익힌 후 다시 앱개발로 돌아왔다.
앱 구조도에 따른 네비게이션을 제작했다.
스택 네비게이션을 사용하는 곳과 조건부 렌더링을 사용해야 하는 곳을 구분했다.

전역변수를 사용하기 위해 useContext를 공부했다.

클라우드서비스

앱 배포 시 최대한 변수를 줄이고 싶어서 개발 초기부터 AWS EC2에 express를 돌리고 AWS RDS를 연결했다.

트래픽 과부화를 대비해(?) 네트워크 로드벨런싱을 구현하였다.
인스턴스 생성 시 기본입력되는 값?에 git clone을 포함한 초기 설정을 넣었고, 인스턴스가 최소 2개, 최대 4개까지 스케일 아웃 되도록 했다.
하지만! 과금 폭탄으로 철회하였다.

컴퓨터공학과 과동아리 서버 사용이 가능해 EC2에서 과동 서버로 이전하였다. 데이터베이스는 RDS를 유지했다.

로그인

클라이언트와 서버 간 통신을 위해 JWT을 공부했다.

인증/인가를 위해 네이버, 카카오 로그인을 구현했다.
react-native-seoul을 통해 네이티브 로그인을 구현하려 했으나 호환성 문제로 웹뷰를 통한 로그인을 구현하였다.
웹뷰는 로그인되면 회원 데이터를 전송하고, redirect URL로 창이 바뀐다. 조건부 렌더링을 통해 회원 데이터가 들어오면 로그인 완료 컴포넌트로 바뀌게 하였다.

문제는 Redirect URL이었다.
Redirect URL로 바뀌고 컴포넌트가 전환되기까지 시간 지연이 있다.
결국 무한로딩하는 사이트를 만들어 Redirect URL에 연결하기로 했다.
무한로딩하는 프로젝트를 리액트로 만들고 빌드해서 netilfy에서 배포한 후 Redirect URL로 연결시켜 해결했다.

로그인되면 서버는 클라이언트에게 accessToken을 발급하고 클라이언트는 이 토큰을 헤더에 담아 모든 요청을 보낸다.
(웹뷰 로그인 규정이 자주 바뀌어서 이 부분은 공식문서를 참고했다.)
RefreshToken도 구현하려 했는데 시간 이슈로 못하고 대신 AccessToken 기한을 길게했다 ㅎ.ㅎ
클라이언트 단에서 우선적으로 accesstoken을 검사해서 만료되면 로그아웃되게 했다.

  • (private key는 단순한 걸로 하지 말고 꼭 랜덤문자열 생성기 같은 거 써야한다 !!)
  • (앱스토어 배포 시, 소셜 로그인 기능이 있으면 애플 로그인도 구현해야 한다. 배포 단계에서 빠꾸먹어서 애플로그인도 추가했다.)

사용자 인증/인가 파트까지 구현을 끝내고, 각 탭 별 기능을 구현해야 했다.

데이터베이스

효율적인 디비를 짜기 위해 데이터베이스 정규화를 공부했다.
userId는 데이터베이스 자체 카운트로 했다. 카카오, 네이버 둘 다 중복되지 않는 id를 제공하긴 하지만 네이버는 정수인 반면, 카카오는 문자열을 제공한다. 효과적인 사용자 검색을 위해 회원가입 시 독립된 userId를 사용했다.

사용자 테이블, 게시글 테이블, 시수기록 테이블 등의 테이블을 만들었다.
목차별로 테이블을 나누되, join을 적게 하는 방향으로 야물딱지게 나눴다.
(학교 도서관에서 주로 코딩하는데 학교 서버가 3306포트를 막고 있어서 포트를 변경해서 진행했다… 이것땜에 엄청 헤매었다 ….)

Data()로 시간을 데베 저장하는데 9시간 차이나는 TimeZone 문제로 한참 삽질했었다.

쿼리문 직접 작성했다.
SQL injection공격을 막기 위해 ‘?‘를 쿼리문으로 대체시켰다.
(주변에서 ORM 왜 안썼냐는데 당시에는 ORM을 몰랐다 ㅜㅡㅜ)

사용자의 시수에는 중, 불, 과녁좌상단 중, 과녁상단 중, ..(9분할), 좌 불, 좌상 불, ..(8분할)을 기록하기 위해 각 시수를 저장하는 배열을 생성했다. 하지만 각 날, 각 달의 총 시수, 평균 관중 시수도 출력하는 기능을 생각하고 있어, 배열의 끝에 각 날짜의 총 시수, 관중한 시수를 추가했다.
시수를 기입하거나 수정할 때 총 시수, 관중 시수도 같이 변경된다.

UI/UX 개선


달력을 통해 이전 날의 시수를 보거나 통계를 확인할 수 있게 하였다.
github push잔디에서 영감을 받아 평균 시수가 높은 날은 파란색이 진해지게 하였다.

효과적인 UX를 위해 습사일지 저장버튼을 없애고 싶었다.
값이 변경될 때마다 서버에 올리는 것은 트래픽 낭비라고 생각되어 방안을 모색하였다.
습사일지는 2가지로 나눌 수 있다.
금일 습사일지, 이전 습사일지

금일 습사일지

금일 습사일지 데이터는 로컬에 저장한다.
날짜가 바뀌었을 때, 사용자가 앱에 접속하면, 로컬에 저장된 이전 습사일지 데이터를 서버로 전송하고, 새로운 습사일지를 로컬에 저장한다.

이전 일 습사일지

이전 일의 습사일지를 변경하는 사용자들은 대다수가 습사 중에 변경한다. 그러므로 변경 후 메인화면이나 이정 화면으로 되돌아간다.
이전 습사일지가 변경되고, 사용자가 이전 습사일지 컴포넌트를 벗어나면 서버로 전송한다.

탭 별 기능

홈 탭, 시수기록 탭, 활터지도 탭, 내정보 탭으로 나뉜다.

홈 탭

홈 탭의 커뮤니티는 4개로 나눴다.

커뮤니티 기능

공지게시판, 자유게시판, 홍보게시판, 정보게시판
공지게시판은 관리자만 create update delete가 가능하다
각 게시글은 해당 사용자만 update delete가 가능하다.

게시글 작성 시 UTF-8에 해당하는 문자만 작성이 가능하도록 했다.

한글 입력을 위해 database charset 설정을 변경했다.

게시글 목록에 게시글의 모든 내용을 불러오면 각 카드의 크기가 들쑥날쑥해진다. overflow : hidden을 하면 글자가 중간에 잘린다. 일정 글자 이상은 …으로 표시되게 했다.

게시글이 많은 경우 불러오는 데 시간이 오래 걸린다.
무한스크롤 기능을 사용해 끝까지 내리면 10개를 추가로 select하도록 구현했다.

게시글 좋아요와 댓글 기능을 구현하려 했는데 시간 이슈로 못했다.
좋아요 기능 구현을 위해 UserId, postId만 구성된 테이블을 따로 생성했었다. postid에 해당하는 userid를 카운트하고자 했다.
나중에 완성해봐야겠다 ..(전역하고)

그룹 기능


사용자는 그룹에 가입해 서로의 최근 시수를 공유할 수 있다.

그룹은 공개, 비공개(password 입력)그룹으로 나뉘고 모든 사용자가 생성할 수 있다.
그룹 리스트도 게시글과 마찬가지로 10개씩 보인다. 그룹이 많아질 경우를 대비해 검색 기능을 추가했는데, 연속된 문자 검색이 아닌 그룹 명을 오타 없이 기입해야 가입이 가능하다.

그룹에 가입하면 홈 탭에 가입된 그룹이 보이는데, 컴포넌트 리랜더링을 통해 가입된 그룹을 업데이트한다.(memo로 불필요한 리랜더링 방지가 필요하다)

그룹에 가입되면 그룹에 가입된 사용자의 최근 2주동안의 습사기록을 토대로 그룹의 평균시수 1, 2, 3위가 나열된다.(추후에 좋아요 기능 추가하려고 한다)

활터지도 탭


지역활터, 공공활터, 실내 활터로 구분하였다.
대한궁도협회 홈페이지에 전국 활터의 주소가 나와있다.
파이썬으로 이를 크롤링해서 주소를 좌표로 변환하고, 지도의 변환된 좌표에 마커를 찍었다.

카드형으로 ui를 만들고 지역활터는 전화번호와 위치를 클릭 시 알 해 알 수 있게 하였다.
네이버 예약을 받는 실내 활터는 네이버 예약을 연결했다.

좌표 변환이 매끄럽지 못하여 일부 활터 포커싱 기능에 문제가 있다. 추후 개선 예정이다.

장비 탭


궁사들이 자주 사용하는 쇼핑몰들과 국궁신문 벼룩시장을 연결했다.

개인정보 보호

앱에서 개인정보를 사용하려면 사용자로부터 개인정보 약관 동의를 받아야 한다.
개인정보 약관 전문을 찾아 활로에 맞춰 변경한 후, 구글로 간단히 웹사이트 제작해 회원가입 시 보이게 했다.

배포

배포하는 데에만 3주 이상 소모하였다.
구글과 애플의 개발자 계정을 생성해야 한다.
구글은 생성할 때만 비용을 지불하지만 애플은 매년 비용을 지불해야 한다. 개비쌈

안드로이드

플레이스토어 배포 준비할 때쯤, 구글 정책이 변경되어서 20명의 사람들에게 2주간 비공개 테스트를 해야 한다고 한다. 입대 3주 남긴 시점이라 빠르게 비공개 테스트를 시작해야 했다.

하지만 빌드를 하고 테스트를 하는 과정에서 무수히 많은 에러가 났다. 그 에러는 위 링크에서 정리했다.
대부분의 알 수 없는 에러는 호환되지 않는 라이브러리가 문제였다.

IOS

testflight라는 앱을 설치해서 테스트할 수 있다.
여기서 개화났던 게 에러 코드도 안나오고 앱 실행 도중에 종료되어버리는 일이 발생했다.
이진탐색으로 빌드..또 빌드,..해서 30번정도 빌드한 결과 원인을 찾았다.

testflight 테스트 완료 후 제출을 했는데 세 가지 이유로 반려당했다.

  1. 회원탈퇴 기능이 있어야 한다.
    급하게 만들다가 회원탈퇴 기능을 못넣어서 회원탈퇴 기능 추가했다.

  2. 소셜로그인 기능이 있다면 애플 로그인도 넣어야 한다.
    네이티브 애플 로그인 라이브러리를 사용해서 해결했다…
    이것도 에러코드 안나와서 너무빡셌다….

  3. 아이패드용 캡쳐본 구라치지마
    세 종류의 화면 크기(아이폰, 아이패드 , ..)에 맞는 캡쳐본을 같이 제출해야 하는데 아이패드가 없어서 아이폰 캡쳐본 길이만 늘려서 제출했었다. 이게 걸려서 아이패드 빌려 새로 캡쳐해 제출했다.

expo로 빌드했는데 expo는 많이 빌드하면 안드로이드 1달러, IOS 2달러의 빌드 비용이 있다.
빌드를 너무 많이 해서 빌드 비용만 10만원 냈다 ㅜㅜ

배포 성공



어찌어찌하다가 결국 입대 이틀 전 완전 배포 성공 ~!

입대 이후

동아리 서버를 사용하는 게 큰 결점이었다. 동아리방이 방학 때 수시로 정전된다고 한다. 결국 훈련소 때 서버가 꺼져서 2달정도 앱 공백기가 있었다.
휴가나가서 서버를 다시 켜긴 했지만 글을 작성하는 최근(2024.07.14)에 또 서버가 꺼졌다.
당분간 앱 운영은 어려울 것 같다.

전역하고 다시 재정비해서 재출시해야 하겠다 !

0개의 댓글