프렌즈 앱은 사용자의 감정을 단순히 기록하는 것을 넘어서 그 감정의 패턴을 시간, 날씨, 활동 같은 외부 요인과 연결해서 보여주고 싶었다. 단순한 통계를 넘어서 사용자 스스로 감정을 이해하고 관리할 수 있도록 데이터를 읽어주는 시스템을 만들고자 했다.
문제 인식: 감정 기록의 한계를 넘어서
처음에는 감정 기록 기능만 있었다. 사용자는 감정을 선택하고 메모를 남길 수 있었지만 기록이 쌓일수록 느꼈다.
- 감정 데이터는 쌓이지만 사용자가 그걸 해석하거나 활용하긴 어렵다.
- 통계 수치는 보여주더라도 흐름이나 원인을 파악하긴 어렵다.
- 그래서인지 기록도 점점 이어지지 않는다.
단순 기록에서 벗어나기 위해선 감정을 둘러싼 시간대, 날씨, 활동 같은 맥락을 함께 분석하고 그걸 사용자에게 해석된 문장으로 전달해줄 필요가 있었다.
데이터베이스 구조
감정 분석 기능은 여러 테이블이 연결된 구조로 되어 있다. 각 테이블은 다음과 같은 역할을 가진다.
테이블 구조 요약
users (1) ───< moods (N) ───< mood_activities (N)
\
\
└──< weather_data (N)
users (1) ───< mood_analysis (N)
- users: 사용자 정보
- moods: 감정 기록 (감정 유형, 메모, 기록 날짜 등)
- mood_activities: 감정 기록과 함께 저장된 활동들 (산책, 운동 등)
- weather_data: 해당 시점의 날씨 상태, 기온, 습도, 위치 정보
- mood_analysis: 분석 결과 저장 테이블
설계 시 고려한 관계와 인덱스
- 모든 user_id는 users 테이블을 참조하며, 삭제 시 CASCADE
- 날짜 기반 분석이 많기 때문에 user_id + date 조합 인덱스를 여러 테이블에 구성
- 분석 결과에 접근을 빠르게 하기 위해 user_id + analysis_date 에도 인덱스를 둠
분석 흐름 정리
- 감정 및 날씨 데이터 수집
- 사용자가 감정을 기록하면 해당 시점의 감정 유형, 메모, 활동이 함께 저장됨
- 날씨 정보는 외부 API에서 자동 수집되어 날씨 테이블에 저장됨
- 시간 기반 분석
- 하루 중 어느 시간대에 어떤 감정이 자주 나타나는지 분석
- 요일별, 주간, 월간 감정 흐름도 함께 계산
- 스트릭(연속 기록 일수)도 추적해서 분석에 포함함
- 날씨 연관성 분석
- 긍정적인 감정이 자주 나타나는 날씨 조건이 있는지 확인
- 감정과 평균 온도/습도 사이의 상관관계를 계산함
- 활동-감정 상관관계
- 활동별로 감정 점수와의 상관관계를 계산
- 예를 들어, 산책은 행복과 0.7 이상의 양의 상관관계를, 야근은 슬픔과 -0.4 정도의 음의 상관관계를 보일 수 있음
AI 분석: 데이터를 읽어주는 글로
숫자와 차트만으론 감정의 의미를 전달하기 어렵다. 그래서 OpenAI API를 통해 분석된 데이터를 기반으로 자연어 인사이트를 생성하는 기능을 추가했다.
어떻게 작동하는가
AiServiceImpl 에서 프롬프트를 구성함
- 프롬프트 내용:
- 최근 가장 자주 느낀 감정
- 행복 백분율
- 스트릭(연속 기록)
- 가장 흔한 날씨 / 평균 온도
- 활동-감정 상관관계 요약
이 프롬프트를 OpenAI API로 전달하면 사람에게 말하듯 해석한 문장이 응답으로 돌아온다.
예를 들어
요즘은 흐린 날보다 맑은 날에 더 기분이 좋은 경향이 보여요. 산책은 여전히 긍정적인 감정과 자주 함께 기록되고 있어요.
예외 대응
- OpenAI API 호출이 실패할 경우를 대비해 단순 통계 기반 fallback 분석 문장을 제공하는 로직도 구현함
프론트엔드: 어떻게 보여줄까?
- Swift 기반의 화면에서 감정 분석 결과를 시각화함
- 주/월/3개월 단위로 감정 흐름을 확인할 수 있게 구성
- AI가 생성한 분석 문장은 별도로 강조되어 표시함
마무리하며
감정 기록 앱을 만들면서 느낀 건 단순한 기록만으로는 변화나 통찰을 만들기 어렵다는 점이었다. 중요한 건 그 데이터를 어떻게 연결하고, 해석하고, 전달하느냐였다.
시간, 날씨, 활동이라는 외부 요인과 감정을 연결해 사용자 스스로 "왜 이런 기분이었을까?"를 돌아볼 수 있도록 도왔다는 점에서 백엔드 설계가 단순한 저장 이상의 역할을 할 수 있음을 경험할 수 있었다.