시연 + 발표영상 포함해서 15분
목차공통팀 소개프로젝트 주제 및 선정 배경프로젝트 협업 과정스프린트 ( 지라 스프린트 사진 넣고 설명 ) 👀 프론트앤드 파트 👀 백엔드 파트 협업 방식 기술 스택ERD인프라 및 CI/CD 중점 내용서버 분리 ( 이미지 , core , 알림 )Facade 패턴 (공통)JWT토큰 + Redis ( 인증, 인가 ) AOP,어노테이션 기반 인증,인가 처리태그 조회 이미지 로그 관리개선점 및 후기🔥 회고프론트앤드백엔드
목차
1기 목차

1. 프로젝트 주제 및 선정 배경 2. 사용자 스토리보드 3. 서비스 브랜딩 4. 서비스 기대효과 5. 프로젝트 협업 과정 6. 프로젝트 협업 툴 7. 프로젝트 협업 일정 8. 프론트엔드 기술 스택 8-1. UI/UX 구현 세부 특징 8-2. 페이지 구성도 8-3. 프엔 멤버 9. 백엔드 기술 스택 9-1. 백엔드 시스템 구성도 9-2. 백엔드 파이프라인 9-3. 백엔드 암호화 기술 설명 9-4. 세부 특징 9-4-1. 쿼리 디에스엘, 소프트 딜리트 10. 프로젝트 시연 후 종료
공통
- 팀소개
- 안녕하세요 ^^ 머쓱한 녀석들입니다 머쓱 ;
- 간단한 팀원 소개
- 역할
- 기획 & 프로젝트 소개
- 프로젝트 동기 및 기획의도
- 프로젝트 차별성
- 기획안 토대로
- 프로젝트 소개
- 협업
- 스프린트 계획
- 1주차
- 2주차
- 3주차
- 협업 방식, 툴
- JIRA 활용, Slack, Discord, 노션, API 문서 (Swagger)
- 코어타임 2시 ~ 7시
- 시작 스크럼 및 마무리 스크럼으로
- 스크럼 시간마다 진행사항, 이슈들을 공유하고 보완
- 노션의 화이트 보드 활용
- 비동기적으로 이슈 해결
- Jira를 통한 티켓 적용
- 앞선 스프린트 계획에 맞춰 이슈 발행 및 개발 진행
- 통합된 환경에서의 개발 진행
- API문서로 Swagger를 채택하여 백엔드와 프론트 빠르게 확인가능






- 전체 인프라
- 사진 대처 ( 프 + 백 통합 )
- 전체적으로 어떻게 돌아가는 지 설명
- 스토리별 기능 달성률
- 시연영상 7~8분 잡는 것 같습니다
- 프론트엔드가 맡을 예정
- 자체 평가 의견 및 계획
팀 소개
🙋♂️ 머쓱한 녀석들
저희 머쓱한 녀석들 팀은 프론트엔드팀 5명과 백엔드팀 4명으로 이루어져 있습니다.
기간 : 2022년 7월 21일 ~ 8월 17일
맡은 역할
프로젝트 주제 및 선정 배경
- 우리의 이야기를 하나의 서비스에서 기록할 수 있고 공유할 수 있다면 어떨까?
- 기존 연인들끼리 사용할 수 있는 어플은 사진 공유 및 서로가 쓴 글들의 공유가 가능하지만, 해당 기능들은 기존의 앱들로 대체가 가능한 경우들이 많다. 또한, 장소 별로 모아보기가 어려워 결국에는 다시 찾아보지 않고 남는 경우들이 많다.
둘이 갔던 장소들을 지도로 모아 한 눈에 볼 수 있으면 좋겠다는 아이디어를 토대로, 우리맵이라는 지도 기반 연인간 추억 공유 서비스를 기획하였다.
서비스 요약
- 안전하다 - 사용자가 쓴 글은 연인 끼리만 공유된다
- 깨끗하다 - 이별 했다면, 커플을 깨기만 하면 된다. 그러면 모든 데이터를 싹 날려버린다. 추억과 함께
- 편하다 - 장소 기반 서비스로, 지도를 통해 포스트를 쉽게 모아볼 수 있으며 추억을 회상하기 쉽다.
프로젝트 협업 과정
- 애자일 기반 프로젝트 관리
- 중간 회고와 최종 회고 총 2번의 회고를 진행
- 백엔드, 프론트엔드간 일정을 공유하고, 한 눈에 진행도를 확인할 수 있도록 Jira를 커뮤니케이션 툴로 사용
- tools: notion, slack, jira, discord
스프린트 ( 지라 스프린트 사진 넣고 설명 )
- 1주차 - 프로젝트 기획 및 자료조사, 기술 스택 선정
- 2주차 - 프로젝트 베이직에 들어갈 기본 기능 구현
- 3주차 - 프로젝트 고도화 및 추가 기능 구현
- 실제 서비스를 테스트하면서 발견한 버그들을 수정
- UI 고도화
- 실시간 알림 기능 구현
👀 프론트앤드 파트
- 기술스택
- Typescript
- React
주 라이브러리
- Next.js
프레임워크
- Recoil
상태 관리 라이브러리
- Emotion
스타일 컴포넌트 라이브러리
- Storybook
컴포넌트 테스트 및 관리
- Jira
백엔드와 함께 에픽 단위로 프로젝트를 관리
- Figma
아이디어 확장 및 프론트엔드 와이어프레임 관리
- Notion
기획 및 프로젝트 자료 문서화 및 관리
- Slack
이슈 사항 공유 및 소통
- vercel
[ 언어 ]
[ 라이브러리 및 프레임워크 ]
[ 협업 툴 ]
[ Lint & Prettier Rules ]
Lint
{ "env": { "browser": true, "node": true, "es6": true }, "parser": "@typescript-eslint/parser", "parserOptions": { "tsconfigRootDir": "./", "project": ["./tsconfig.json"] }, "plugins": [ "prettier", "@typescript-eslint" ], "extends": [ "airbnb", "airbnb-typescript", "next/core-web-vitals", "plugin:prettier/recommended" ], "rules": { "react/jsx-props-no-spreading": "off", "react/require-default-props": "off" }, "settings": { "react": { "version": "detect" } }, "overrides": [ { "files": [ "*.config.js" ], "rules": { "@typescript-eslint/no-var-requires": "off" } } ] }
Prettier
{ "singleQuote": true, "semi": true, "useTabs": false, "tabWidth": 2, "trailingComma": "all", "printWidth": 80, "endOfLine": "lf" }
[ 배포 ]
- 컨벤션 & 브랜치 전략 (발표 내용이나 README에는 굳이 들어갈 필요는 없어보임)
- rebase 후 merge를 통한 충돌 방지
- 트러블 슈팅 기록
- 페이지별 UX,UI (gif)
프론트엔드 시연 영상
기본적으로 유저 스토리 기반으로 진행
위에서부터 아래로 순서대로 진행
- 회원 가입
- 회원 가입 실패
- 잘못된 값 또는 빈 값을 넣고 난 뒤 제출 버튼을 클릭하면 어떻게 처리하는지 보여준다
- 회원 가입 성공 -
/auth/signin
페이지로 이동하는 것을 보여준다.
- 로그인
- 로그인 실패
- 잘못된 아이디 또는 비밀번호를 입력했을 때 어떻게 처리되는지 보여준다.
- 로그인 성공 -
/profile
페이지로 이동하는 것을 보여주고, 왜 그렇게 되는지 설명
- 프로필 페이지
- 프로필 페이지에서 닉네임 변경이 가능하다는 것을 보여준다.
- 프로필 페이지에서 아바타 변경이 가능하다는 것을 보여준다.
- 커플 맺기 버튼을 클릭하여, 커플 맺기 페이지로 이동이 가능함을 보여준다.
- 커플 맺기 페이지
- 코드 기반으로 커플을 맺을 수 있음을 설명한다.
- 커플 맺기 실패
- 잘못된 코드를 입력했을 경우, 유저에게 어떤 피드백이 전해지는 지 보여준다.
- 커플 맺기 성공
- 코드를 제공 받아서 입력하는 쪽은 입력 후에 커플이 맺어지면
/
경로로 이동하는 것을 보여준다. - 코드를 제공하는 쪽은 커플이 성사되기 전과, 후에
커플이 맺어진지 확인하기
버튼을 눌러 커플이 맺어진지 확인한다. - 실패
- 실패 시 피드백을 보여준다.
- 성공
- 성공 시 피드백을 보여준다.
- 포스트 생성
- 메인페이지에서 보이는 포스트 생성 버튼을 눌러 포스트 생성 페이지로 이동한다.
- 포스트 생성 페이지에서 글을 작성한다.
- 지도 검색을 통해 핀을 찍을 수 있음을 보여준다.
- 지도를 클릭하여 핀을 찍는 것을 보여준다.
- 실패 시나리오
- required field 중 하나라도 required 옵션을 만족하지 않으면 게시글 작성이 안되고, 피드백이 뜸을 보여준다.
- 빈 문자에 대해 예외 처리가 되어 있다면 해당 피드백을 보여줘도 좋을 것 같다.
- 성공 시나리오
- required 조건을 만족하고, 버튼을 클릭했을 때 메인페이지로 라우팅이 이동함을 보여준다.
- 메인 페이지
- 메인 페이지 좌측에 메인 사이드바의 역할에 대하여 설명한다.
- 메인 사이드바의 검색 기능에 대하여 보여준다. - 몇가지 완성된 게시물들이 존재한다면 좋을 듯 하다
- 태그 검색을 통해 해당 태그가 존재하는 게시물을 찾을 수 있음을 시연한다.
- 게시물 검색을 통해 제목이 존재하는 게시물을 찾을 수 있음을 보여준다.
- 게시물을 클릭 시 해당 디테일 페이지로 이동할 수 있음을 설명한다.
- 메인 페이지 오른쪽에 맵의 역할에 대하여 설명한다.
- 맵을 축소하여 게시물에서 찍은 좌표가 맵에 표시됨을 시연한다.
- 마커를 클릭하여 오버레이가 뜸을 보여준다.
- 오버레이를 클릭하여 해당 게시물이 쓰여진 페이지로 이동할 수 있음을 보여준다.
- 포스트 디테일 페이지
- 포스트 디테일 페이지의 레이아웃에 대해서 설명한다.
- 왼쪽의 사진 리스트를 클릭하면, 가장 큰 사진 칸의 사진이 변함을 보여준다.
- 오른쪽에 제목, 날짜, 태그 및 내용이 존재함을 보여준다.
- 게시글 삭제 버튼을 눌러 게시글이 삭제됨을 보여준다.
- 게시글 수정 버튼을 눌러 게시글 수정 페이지로 이동하는 것을 보여준다.
- 포스트 수정 페이지
- 포스트를 수정할 수 있음을 보여준다.
- 맵과 태그등을 바꾸면서 수정이 가능함을 보여준다.
- 알림 기능
- 한 쪽에서 게시글을 생성하거나 수정하면, 커플로 연결된 다른 사용자에게 실시간으로 알림이 감을 보여준다.
- 알림 중 하나를 클릭하여 해당 게시글 페이지로 이동할 수 있음을 보여준다.
- 다시 알림을 클릭하여 읽음 처리가 되었음을 보여준다.
- 페이지를 새로 고침하여 읽은 알림이 사라졌음을 보여준다.
- 커플 정보 페이지
- 사귄 날짜의 변경이 가능함을 보여준다.
- 커플을 끊을 수 있음을 보여준다.
- 커플을 끊고 난 뒤, 페이지 이동을 보여준다.
- 회원 탈퇴
- 프로필 페이지에서 회원 탈퇴가 가능함을 보여준다.
시나리오 스크립트
회원가입 페이지
지금부터 시연을 시작하겠습니다. 우선, 회원가입 먼저 진행해 보도록 하겠습니다. 여러 시나리오를 보여드리기 위해, 우선 잘못된 값을 넣어보도록 하겠습니다.
잘못된 값을 넣어봄
잘못된 값을 넣을 경우, 유효성 검증을 통과하지 못하고, 인풋 아래쪽에 빨간 글씨로 사용자에게 경고가 나타나게 됩니다. 또한, 화면 오른쪽 상단에 토스트로 유저에게 피드백이 전달됩니다.
이번엔 올바른 값을 폼에 입력해 보겠습니다.
올바른 값으로 회원 가입 진행
로그인 페이지
올바른 값을 넣어 회원가입이 완료되면, 바로 로그인 페이지로 이동하게 됩니다.
그럼 바로 로그인을 진행해 보도록 하겠습니다.
우선 잘못된 값을 넣어보도록 하겠습니다.
잘못된 값을 넣어봄
잘못된 값을 넣을 경우, 폼 아래쪽에 유저에게 빨간 글씨로 메시지가 나타나게 됩니다.
이번에는 올바른 값을 넣어보도록 하겠습니다.
올바른 값을 넣어봄
올바른 값을 넣으면 로그인되고, 아직 커플을 맺은 상태가 아니기 때문에 프로필 페이지로 이동하게 됩니다.
프로필 페이지에서는 닉네임과, 프로필 사진, 연애 시작일을 수정할 수 있으며, 아직 커플을 맺지 않았다면, 커플 맺기 버튼을 눌러 해당 페이지로 이동하여 커플을 맺을 수가 있습니다.
커플을 맺기 전에, 우선 프로필 사진과 닉네임을 바꿔보도록 하겠습니다.
사진과 닉네임을 바꿈
사진과 닉네임을 바꾼 뒤, 완료 버튼을 누르면 수정이 됩니다.
다음은, 우리 서비스의 핵심 기능인 커플 맺기를 시연하도록 하겠습니다.
커플맺기 버튼 누름
버튼을 누르면, 커플 맺기 페이지로 이동하게 되고 다음과 같이 내 코드에는 7자리의 숫자 코드, 상대 코드 영역은 상대로부터 코드를 얻어 입력할 수 있는 인풋 창이 보여집니다. 내 코드는 생성 후 24시간 동안만 유효하며, 유효하지 않은 코드를 입력할 경우, 커플이 맺어지지 않습니다.
사용자는 커플이 맺어졌는지 확인하는 버튼을 눌러
커플이 맺어진지 확인이 가능합니다.
커플이 맺어졌다면, 메인 페이지로 이동할 수 있습니다.
그럼 저희가 준비해둔 다른 계정으로부터 코드를 얻어와 커플을 맺어보겠습니다.
다른 창을 띄워서 커플 코드를 입력한다.
이렇게 상대 커플 코드를 입력하고,
확인하기 버튼을 누름으로써 커플이 맺어지게 되고,
메인페이지로 이동하게 됩니다.
게시글 작성 페이지
메인페이지를 소개 해 드리기 이전에, 게시물 작성부터 보여드리도록 하겠습니다.
게시물 작성 버튼 클릭
게시글 작성 페이지는 왼쪽 사진을 업로드할 수 있는 영역과 오른쪽 글을 적을 수 있는 영역으로 이루어져있습니다.
이미지 업로드 버튼을 누른다
이미지 업로드 버튼을 눌러 사진을 업로드 해보겠습니다. 사진을 업로드 하게 되면, 이미지 업로드 컴포넌트 아래 작게 이미지 리스트가 나타나, 사용자가 어떤 사진을 업로드 했는지 한 눈에 알아볼 수 있습니다.
이제 오른쪽으로 넘어가 글을 작성하도록 하겠습니다.
글을 작성한다.
오른쪽은 제목, 데이트한 날짜, 태그, 내용으로 이루어져있으며, 맨 아래쪽은 어디를 방문했는지 기록할 수 있는 지도가 있습니다.
지도는 장소 검색 또는 클릭을 통해 위치 정보를 저장할 수 있습니다.
모든 내용을 입력했기 때문에, 포스트 생성 버튼을 눌러보도록 하겠습니다.
포스트 생성 버튼을 누른다.
(메인페이지에 포스트가 생성된 것을 보여주며)
이렇게 정상적으로 새로운 포스트가 생성된 것을 볼 수 있습니다.
지금부터는 더 나은 시연을 위해
미리 준비된 계정으로 시연을 진행하겠습니다.
메인 페이지 (계정 변경)
메인 페이지는 화면과 같이 왼쪽의 사이드바와, 오른쪽의 지도로 이루어져 있습니다.
왼쪽의 사이드바에서는 커플 정보, 서치바, 게시글 리스트를 볼 수 있습니다.
서치바에서 검색은 크게 태그 또는 제목으로 입력이 가능합니다.
체크박스를 통해 태그, 제목 검색 전환이 가능합니다.
제목과 태그로 검색 기능 시연
입력을 통해 실시간으로 필터링 되는 값을 볼 수 있으며, 검색된 게시물의 썸네일을 클릭하면 해당 게시물의 상세 페이지로 이동합니다.
(이동은 하지 않음)
오른쪽의 맵 컴포넌트에서는 기록된 게시물들의 장소를 맵마커를 통해 볼 수 있습니다.
맵마커를 클릭하면 해당 장소에서 작성된 게시물 오버레이가 보여지며, 해당 오버레이를 클릭하면 상세 페이지로 이동하게 됩니다.
게시물 상세 페이지
게시물 상세 페이지 왼쪽부터 보도록 하겠습니다. 왼쪽 영역은 사용자가 업로드한 사진을 볼 수 있는 영역입니다. 왼쪽 아래 사진 리스트중 하나를 클릭해보겠습니다.
왼쪽 리스트 아래에 사진을 클릭한다.
사진을 누르면 큰 이미지 영역에 클릭한 사진이 보여지게 됩니다.
그럼 다음으로 오른쪽으로 넘어가보겠습니다.
오른쪽 영역은 포스트 생성 페이지와 유사한 구조를 가지고 있습니다. 해당 영역에서는 포스트 편집 버튼을 눌러 편집이 가능합니다. 버튼을 눌러 포스트를 편집해 보겠습니다.
포스트 편집 버튼을 누른다.
게시물 수정 페이지
게시물 수정 페이지에서는 사진을 제외한 나머지 정보들의 수정이 가능합니다. 한번 다른 영역의 정보들을 변경하여 게시글을 수정해 보겠습니다.
포스트를 수정한다.
포스트 수정 페이지에서는 제목, 날짜, 태그, 내용, 장소를 수정할 수 있으며,
수정을 정상적으로 마칠 경우, 메인 피드로 이동하게 됩니다.
포스트 수정 버튼을 누른다.
메인 페이지
우리맵 서비스는 커플 양 측 모두 게시글을 생성할 수 있으며, 상대 커플이 게시글을 작성, 수정시, 알림 기능을 통해 알 수 있게 됩니다.
알림은 내비게이션 바 오른쪽의 종 모양 아이콘을 통해 받을 수 있습니다. 커플로 맺어진 상대측 사용자가 게시물을 생성하거나 수정하면, 사용자에게 실시간으로 알림이 전달됩니다.
알림이 올 때까지 기다린 후, 알림 버튼을 누른다.
새로 고침을 하지 않더라도 알림이 도착하는 것을 볼 수 있습니다. 알림을 클릭하면, 알림이 읽음 처리되고 해당 게시물 상세 페이지로 이동하게 됩니다.
👀 백엔드 파트
- 팀원 설명
- 환
- 프로젝트 전체 관리
- 인증,인가 기능 구현
- 회원 API 구현
- 알림 API & 기능 구현
- 로그백 및 Cloudwatch를 통한 모니터링 구축
- 인프라 구축 (HTTPS, Docker)
- 윌
- 포스트 및 태그 도인 API 개발
- 마토
- 커플 도메인 API 개발
- 포스트 검색 API 개발
- 에디
- 이미지 업로드
- CI/CD 구축
협업 방식
- 개발 진행 방식
- 개발 컨벤션
- 각 필요한 설정을 미리 전파하여 불필요한 코드 리뷰 시간을 줄일 수 있었음.
- 그 외에도 각 테스트 전략, 패키지 구조 등을 사전에 미리 팀 컨벤션으로 정해놓음으로써 통일성이 있는 코드를 구현할 수 있었음.


- 브랜치 및 PR 전략
- 브랜치 전략 : git flow 전략을 따르되, release 브랜치의 경우 현재 상황에서 없다고 판단하여 제외하고 main, develop, feature, hotfix 브랜치만 사용
- PR 코드 리뷰
- 코드 리뷰를 통해 사전에 발생할 수 있는 문제 방지, 함께 고민하고 생각하며 개발 진행




기술 스택
- Java 11
- Gradle
- Spring Boot
- Spring JPA
- Query DSL
- 복잡한 쿼리 및 동적 쿼리를 위해 사용
- flyway를 통한 DB 형상 관리
- github action, docker 을 통한 CI/CD 처리
ERD

- 기획서를 기반으로 테이블 도출
- 알림의 경우 서버 분리시 DB도 분리될 수 있다고 생각하여 외래키 설정 X
- Redis에는 jwt token 저장
인프라 및 CI/CD

- 개발 서버와 운영 서버 분리하여 사용
- nginx를 통한 reverse proxy 및 ssl 적용
- 총 3개의 was 사용
- infrastructure
- CI/CD
- github actions와 docker를 통한 CI/CD 구축
- PR 생성시 jacoco와 sonarcloud를 통한 정적 분석 실시
- github actions에서 빌드 및 테스트 진행 후 docker file을 통한 이미지 빌드 및 허브 푸쉬
- 이후 ssh를 통해 스크립트 실행으로 배포 실시
- 서버가 분리됨에 따라 PR 라벨을 통한 파이프라인 분리하였습니다.,


중점 내용
서버 분리 ( 이미지 , core , 알림 )


- 왜? 이미지나 알림의 경우 리소스가 크기 때문에 하나의 서버에서 진행하면 부하가 심하다고 판단
- 세 가지의 모듈로 분리 - core, image, notification
- 분리하면서 인증 처리는 core에게 책임 , 나머지 서버들은 API 콜을 통한 인증,인가 처리
- 게시물 생성, 수정에 따른 알림 처리는 redis pub sub 방식을 사용하여 후에 분산 서버로 확장시에도 용이하게 설계
- 또한, 빌드시간과 테스트 시간 개선 경험

Facade 패턴 (공통)

- 하나의 서비스에서 여러 도메인과 레포지토리를 사용하다보니 너무 많은 책임을 가지고 있었으며 명확하게 구분이 안되는 문제점 발생
- 퍼사드 패턴의 적용으로 하나의 서비스 객체에서 하나의 도메인만 맡도록 분리
- 하나의 책임만을 가질 수 있어 명확하게 구분을 할 수 있었으며 재사용성 및 테스트 코드 작성에도 용이하였음
JWT토큰 + Redis ( 인증, 인가 )

- jwt토큰을 활용하여 서버의 부하를 줄이고 분산 서버로 확장했을 때도 정합성에 문제가 없도록 활용
- accessToken, Refresh Token을 활용해 토큰 탈취, 만료 시 재발급 문제 해결
- 저장의 경우 만료시간라는 휘발성을 고려하여 Redis에 저장하도록 구현
- 좀 더 보안 강화를 위해 로그아웃시 해당 토큰을 블랙리스트로 등록하는 기능 도입
AOP,어노테이션 기반 인증,인가 처리
- 시큐리티 사용 X
- 인터셉터와 어규먼트 리졸버 적극 활용
- 어노테이션과 AOP를 통한 인가 처리
- 개발 편리함
- @LoginRequired 인증 필요
- @OnlySolo, @OnlyCouple 인가 필요
태그 조회

- 사진 변경되야함@@@@@@


- 게시물 태그 검색이나 게시물 작성 시 전체 태그를 반환해줘야 했습니다.
- 하지만 태그의 경우 자주 바뀌긴 하지만 점차 사용하던 태그를 사용할 것이기 때문에 새로 생성된 태그가 없음에도 같은 태그를 계속 데이터베이스에 접근하여 조회하는 것은 비효율적이라고 생각하여 캐시를 도입하였습니다.
- 캐시 저장소에 데이터가 있으면, 캐시에서 가져오고, 없으면 메인 DB에서 값을 가져오는 대표적인 캐시 전략인 Look Aside Cache 사용하였고 태그 응답시 캐싱처리를 하고 태그 생성시에는 캐시를 삭제하도록 하였습니다.
- 이를 통해 캐시를 사용하기 전보다 응답속도를 개선시킬 수 있었습니다.
이미지
- S3 폴더 구조는
{개발환경}/{멤버ID}/{yyyy-MM-dd}
형태로 가져감 - 파일명은 UUID로 중복될 수 없도록 설정
- S3에 이미지를 업로드 해 URL을 내려주는 방식을 사용
- 여러개의 이미지가 업로드 될 경우 동기적으로 처리하는 것보단 비동기로 처리후 취합하는 것이 더 효율적이라고 생각
- 비동기 처리에
parallelStream
,CompletableFuture
중 고민을 한 결과 I/O 작업에 더욱 유연하고 커스텀하게 스레드 수를 설정할 수 있는CompletableFuture
를 사용 - 커스텀 스레드 사진
- 성능 개선 사진
로그 관리

- 서버를 분리하면서 분산된 로그들을 확인하기 어려운 문제점


- 클라우드와치를 이용한 모니터링 실시
- CPU 및 메모리 사용량도 확인할 수 있는 부가적인 이득
백엔드 대본 안녕하세요. 머쓱한 녀석들팀의 우리가 갔던 곳 우리맵 발표 시작하겠습니다.
먼저 팀원 소개입니다.
각 팀마다 역할을 부여하고
이어서 백엔드 발표 시작하겠습니다.
먼저 협업 방식입니다.
저희는 사전에 자체적으로 팀 컨벤션을 제작하여 사용하였습니다.
테스트 전략, 패키지 구조 등 컨벤션으로 정해놈으로써 팀 전체가 통일성 있는 코드를 작성할 수 있게 되었고 그 결과 코드 해석 등 불필요한 코드 리뷰 시간을 줄일 수 있게 되었습니다.
브랜치 전략의 경우 git flow를 따르되 release 브랜치의 경우 현재 상황에서는 필요없다고 생각되어 제외하고 main, develop, feature, hotfix 브랜치만 사용하였습니다.
PR의 경우 팀원 중 한명 이상의 승인이 필요하며 리뷰어는 24시간 내에 리뷰를 수행하도록 하였습니다.
코드 리뷰를 진행하면서 사전에 발생할 수 있는 문제를 방지하고 클린 코드를 지향할 수 있었으며 함께 고민하고 생각할 수 있는 소통의 한 창구로 사용하였습니다.
백엔드 기술 스택입니다.
Java11, Spring Boot, JPA를 중심적으로 서비스를 개발하였으며 복잡한 쿼리 및 동적 쿼리를 위해 QueryDsl을 사용하였습니다.
ERD는 기획서를 기반으로 테이블 도출하였습니다.
알림 테이블의 경우 서버 분리시 데이터베이스도 분리될 수 도 있다고 생각하여 외래키를 설정하지 않았습니다.
백엔드 인프라입니다.
저희는 개발 서버와 운영 서버 두개의 서버로 분리하여 사용하였습니다. 개발 서버를 구축함으로써 좀 더 빠르게 프론트와 협업을 진행할 수 있었습니다.
총 3개의 WAS를 사용하며 각 WAS는 도커를 통해 실행되게 됩니다.
각 요청을 전달하기 위해 WAS앞단에 Nignx를 두었고 Reverse Proxy를 통해 알맞게 통신할 수 있도록 하였습니다. 추가적으로 SSL도 적용하여 https 프로토콜을 사용할 수 있었습니다.
CI/CD입니다.
저희는 깃허브 액션과 도거를 사용하여 구축하였습니다.
PR이 생성되면 CI 파이브라인이 실행되게 되고 이 과정에서 jacoco와 sonarcloud를 통한 정적 분석 실시하게 됩니다.
브랜치가 머지될 경우 docker file을 통해 이미지를 빌드하고 도커 허브에 업로드 하게 됩니다.
이후 서버에 스크립트를 실행하여 배포를 실시하게 됩니다.
저희는 하나의 레포지토리에서 3개의 모듈을 관리하기 때문에 파이브라인을 분리할 필요가 있었습니다. 이를 PR 라벨을 통해 구분하는 방법으로 해결할 수 있었습니다.
다음은 저희가 프로젝트를 진행하며 생각한 핵심사항 및 시도입니다.
저희는 퍼사드 패턴을 적용하였습니다.
본래의 MVC 패턴으로 개발했을 때 하나의 서비스에서 여러 도메인과 레포지토리를 사용하게 됩니다. 그 결과 하나의 서비스가 너무 많은 책임을 가지며 명확하게 구분이 안되는 문제점이 발생하였습니다.
이에 저희는 Facade 패턴을 적용하여 하나의 서비스 객체에서 하나의 레포지토리만 맡도록 분리하고 Facade에서 이를 사용하는 방식으로 구현하였습니다.
그 결과 서비스는 하나의 책임만을 가질 수 있어 명확하게 구분을 할 수 있었으며 재사용성 및 테스트 코드 작성에도 용이하였습니다.
다음은 인증 인가 입니다.
저희는 인증을 위해 토큰 방식을 사용했습니다. JWT 토큰을 활용하여 서버의 부하를 줄이고 분산 서버로 확장했을 때도 정합성에 문제가 없도록 하였습니다.
accessToken만을 사용하는 것이 아닌 Refresh Token을 도입하여 토큰 탈취, 만료 시 재발급 문제를 해결하였고 만료 시간이라는 휘발성을 고려하여 Redis에 저장하도록 하였습니다.
추가적으로, 보완 강화를 위해 로그아웃 시 해당 토큰을 블랙리스트로 등록하는 기능도 도입하였습니다.
저희는 시큐리티를 사용하지 않았기 때문에 인터셉터와 어규먼트 리졸버를 적극적으로 활용하였습니다.
이 과정에서 인터셉터를 path로 지정하는 것이 아닌 메서드단에 어노테이션을 붙여 인증을 처리할 수 있도록 하였습니다.
이를 통해 좀 더 개발이 용이해졌고 휴먼 에러를 방지할 수 있었습니다.
마찬가지로 인가의 경우 각 권한별 어노테이션과 AOP를 활용하여 관심사를 분리하였습니다.
다음은 캐싱 처리입니다.
게시물 태그 검색이나 게시물 작성 시 전체 태그를 반환을 해줘야 했습니다.
하지만 태그의 경우 자주 바뀌긴 하지만 점차 사용하던 태그를 사용할 것이라고 생각되어 매번 데이터베이스에 접근해 조회하는 것은 비효율적이라고 생각하였습니다.
이에 저희는 태그 조회시 캐싱을 적용하기로 하였습니다.
저희는 캐시 저장소에 데이터가 있으면, 캐시에서 가져오고 없다면 DB에서 값을 가져오는 전략인 Look Aside Cache를 사용하였으며 태그 응답시 캐싱처리를 하고 생성시에는 캐시를 삭제하도록 하였습니다.
이를 통해 캐시를 사용하기 전 보다 응답속도를 개선시킬 수 있었습니다.
다음은 이미지 비동기 처리입니다.
저희는 이미지를 받아 S3에 업로드하여 URL을 반환하는 방식을 사용하고 있습니다.
이때, 여러개의 이미지를 업로드할 시 동기적으로 처리하는 것보단 비동기로 처리한 후 취합하는 것이 더 효율적이라고 생각하여 도입하게 되었습니다.
비동기 처리에 parallelStream과 CompletableFuture 중 I/O작업에 더욱 유연하고 커스텀하게 스레드 수를 설정할 수 있는 CompletableFuture를 사용하였습니다.
이를 통해 동기적으로 처리했을 때보다 응답속도를 개선시킬 수 있었습니다.
다음은 서비스 분리입니다.
저희가 구현한 기능인 이미지나 알림의 경우 리소스가 크기 때문에 후에 트래픽이 늘어난다면 하나의 서버에서 진행하기에 부하가 심하다고 판단하였고 서비스를 분리하기로 하였습니다.
저희는 코어, 이미지, 알림 총 3가지로 모듈을 나누었습니다.
서버를 분리하면서 인증,인가의 경우 각 서버가 책임을 가지고 있는 것이 아닌 Core모듈에게 책임을 주기로 하고 API를 통해 처리하도록 하였습니다.
또한, 게시물 생성, 수정에 따른 알림 처리는 Redis의 Pub/Sub 방식을 사용하여 알림 모듈에게 전달하여 처리할 수 있도록 하였습니다.
Redis pub/sub를 활용함으로써 후에 분산 서버로 확장시에도 용이하게 설계하였습니다.
3가지 모듈로 나누게 되면서 빌드시간과 테스트 시간 감소의 경험도 할 수 있었습니다.
다음은 로그 모니터링입니다.
저희는 로그백을 활용해 access, info, warn, error, db 로그를 파일로 관리하고 있었습니다.
하지만 서비스 분리를 하며 로그가 3배로 늘어나게 문제점이 발생하였고 트러블 슈팅이나 서버가 제대로 동작하는 지 확인이 어려웠습니다.
이에 저희는 클라우드 와치를 활용하여 각 모듈의 로그를 수집하고 한 곳에서 확인할 수 있도록 모니터링을 구축하였습니다.
클라우드와치를 도입하면서 좀 더 빠르게 트러블슈팅을 해결할 수 있게 되었고 전체적인 로직확인도 할 수 있게 되었습니다.
부가적으로 CPU 및 메모리 사용량 등 여러 지표도 확인할 수 있었습니다.
저희는 프로젝트가 끝났다고 개발이 끝나는 것이 아닌 다음과 같은 개선점을 개선해나갈 예정입니다.
개선점 및 후기
- 로드밸런싱 및 무중단 배포
- cloudfront을 활용한 이미지 응답 개선
- 채팅 기능 구현
- 테스트 코드 리팩토링
- 커플 초대 코드 삭제 시점 (필요)
- 커플 변경시 알림 서비스 (필요)
readme 정리
소개
사용 기술
기술 스택 사진
커밋, PR , branch 전략
인프라
인프라 구조 사진
CI CD
CI CD 구조 사진
ERD
API 문서
구현 기능?
노션 문서 링크
WIKI ( 코드 스타일 등 )
어떤식으로 자료 만들지 정리 ( 각자 적으세용 )
기술 스택 사진
인프라 구조 사진
인프라 구조 사진
JWT토큰을 사용하며 문제점
캐싱 기능 (Redis)
성능 개선 사진
AOP,어노테이션 기반 인증,인가 처리
어떤 로직으로 돌아가는지
서버 분리 ( 이미지 , core , 알림 )
왜? 하나의 서버에서 처리하면 부하가 심할 것으로 예상
redis pub sub, SSE , 이벤트 처리 를 활용한 알림 처리 기능
알림과 이미지에서 필요한 인증과 인가 API 콜
나눠서 사용
로그 관리
로그백과 클라우드와치를 이용한 모니터링 실시
이미지 병렬 처리
개선점 ( 꼭 필요 )
프론트엔드 README

## 서비스 소개 > 우리 갔던 곳, 우리맵 WooriMap은 연인들간 추억을 공유하고 모아볼 수 있는 지도 기반 SNS 플랫폼입니다. ## 주요 기능 - 사용자와 또 다른 사용자는 서로 커플을 맺을 수 있습니다. - 커플을 맺은 사용자는 글을 쓰고 수정할 수 있으며, 우리가 갔던 곳의 위치를 표시할 수 있습니다. - 표시한 위치들을 모아 한 눈에 볼 수 있습니다! 우리 갔던 곳을 모아서 추억 지도를 만들어보세요. - 이별하셨나요? 걱정할 것이 없습니다. 버튼 하나만 누르면, 커플을 끊음과 함께 추억들 역시 날려버립니다. ## 기술 스택 ### 개발    ### 코드 관리   ### 스타일    ### 커뮤니케이션     ## 팀원 소개 <div align="center"> | [벤](https://github.com/mrbartrns) | [위고](https://github.com/Yummy-sk) | [오월](https://github.com/MayOwall) | [맷](https://github.com/sangjin149 | [엘리오](https://github.com/woojerry) | | :-------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------: | | <img src="https://avatars.githubusercontent.com/u/56826914?v=4" width=150 /> | <img src="https://avatars.githubusercontent.com/u/60822846?v=4" width=150 /> | <img src="https://avatars.githubusercontent.com/u/97934878?v=4" width=150 /> | <img src="https://avatars.githubusercontent.com/u/53640976?v=4" width=150 /> | <img src="https://avatars.githubusercontent.com/u/50645183?v=4" width=150 /> | --- </div>