[근근근] 운동 루틴 공유&추천 커뮤니티

5 more properties

배경 Problem

우리가 이 서비스를 개발하게 된 이유에요.
헬스장 PT의 필요성과 가격 부담
1.
헬스장을 처음 찾아 운동법을 잘 모르는 이들에게 PT는 필수 코스
2.
체격을 올리기 위해서 고중량 운동 기구 사용 필요
3.
운동 기구마다 근육에 미치는 효과가 달라서 전문가의 코칭 필요
4.
부담스러운 PT 가격
효율적이고 안전한 운동을 위해서 PT는 필요하지만 비용이 부담스러워요.
낮은 트레이너 요건
1.
"300㎡가 넘지 않는 헬스장에 체육지도자가 1명 이상만 있다면 나머지 트레이너들은 자격증이 없어도 회원들을 지도할 수 있다."
2.
"300㎡가 넘는 헬스장에 체육지도자가 2명 이상만 있다면 나머지 트레이너들은 자격증이 없어도 회원들을 지도할 수 있다."
출처 - 국가법령정보센터
신뢰성 있고 전문성 있는 트레이너를 선별하기 어려워요.

서비스 소개 Solution

근근근: 운동 루틴 공유 & 추천 커뮤니티 서비스에 대해 알아볼까요?
운동 커뮤니티 구축
운동 역량을 수치화한 정보를 제공해 자신의 운동 능력을 개선할 수 있도록 도와줘요. 운동을 즐기고 있는 사람들 간에 운동 경험을 공유하고 피드백 함으로써 활성화된 운동 커뮤니티를 구축할 수 있어요.
개인 맞춤 운동 일지 추천
초기 회원 가입 시 입력된 유저의 인바디 정보와, 기존 사용자의 인바디 데이터를 활용하여 사용자에게 맞는 운동 일지와 성장한 이용자의 운동 일지를 추천해줘요. 사용자들은 동기부여를 얻을 있을 뿐만 아니라, 자신의 운동 계획을 효과적으로 수립하고 지속적인 성장을 이룰 수 있게 돼요.
트레이너 검증 및 온라인 PT 채팅 상담
서비스 자체적으로 자격증이나 신체 정보를 통해 트레이너의 신뢰성을 확인하고 트레이너와 사용자 간의 온라인 PT 사전 상담을 지원해요. 사용자들은 안전하고 효율적인 트레이닝을 보장하며, 상담 시간을 절약할 수 있어요.

아키텍처 Architecture

옹기종기 팀에서 개발한 근근근의 아키텍처에요.

핵심 기능 Features

옹기종기 팀에서 개발한 근근근의 핵심기능이에요.
운동이 처음이라 어려우신가요? 근근근을 통해 다른 사람들의 운동일지루틴을 따라해보세요! 사람들과 운동에 대한 얘기를 나누면 효과는 2배!

1. 운동을 기록해 변화를 기록해 보아요.

1) 원하는 날짜를 선택하고 운동일지 추가를 클릭
2) 운동을 추가하고 세트, 무게, 횟수를 설정
3) 운동을 완료하면 체크 버튼 클릭
4) 일지 공유하기를 클릭해 사람들과 오늘의 운동 공유
운동을 깜빡할까 불안하신가요? 까먹지 않게 알림을 통해 알려드려요!

2. 운동 일지와 루틴을 작성하고 공유해요.

1) 본인의 운동 루틴과 일지를 작성하고 공유할 수 있어요.
2) 다른 유저들의 운동 루틴도 함께 공유 받고 본인의 루틴으로 작성할 수 있어요.
어떻게 운동을 시작할지 막막하다면? 걱정마세요! 근근근에서는 사용자의 인바디 점수 기반의 추천 알고리즘으로 다른 사용자의 운동일지와 루틴를 추천해드리고 있어요.

3. 다른 사람들과 소통해 보아요.

1) 운동일지와 루틴의 댓글을 통해 사람들과 소통해요!
2) 운동을 열심히 하는 사람이 있다면 팔로우해서 동기부여를 해보아요.
3) 궁금한걸 자세하게 물어보고 싶다면? 채팅을 통해 자세히 얘기를 나누어 보아요.

4. 트레이너 자격을 검증받아요.

1) 트레이너 등급으로 승급하기 위해 자격증과 수상경력을 제출할 수 있어요.
2) 관리자는 제출된 내용을 검토해서 승인 혹은 반려할 수 있어요.
3) 트레이너 등급으로 승급 시 라벨이 트레이너로 바뀌어요.
PT 상담을 받으러 갔는데 불안해서 고민이신가요? 초보자분들은 신뢰성 있고 전문성 있는 트레이너를 선별하기 어려워요. 근근근이 제공하는 검증된 트레이너와 안전하고 효율적인 트레이닝을 경험해 보세요.
그럼 이제 근근근과 함께 안전하고 건강하게 득근하러 가볼까요?

활용 라이브러리 및 개발 환경

옹기종기 팀에서 사용한 활용 라이브러리 와 개발 환경이에요.

Frontend

기술 스택
React 컴포넌트 기반 아키텍처로, 코드의 재사용성을 높이고 분리 및 결합이 쉬워 유지 보수를 편리하게 할 수 있어서 사용했어요.
Typescript 런타임 에러를 줄이고 안정적인 코드를 작성할 수 있어서 사용했어요.
vite 빠른 개발 서버를 지원하고 최소한의 설정으로 초기 설정의 부담을 줄이고 빌드 성능이 좋아 생산성 향상을 할 수 있다는 점에서 사용했어요.
styled-components CSS-in-JS 방식을 활용해 React 컴포넌트를 구성하여 코드의 가독성을 향상 시키고 유지 보수를 쉽게 할 수 있어 사용했어요.
recoil 보일러 플레이트가 적고 상태 관리가 쉬워서 사용했어요.
apexcharts 데모와 소스코드가 보기 쉽게 구성되어 있고 기본적인 디자인이 예뻐서 사용했어요.
sockjs 브라우저 호환성이나 다양한 네트워크 환경에서 안정적인 양방향 통신을 구현하기 위해 사용했어요.
stompjs Web Socket 통신 시 백엔드와 STOMP 프로토콜을 통해 통신하기 위해 사용했어요.
firebase FCM토큰을 받아오기 위해 사용했어요.
axios HTTP 요청 취소 및 요청과 응답을 JSON 형태로 자동 변환해주기 때문에 사용했어요.
eslint 코딩 스타일을 통일해 코드 품질을 향상 시키기 위해 사용했어요.
worker-timers Web Worker를 이용한 타이머를 구현하는데 라이브러리도 안정적이고 꾸준히 업데이트 되어서 사용했어요.
esli

Backend

Language (언어)
Java 17 주요 개발 언어로 개발 당시 최신 LTS 버전의 Java 예요.
Framework (프레임워크)
SpringBoot 3.1.4 개발을 위한 편리한 프레임워크로, 빠른 설정과 쉬운 배포가 가능하고, 스프링 애플리케이션을 쉽게 만들 수 있도록 도와줘요.
Spring Data JPA 데이터베이스 작업을 간편하게 만들어 주는 프레임워크예요. Java Persistence API를 사용하여 데이터 접근과 관리를 단순화해요.
Querydsl SQL 쿼리를 타입 안전하게 작성할 수 있도록 도와주는 도구입니다. 복잡한 쿼리 작성과 동적쿼리를 보다 쉽게 사용할 수 있어요.
Spring Security 웹 애플리케이션의 보안을 위한 프레임워크예요. 인증과 권한 부여 기능을 제공하여 애플리케이션을 보호해줘요.
OAuth2 웹, 모바일, 데스크톱 애플리케이션에서 사용자 인증 및 권한 부여를 위한 표준화된 프로토콜이에요. 사용자의 자격 증명을 안전하게 공유하지 않고도, 애플리케이션이 사용자의 대신 행동할 수 있게 해줘요.
Jwt (JSON Web Token) 간편하고 안전한 방식으로 정보를 교환하기 위한 토큰 기반 시스템이며 인증 정보를 토큰에 담아 사용해요.
Spring WebSocket 양방향 통신을 지원하는 프레임워크로, 클라이언트와 서버 간의 실시간 데이터 교환을 가능하게 해요.
stomp 메시징 프로토콜로, 클라이언트와 서버 간의 메시지 기반 통신을 지원하며, 주로 웹 소켓과 함께 사용돼요.
Database (데이터베이스)
MySql 관계형 데이터베이스 관리 시스템이에요.
Redis 인-메모리 데이터 구조 저장소 및 데이터베이스예요.
ETC
AWS S3 아마존에서 제공하는 대규모 데이터 저장 서비스예요. 다양한 형태의 데이터를 저장하고 관리할 수 있어요.
Firebase 구글에서 제공하는 모바일 및 웹 앱 개발 플랫폼이에요. 데이터베이스, 인증, 알림 등 다양한 기능을 제공해요.
Spring Rest Docs API 문서를 쉽게 작성하고 관리할 수 있게 도와주는 도구예요. 정확하고 상세한 API 문서를 생성할 수 있어요.

트러블 슈팅 Trouble Shooting

옹기종기 팀에서 발견한 개발 이슈는 어떻게 해결했을까요?

Frontend

다른 웹 페이지로 이동했을 때 운동 타이머가 동작하지 않는 문제가 발생했어요.
원인
setInterval 이 메인 스레드에서 동작해 다른 곳으로 가면 타이머가 동작을 멈췄어요.
사용자가 운동일지를 기록하면서 유튜브, 카카오톡 등을 오가면서 사용할 수 있으므로 타이머를 백그라운드에서 실행시킬 방법이 필요했어요.
해결
문제 해결을 위해 조사 하던 중 Web Workerworker-timers 라이브러리를 찾았어요.
Web Worker는 메인 스레드와 별개로 작동되는 스레드를 생성해줘요.
worker-timersWeb Worker를 이용해 setIntervalsetTimeout을 구현한 라이브러리에요
setIntervalsetTimeout에 대해 알고 있다면 러닝 커브 없이 Web Worker 기능을 사용할 수 있으므로 worker-timers 라이브러리를 이용해 타이머를 구현해 문제를 해결했어요.
Input Component 에 글자를 입력할 때마다 페이지 전체가 재랜더링 되는 이슈가 있었어요.
원인
상위 컴포넌트에 재사용가능한 Input Component 호출했어요
상위 컴포넌트에서 상태를 선언하고 Input ComponentProps상태를 전달했어요.
해결
문제 해결을 위해 조사 하던 중 Uncontrolled Component 에 대해 알게됐어요
React HooksuseRef forwardRef를 사용해서 상태 바인딩을 하지 않고 DOM에 직접 접근해서 불필요한 렌더링을 줄였어요.
유저 검색 시 서버에 수많은 요청이 보내졌어요
원인
사용자 UX 를 개선하기 위해, 글자를 입력할 때 마다 검색 결과를 반환하게 구현했어요.
해결
React HooksuseEffect 를 활용해서 Debounce 를 구현했어요.
글자 입력이 모두 끝났을 때 요청이 날아가도록 구현해서 요청 수를 줄일 수 있었어요.
스크롤을 할 때마다 루틴 목록, 운동 일지 목록을 불러오는데 성능적 이슈가 있었어요.
원인
Scroll Event 를 사용해서 사용자가 스크롤을 할 때마다 함수가 동작하게 구현해서 발생한 문제였어요.
해결
Intersection Observer 를 사용해서 최하단까지 스크롤 했을 때 함수가 동작하도록 구현해서 성능을 향상시킬 수 있었어요.

Backend

서비스 레이어의 코드의 길이가 길어지고 가독성이 낮아지는 문제가 생겼어요.
원인
각각의 서비스 레이어에서 같은 기능을 하는 조회 로직이 작성되어 있었어요. 각 서비스에서 같은 로직이 작성되어 있다보니 서비스 레이어마다 코드의 양이 증가하고, 가독성이 좋지 않아졌어요.
해결
Helper class 를 생성하여 공통되는 로직을 각 서비스에서 참조할 수 있도록 해결했어요.
이를 통해 비즈니스 로직의 일관성을 보장하고 재사용이 가능한 코드를 작성하여 가독성 외에도 유지보수에 이점을 가져갈 수 있었어요.
서비스 간의 참조보다 Helper class 를 사용했기 때문에 순환 참조에서 안전함을 가져가고, 중복되는 코드를 줄어드는 효과를 얻을 수 있었어요.
각 엔티티들을 패키지 한 곳에서 관리하는데 늘어남에 따라 관리가 어려워 졌어요.
원인
이전 프로젝트에서는 도메인 별로 패키지를 나눠서 각 패키지 안에 엔티티를 관리 했는데 이번엔 엔티티들을 도메인 패키지 한 곳에서 관리하기로 했는데 프로젝트 기능이 늘어남에 따라 한 패키지 안에서 너무 많은 도메인들을 관리하고 찾기가 어려워 졌어요.
해결
도메인 패키지 내부에서 도메인 별로 패키지로 나누어서 엔티티를 관리하기로 했어요.

옹기종기 팀 소개 Team Introduce

개발에 대한 열정, 의지만 있다면 우리와 함께해요!
Frontend
김준서 | jykim9868@gmail.com 팀 리더
조재균 | kyeun950830@gmail.com
한승재 | hseungjae1202@naver.com 팀장
한세라 | hsr0782@gmail.com
Backend
고예진 | yaejingo@gmail.com
안병규 | an622911@gmail.com 팀장
이동진 | dlehdwls21@naver.com
이정준 | uuufg3322@gmail.com
팀명이 옹기종기인 이유는 무엇인가요? 저희 팀원들이 구름 스페이스 구석에 모여 있는 모습을 보고 ‘옹기종기’라는 이름이 붙었어요. 교육이 시작할 때부터 끝날 때까지 옹기종기 모여 스터디와 회의를 진행했답니다
옹기종기 팀만의 강점은 무엇인가요? 저희 팀의 강점은 속도와 전략에 있어요. 모든 팀원들이 마치 1분 대기조처럼, 필요할 때마다 빠르게 디스코드를 통해 소통하고 모이는 습관이 팀 전반의 작업 효율성을 높였어요. 옹기종기 팀만의 개발 프로세스가 있고 협업 규약이 있어요. 매 프로젝트마다 프로세스와 규약을 개선하고 실행해 왔어요. 이로써 프로젝트 구현이 빠르게 진행되었고, 팀 전체의 협업 능력을 향상시키는 데 큰 역할을 했어요.