프로그래머스 2차 프로젝트가 끝났다. 아이디어도 재밌었고 기획도 잘 뽑혀서 정말 재미있게 작업했던 것 같다. 멘토님이 처음 우리의 기획과 디자인을 보시고는 "기획과 디자인은 정말 좋은데 3주만에 다 할 수 있겠어요?"라고 물어보셨다. 팀원들과 대화해 보고 괜찮을 것 같다 판단했고 강행했다. 그리고 우리는 선배님의 조언은 마음에 새겨들어야 한다는 것을 깨달았다.
# 프로젝트 개요
우리 프로젝트는 감정 일기 컨셉이였다. 일기를 작성할 때 내가 당시 느끼는 감정을 선택하고 왜 이런 감정을 느꼈는지 일기 형식으로 기록하는 아이디어였다.
•프로젝트명 : Seediary
•개발 기간 : 3주 ( 2025.07.22 ~ 2025.08.06 )
•팀 구성 : 4명
•기술 스택 : React, supabase
리액트 수업이 끝난 직후 처음으로 하는 프로젝트라 리액트 생태계에서 많이 사용되는 라이브러리들을 사용하지 않고, 최대한 리액트 바닐라? 기술만 사용하여 작업해 보기로 했다. 또한 github project로 이슈를 관리하며 모든 작업 기록을 남겨 두었다.
# 기획과 설계 단계
팀원 4명이서 하나씩 아이디어를 러프하게 기획해왔고 투표로 선정했다. 내 아이디어는 익명 게시판이였는데 사용자에게 소셜 포인트를 부여하고 포인트가 낮으면 익명성을 잃어 버리는 자정작용이 가능한 익명 서비스였다. 아쉽게도 감정 일기와 동점이였다가 두 번째 투표에서 떨어지고 말았다. 3차에는 할 수 있을까?
최종 기획 방향
기본적으로 감정 일기 형태의 서비스에 요즘 트렌드인 AI를 활용한 서비스를 만들어 보기로 했다. 멘탈 케어 챗봇과 일기와 선택한 감정을 AI가 분석해주는 기능 멘토님도 최신 트렌드를 잘 반영한 아이디어라고 말씀해주셨다.
주요 기능 설계
•일기 작성 + 메인 감정 선택
•사용자가 작성한 일기와 선택 데이터 기반으로 AI 감정 분석 및 시각화
•AI 멘탈 케어 챗봇
•커뮤니티
기술적 설계
•프론트엔드 : React 바닐라
•백엔드 : Supabase
•외부 API : Gemini API
# 개발 과정
내가 맡은 파트는 로그인, 회원가입, 마이페이지, 실시간 알림, AI 챗봇, 감정분석 기능 구현과 각종 공통 로직들이었다.
프로젝트를 진행하면서 마주한 트러블 슈팅을 정리해 보았다.
1. 사용자 상태 관리와 인증 시스템
로그인과 회원가입은 간단하게 UI와 supabase의 Authentication 기능들을 사용해서 손쉽게 구현하였다. GNB도 함께 구현하면서 User 상태를 관리하기 위한 useUser 공통 훅을 만들어 사용했지만 여러 페이지에서 서로 다른 인스턴스를 생성하며 데이터 동기화가 되지 않아 UserContext를 만들어 사용하기로 했다.
문제 상황
이메일 로그인만 적용 했을 땐 쉽게 구현했지만 github login이 추가되면고 user 상태 감지하는 onAuthStateChange의 콜백에서 데이터 통신에 블로킹이 걸려 애를 먹었다..
콜백에서 비동기 로직을 구현하게 되면 경쟁 상태가 되어 비동기 로직의 순서를 보장하지 못할 수 도 있고 유저 상태에 따른 업데이트나 UI 변경 로직이 포함되면 무한 로딩 상태로 네트워크 블로킹 상태가 될 수 있는데 나도 콜백에 유저 상태를 업데이트하고 이에 따른 UI 변경 로직이 들어있어 블로킹 상태가 되어 웹서비스 전체가 먹통이 되었다.
해결 방안
콜백에서 최소한의 상태만 업데이트하고 비동기 통신을 하더라도 결과를 기다리지 않아도 되는 API 통신( fire-and-forget 방식)만 콜백 내부에서 호출하게 만들고 추가적인 API 통신이나 사이드 이펙트들은 별도의 useEffect와 loading state로 관리하여 해결했다.
2. AI 챗봇, AI 감정 분석
AI 챗봇은 supabase에서 제공해주는 edge function과 테이블 real time 기능을 활용하여 구현 했다. chat_messages 태이블을 리얼타임으로 설정 후 테이블에 유저의 insert가 감지되면 edge function이 호출되고 AI 답변을 받아 메시지 테이블에 저장하는 방식으로 채팅을 구현했다.
문제 상황
Gemini API는 단발성으로만 사용 가능하기 때문에 이전 채팅 내용은 기억하지 못했다. 그래서 사용자가 작성한 메시지와 AI 답변을 같이 매 호출마다 프롬프트에 작성하여 전달해줘야 했다.
이 방법은 메시지 양이 많아질수록 select하는 row 데이터도 많아지고 Gemini API에 보낼 프롬프트의 양도 많아지기 때문에 성능 이슈가 발생할 것이라 생각했다. 이를 해결하기 위해 하루 50개 메시지를 제한하기로 했다. 멘탈 케어 챗봇이기 때문에 사용자에게 직접적으로 "5개 남았다", "소진되었다"라는 문구를 보여주고 싶지 않았다.
해결 방안
처음에는 user_chat_session 테이블을 생성하고 유저 접속 시마다 메시지 카운트를 업데이트하는 방식으로 구현했다. 메시지 제한 알림도 "5회 남음", "소진됨" 같은 직접적인 문구 대신 자연스러운 메시지로 페어를 여러개로 만들고 해당 테이블에 랜덤하게 인덱스를 업데이트해서 불러오게 만들었다.
동작은 잘했지만 클라이언트에서 데이터를 select → update → 다시 select하는 과정이 너무 복잡했다. 유지보수성이 떨어질 뿐만 아니라 테이블 업데이트 로직이 실패하면 되돌리는 방법도 복잡했다.
supabase 테이블에 함수를 작성하여 gemini API 와 통신하는 edge function에서 해당 함수를 rpc로 호출하여 백엔드에서 처리하게 만들었다.
rpc를 사용하므로서 클라이언트 단에서 복잡한 로직을 처리할 필요가 없어졌고, rpc 호출 한번으로 모든 로직을 처리할 수 있었기 떄문에 데이터 일관성도 보장할 수 있게 되었다.
# 결과
멘토님의 우려를 뒤로 하고 우리가 기획했던 모든 기능을 구현할 수 있었다. 생각보다 프로젝트의 퀄리티가 좋아 너무 만족스러운 프로젝트를 완성한 것 같아 뿌듯하다. supabase를 사용한 프로젝트는 처음이였는데 복잡하고 귀찮은 작업들을 supbase가 처리해줘서 쉽게 실시간 채팅이나 실시간 알림과 같은 기능들을 구현할 수 있었다. 또한 웹 접근성을 최대한 고려하며 웹사이트를 제작하여 거의 모든 페이지의 lighthouse 접수가 95점을 넘을 수 있었다.
# 배운점과 성장
개인적으로 했던 리액트 프로젝트는 정확한 이해 없이 구현하기 급급했던 것 같다는 생각이 들었다. 이번 프로젝트를 하면서 전역 상태 관리, 웹 접근성, 그리고 컴포넌트 설계에 대해 생각을 많이 할 수 있었고, 공통 로직을 작성하면서 타입스크립트에 대한 깨달음을 얻은 것 같았다. 그냥 코드를 작성할 때는 잘 몰랐지만 공통 로직을 작성할때의 타입스크립트는 정말.. 어려웠다.
프로젝트 초기 코드가 복잡하지 않은 단계에선 리렌더링 최적화를 고려하며 작업했지만, 작업을 하면서 점점 코드 양이 증가하고 여러가지의 상태들과 복잡한 로직이 추가되면서 최적화 고려를 후반에는 많이 못했고 이로 인해 코드 리팩토링을 할 때 정말 애를 많이 먹었다. 다음 프로젝트에는 항상 확장성과 리렌더링 최적화를 고려하며 코드를 작성하는데 집중해야 할 것 같다.
# 마치며
3주간의 여정이 끝났지만, 이 프로젝트를 통해 정말 많은 것을 배울 수 있었다. 특히 팀원들과 함께 하나의 서비스를 완성해나가는 과정에서 개발 실력뿐만 아니라 협업 능력도 크게 성장할 수 있었던 것 같다.
🌱 Seediary 체험해보기
저희가 만든 감정 일기 서비스 Seediary는 여기서 직접 체험해 볼 수 있습니다.
여러분도 매일 느끼는 감정을 기록하고 당신의 마음에 씨앗을 심어보세요.