💻 프로젝트
개발인원 | 프론트 3명 , 백엔드 5명
개발기간 | 22.07 - 22.08 (3주)
서비스 소개
RG 는 쉽고 빠르게 자전거 모임을 주최하고, 참여할 수 있는 서비스 입니다.
기존의 모임 서비스(네이버카페 및 도싸 커뮤니티)가 가지는 문제를 해결하고자 하였습니다.
- 모임주최자는, 정해진 형식이 없는 자유 게시글 형식으로 게시글 작성에 오랜 시간이 소요된다.
- 모임참여자는, 내가 참여할만한 자전거 모임을 빠르게 발견하기 어렵다.
RG는 다음과 같은 기능을 통해 문제를 해결합니다.
- 쉽고 빠르게 작성할 수 있는 자전거 모집 특화 Form 제공
- 다양한 필터를 통한 빠른 모임 검색
- 주최/참가한 모임 관리 기능 제공
🛠 기술 스택
- React | Typescript | Recoil | Storybook
🧑🏽💻 담당 역할 및 기능
- 인증 및 인가, 유저 관련 페이지 담당
- 팀 내 스크럼 진행 및 노션 문서화 담당
🖥 세부 개발 내용
1. 인증 및 인가
- 1) 인증 로직 설계
- AccessToken을 LocalStorage에 저장하는 인증 로직 설계
- AccessToken을 Recoil State로, RefreshToken을 Cookie에 저장하는 인증 로직으로 리팩토링
- RefreshToken을
secure
,httpOnly
옵션을 설정하여 CSRF 공격을 대비
- 2) CustomRoute를 통한 로그인 유지 및 인가 처리
- Route를 감싸고 있는 AuthRoute 구현
- 페이지 이동 / 새로고침이 발생할 때 마다, 현재 state로 보관 중인 AcessToken의 유효성을 확인
- API 요청 응답에 따라, 현재 로그인 여부(isAuth)를 update
- 3) AxiosInterceptor를 활용하여 토큰 refresh 진행
- AxiosInterceptor의 request 옵션을 통해, 현재 AceessToken을 항상 request Header에 담아 전송
- AccessToken 만료의 경우, Cookie에 저장된 RefreshToken을 통해 새로운 AccessToken을 발급받고, 기존 request를 다시 요청함
- RefreshToken 만료 응답이 올 경우, 기존 저장된 Token을 모두 삭제하고 로그인 페이지로 redirect
2. 유저 페이지
- 1) 유저 정보 수정 및 유저 평가 기능 구현
- 2) Storybook을 통한 개발 및 컴포넌트 공유
💡 성장 경험
다양한 환경에서의 협업 경험
- 백엔드 엔지니어와의 협업
- 온오프라인 환경에서의 협업
- 1:1 및 다수의 인원이 존재할 때의 협업
👀 서비스 화면



접어두기
진행상황
추후 진행
userId를 전역상태로 저장 (AuthCheck 후 받은 id로 update)
추후 진행
반응형을 위한 util작성
고민사항
- 다른 사람 프로필 보는 페이지 간략히 따로 만들지
- 마이페이지의 기능 독립의 필요성 (현재 userId와 같은지 신경쓸 필요 없다는 점)
- 보안상, 토큰을 활용하기 때문에 이점
추후진행
- 라이딩 내역 3개 탭으로 분리
- 라이딩예정, 라이딩 완료, 개설한 라이딩
env관련
- 옛날 환경변수 적용되고 있음 확인 node환경에서 읽히도록 처리
- new DotenvPlugin({ systemvars: true }), 브라우저환경에서 읽히도록
- 요것도 적용안하니 안되었는데, 가능해졌음
- jwt token 관련 best article (jwt, ractquery, mui, ts)

register페이지
- 레지스터폼임을 안내하는 타이틀 상단에 추가하기
- post > register 리다이렉트 후 제출 > post 로 이동하지 않는 이슈
카카오 로그인 UI 내리기
닉네임 한글과영어만 가능하도록 프론트 validation
bug
- register안하고 마이페이지 접속 시 에러발생
작업내용
[Epic] 인증 및 인가 by OAuth
전체 흐름
카카오 Oauth 이해하기
>인증 관련 로컬 상태 저장(by쿠키)
>새로고침 및 토큰 만료 시 업데이트 로직
>추가 회원가입 정보 입력
>인가관련 처리
사례
- 로그인 구현 예제1
- 로그인 => 인가코드발급
- 인가 코드 => 토큰 발급(access, refresh)
- access토큰을 서버로 넘겨 사용자 인증 후 DB 저장 => JWT 토큰 발급
- JWT 토큰 localStorage에 저장 후, 자동 로그인 처리
- 사례2
- 프론트앤드에서 카카오 로그인으로 인가코드 요청
- 카카오 로그인 & 서비스 이용등록 수락 등록 ->
- 리다이렉트 호출(프론트앤드) ->
- 인가코드를 이용해 토큰정보 받기(백앤드) ->
- 토큰정보를 이용해 유저정보 받기(백앤드) ->
- 유저정보 리턴(프론트앤드)
0. Axios 모듈 만들기
- 서버용 ✅
- 카카오 oauth용 ✅
- oauth host가 2개 (kapi.kakao, kauth.kako)로 공통화하지않고 분리하여 사용 ✅
1. 카카오 Oauth 이해하기 ✅
카카오 Oauth 이해하기1.5 백엔드와 일정 및 현재 상황 공유 ✅
2. 토큰 로컬 상태 저장 및 쿠키 저장
jwt관리 로직+ 인증 관련 전역 상태 저장 by쿠키 , recoil3. 이후 작업
kakao server로 직접 요청이 아닌 server 로 간접 요청하기 (API변경 필요)
로그인 성공 시, main 페이지로 redirect
(Adv) 로그인 페이지 진입한 페이지로 redirect
페이지이동/새로고침 시 authUser 호출하여, 토큰 확인 및 인증유지
AuthRoute를 통한 인가 관련 처리
[feat] accessToken 만료 시 교체
[Goal]
사용자가 만료된 Token (but refresh는 있는) 으로 요청 시, 요청을 처리하고 새로운 토큰을 받아, 현재 토큰과 교체한다.
사용자가 완전히 만료된 Token일 경우 (refreshToken 만료), 요청을 수행하지 않고, 에러와 함께 로그아웃 처리한다.
[Todo]
요구사항 명확히 파악
response Header로 오는 Token 확인하기
해당 Token으로 전역 토큰 및 localStorage Token 교체
[Detail]
요구사항 명확히 파악
- server API 변수명 교체
- 현재 accessToken, token, jwt토큰, refesh토큰, refrsh기간 용어 혼재
- accessToken으로 변수명 합의?
- 내가 생각한 로직
- accessToken
만료
- 403에러 (axisoInterceptor.reponse 확인 후 로직 진행)
- refesh 요청
→
성공
(refresh기간 정상): 새로운 accessToken 받고, 이전 요청 진행→
실패
(refresh기간 만료): 이전요청 실패 및 로그아웃 처리- accessToken
정상
, refresh기간정상
- 200
- accessToken
만료
, refresh기간정상
- 200 + response Header에 새로운 Token
- Client에서 교체 작업 필요
- accessToken
만료
, refresh기간만료
- 401
- Client 에서 로그아웃 처리
- accessToken
없을때
- 403
Token교체
- 언제 교체할 것인가?
- 매번 responseHeader에 Token 있는지 체크
- 어디서 교체할 것인가?
api단
vsaxiosInterceptor
이슈리스트
[Epic] 추가 회원가입 정보 Form
[Epic] 프로필 페이지
1. [feat] 레이아웃 및 목업 데이터 구성
최대한 빠르게 개발해보기!
빠르게 개발해보는 연습
SideNavigation
UserInfo
- 유저이미지
- 유저닉네임
- 자전거종류
- 매너점수
- 경력
UserMenu
- 마이페이지
- 라이딩 관리
- 라이딩 현환
- 라이딩평가
- 계정 관리
- 프로필 수정
- 프로필 이미지
- 닉네임
- 자기소개
- 실력
- 경력
- 자전거종류
- 선호지역
- 개인정보 수정
- 전화번호
- 카카오계정 이메일
- (adv) 성별, 나이, …
- 로그아웃
[feat] 마이페이지 라우팅 및 프로필 조회 API 연동
- 마이페이지 라우팅
- userId를 전역상태로 가지고 있어야만 가능
[feat] 프로필 페이지와 마이페이지의 구분
- 프로필 페이지
- 다른 사람의 정보를 볼 수 있다.
- 마이페이지
- 전역상태로 관리 중인 userState로만 접근하도록 한다.
[Todo]
SideNavigation에서 UserInfo 컴포넌트의 분리
프로필 페이지 params로 UserInfo 띄우도록 수정
마이페이지 params로 id 받는 부분 제거
2. [feat] 라이딩 현황/상세페이지 기능 구현
[Goal]
- 라이딩 내역
- 라이딩예정, 라이딩 완료, 개설 라이딩 3개 탭 구현
- 라이딩 상세
- 라이딩 내역 상세 정보 카드 출력
- 예정 라이딩의 경우 취소 하기
[Todo]
API 요청
Tab 컴포넌트 사용하여 레이아웃 및 Mock 데이터로 라이딩 내역 출력
CardUserAction을 통한 라이딩 상세페이지 이동 및 정보 출력
[Detail]
API 요청
3. [feat] 프로필, 개인정보 수정 기능
[Goal]
- 7가지 동시 수정 가능
- 프로필이미지, 닉네임 , 자기소개
- 시작년도, 선호지역, 실력, 자전거 종류
[Todo]
문서 확인하기
API 문서
React-hook-form 기본값 가져오기
7가지 인풋을 프로필수정Form 컴포넌트로 만들기
기본 값 불러오기
수정 API 만들기
[Detail]
수정 버튼을 통한 이미지 등록
4. [feat] 라이딩 평가 기능 구현
추후진행
: 카드에 시작시간 표시[Goal]
- 라이딩 이후 사용자에 대한 평가를 남길 수 있다 라이딩 리더는 노쇼 라이딩 멤버를 기록할 수 있다.
[Todo]
API 및 평가 기능 이해
레이아웃 및 더미 요청을 통한 구현
API 연동
[Detail]
API 및 평가 기능 이해
- 평가체크 여부 체크는 백에서 가능 (필터링에서 보내주기 가능)
- 사용자 기준 흐름
- 마이페이지 > 평가메뉴 > 평가가능라이딩 /
평가한 라이딩 탭조회 api 필요
> 라이딩 카드 > 클릭 - 평가 가능 라이딩 (라이딩 시작 시간 지나고, 평가 하지 않은 라이딩)
- 평가페이지(id)
리더orNot 여부에 따라 다른 뷰
- 해당 라이딩 참가자목록 출력
- 유저닉네임, 체크박스 (유저닉네임으로 사람구별가능한가? 이름도 아니고..)
- 평가 API 호출
평가한 라이딩평가 내역 출력 API <Opt>
- 조회 API
- 평가가능 라이딩과 평가한 라이딩을 구별해서 받고 싶음.
- request : userId
- response
- { canEvaluatingRiding, } …이부분 어렵네요.. 평가여부 체크를 어떻게 할건지 잘..
- 리더 or Not 여부
- 평가 완료한 라이딩 체크
- 리더 > 멤버 평가, 멤버 > 멤버 평가 같은 API 사용해도 되지 않을까?
- 같은 페이지, 같은 API 사용
- 자신이 리더인 게시글에만 노쇼 체크박스가 보이도록 처리
- 기본값:
noshow: false
recommened:true
- request
레이아웃 및 더미 요청을 통한 구현
- ✅ 기본적인 Routing 세팅
- 유저평가폼 레이아웃 잡기
- mockData 불러와서 레이아웃 구성
userId
> from statepostd
> from url
react hook form 데이터 파싱하기
noshow
: true | falserecommened
: “true” | “false” | null- “true” ⇒ true
- “false” ⇒ false
- null ⇒ true
before
After
5. [feat] 메인페이지
[Goal]
- 특정 필터에 맞는 4가지 카드 뿌려주기
[Todo]
필터링 할 것 4가지 선정
4가지 선정
선정 후 API 어떻게 불러오는 지 확인
해당 API 로 MockData 구성
MockData 기반으로 레이아웃 및 디자인 구성
API 연동
[Detail]
필터링 4가지 선정
- 4가지
- 선호 자전거
- 선호지역
- 실력별
- 랜덤
-
사용자
- 선호 자전거 > user.ridingProfile.bicycles
[”로드", “MTB”]
- 선호 지역 > user.ridingProfile.favoriteRegionCode
11
- 실력별 > user.ridingProfile.level
중
포스트
- 선호 자전거 > post.riding.bicycleType
[”로드", “MTB”]
https://rg-server.p-e.kr/api/v1/ridingposts?bicycleCode=2
- 선호 지역 > post.riding.code
35060
- 실력별 > post.riding.ridingLevel
“상" | “중" | “하"