
핏플(Fitple) 프로젝트 진행기 (1차 프로젝트)
멋쟁이 사자처럼 프론트엔드 심화 4기에서 현재 1차 프로젝트를 진행하고 있다.
이번 프로젝트의 중요한 조건은 다음과 같다.
- 클린 아키텍처 기반 백엔드 설계
- DB는 Supabase 활용
- CSR(Client Side Rendering) 환경으로만 구성
크게 보면 이 세 가지가 가장 중요한 조건이었다.
프로젝트 주제 : "핏플" (Fitple)
우리가 기획한 주제는 '핏플'이라는 이름을 가진 사이드 프로젝트 양방향 매칭 플랫폼이다.
나 역시 포트폴리오를 쌓거나, 새로운 경험을 하고 싶을 때 인프런이나 홀라 같은 플랫폼을 찾아보곤 했다.
하지만 항상 아쉬웠던 점은, 그런 플랫폼들도 결국 "회사 취업"처럼 운영된다는 점이었다.
- 프로젝트 모집글이 올라온다
- 내가 지원한다
- 면접을 보고, 커피챗을 하고
- 최종적으로 합류 여부가 결정된다
물론 이런 과정은 필요하지만,
한편으로는 "내가 나를 소개하는 글을 올려두고",
"프로젝트 모집자가 나를 찾아올 수 있다면?" 더 편하고 기회가 넓어질 수 있다고 생각했다.
그래서 양방향 매칭이 가능한 플랫폼을 만들기로 조원들과 함께 결정했다.
기능 구현 상황
DB 설계나 더 세세한 개발 이야기는 차후 프로젝트 회고에서 다루기로 하고,
이번 글에서는 내가 추가적으로 도전해보고 싶은 기능에 대해 기록하려고 한다.
현재 구현된 기본 기능은 다음과 같다.
- 요청을 보내는 기능
- 요청이 수락되면 팀이 자동으로 생성되는 기능
하지만, 여기서 끝나는 것만으로는 플랫폼으로서 아쉬움이 남았다.
'팀'이 만들어졌으면 그 안에서 사용자 간에 상호작용이 가능해야 진짜 서비스답다고 생각했다.
그래서, 팀 디테일 페이지에 "채팅 기능" 을 직접 구현해보기로 했다.
내가 목표로 잡은 채팅 기능
- 만들어진 팀마다 별도의 채팅방이 존재할 것
- 내가 보낸 메시지와 상대방 메시지를 시각적으로 구분할 것
(ex. 나의 메시지는 오른쪽 정렬) - 거의 실시간처럼 보이게, 빠른 반영이 가능할 것
- 채팅 데이터를 DB에 저장하여, 페이지를 새로고침해도 과거 대화가 남아있을 것
현실적인 제약과 방법 찾기
'웹소켓'이나 '리얼타임' 같은 기술들을 들어본 적은 있었지만, 직접 구현하는 건 처음이었다.
하지만 문제는, 우리는 서버를 따로 띄울 수 없는 환경이었고,
쿠키 기반 업데이트(SWR hooks 등) 도 자유롭게 사용할 수 없었다.
그런 상황에서 찾은 방법이 바로 풀링(Polling) 이었다.
- 풀링(Polling)이란?
→ 클라이언트가 주기적으로 서버에 요청을 보내서
→ 데이터 변화를 감지하고, 변화가 있으면 화면을 업데이트하는 방식이다.
예를 들면, 3초마다 서버에 요청을 보내
"새로운 메시지가 있는지" 확인하고, 있으면 바로 반영하는 식이다.
지금의 환경에서는 웹소켓만큼은 아니지만,
거의 실시간처럼 보이게 하는 좋은 대안이라고 생각했다.
먼저 UI는 다음과 같은 형태로 구성했다.
내가 보낸 메세지와 남이 보낸 메세지의 색과 위치를 구분하여 사용자가 편하게 구분할 수 있도록 구현했다.
코드 구현
1. 만들어진 팀 마다 별도의 채팅방이 존재할 것
구현 방법
- ChatBox 컴포넌트에서 props로 teamId를 받도록 했다.
- 이렇게 해서 팀 고유의 teamId를 기준으로 각 팀마다 별도 채팅방을 생성할 수 있도록 설계했다.
2. 내가 보낸 메세지와 상대방의 메세지를 구분할 것
구현 방법
- 채팅 목록을 렌더링할 때 user_id를 체크했다.
- user_id가 나(me) 라면 self-end를 적용해서 오른쪽 정렬하고,
상대방이면 self-start로 왼쪽 정렬하게 했다. 또한 배경색도 다르게 주어 나의 메시지는 bg-blue, 상대방 메시지는 bg-gray 로 구분되게 스타일링했다.
3. 거의 실시간 처럼 보이게, 빠른 반영이 가능할 것
구현 방법
- fetchMessages 함수를 만들어서 /api/member/chat/${teamId} 경로로 채팅 데이터를 요청했다.
- useEffect 안에서
- 컴포넌트가 처음 마운트될 때 한 번 데이터를 불러오고,
- 이후에는 setInterval을 이용해 3초마다 주기적으로 fetch 하도록 설정했다.
- clearInterval을 리턴해서 컴포넌트가 언마운트될 때 인터벌을 해제해주었다. (클린업)
- 추가로, 새로운 메시지가 추가될 때마다 채팅창이 자동으로 스크롤 되도록 처리했다.
- useRef로 채팅 리스트의 DOM 요소를 참조한 뒤, scrollTo 메서드를 사용해 스크롤을 최하단으로 이동시켰다.
4. 채팅 데이터를 DB에 저장하여, 페이지를 새로고침해도 과거 대화가 남아있을 것
구현 방법
- 사용자가 메시지를 입력하고 전송할 때 handleSend 함수가 호출된다.
- fetch를 이용해 /api/member/chat/${teamId} API 엔드포인트로 POST 요청을 보낸다.
- 요청 바디에는 user_id와 message를 함께 담아 보낸다.
- 메시지를 서버에 성공적으로 저장한 후 fetchMessages를 다시 호출해서 최신 채팅 목록을 불러온다.
- 이 구조 덕분에 메시지가 Supabase DB에 저장되고,
페이지를 새로고침해도 과거 대화 내역을 불러올 수 있게 만들었다.
시연 영상
아쉬웠던 점
채팅 기능을 구현하면서 가장 아쉬웠던 부분은,
상대방 채팅의 정보(닉네임, 프로필 사진, 시간) 를 가져오지 못했다는 점이다.
지금은 단순히 메시지 내용만 불러오고 있어서,
나를 제외한 상대방이 누구인지, 언제 보낸 메시지인지 알 수 없는 상태다.
- 누가 보낸 메시지인지 구분이 어렵고,
- 대화 흐름이나 시간의 흐름도 파악하기 어렵다.
아쉬웠던 이유
이번에 급하게 채팅 기본 기능만 완성하는 데 집중하다 보니,
DB 구조나 API 응답 형태를 확장하는 데까지는 미처 손이 닿지 못했다.
현재 메시지 테이블에는 user_id, message, created_at 같은 기본 정보는 저장되어 있지만,
프론트에서 user_id만 가지고는 사용자의 닉네임이나 프로필 이미지를 바로 알 수 없기 때문에,
추가적인 데이터 Join이나 API 수정이 필요했었다.
앞으로 개선하고 싶은 방향
- 채팅 데이터에 닉네임, 프로필 사진, 생성 시간(created_at) 을 함께 불러오도록 API 수정
- 메시지 카드 형태로 닉네임, 사진, 시간까지 자연스럽게 노출
- 필요하다면 메시지를 보낼 때 자동으로 현재 시간을 저장하는 처리도 추가
'경험들 > 교육' 카테고리의 다른 글
멋쟁이 사자처럼 프론트엔드 심화과정 4기 - 1차 프로젝트 회고 (0) | 2025.05.04 |
---|---|
멋쟁이 사자처럼 프론트엔드 심화과정 4기 - Day 6 (0) | 2025.04.20 |
멋쟁이 사자처럼 프론트엔드 심화과정 4기 - Day 5 (0) | 2025.04.08 |
멋쟁이 사자처럼 프론트엔드 심화과정 4기 - Day 4 (0) | 2025.04.05 |
멋쟁이 사자처럼 프론트엔드 심화과정 4기 - Day 3 (4) | 2025.04.04 |
프론트엔드 공부 기록 및 나의 성장기
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!