티스토리 뷰

1. 프로젝트 개요 (Project Overview)

핏메이트(Fitmate)는 '핏'과 '메이트'를 결합한 이름으로, 헬스와 관련된 맞춤형 트레이닝을 돕는 친구 같은 존재를 의미합니다. 이 서비스는 운동 전문가와 건강 운동을 배우고자 하는 유저를 매칭하여 1:1 맞춤형 운동 프로그램을 제공하는 것을 목표로 합니다. 또한,  AI 챗봇 기능을 제공하여 사용자 입력을 분석하여 맞춤형 운동 추천 및 운동 관련 질문에 대한 응답을  제공합니다.

2. 담당한 작업 (Task & Contribution)

백엔드 개발

  • 데이터베이스 설계
  • 레슨 관련 API 개발
    • 레슨 요청 및 취소 기능
    • 레슨 목록 및 레슨 상세 조회
    • 내가 신청한 레슨 목록 조회
    • 나의 요청 레슨에 대한 지정 견적 요청 생성
    • 지정 견적 요청에 대한 반려 기능 (트레이너)
  • 견적 관련 API  개발
    • 견적 작성 기능
    • 견적 목록 및 견적 상세 조회
    • 견적 확정 및 반려 기능
    • 리뷰 작성 가능한 견적 목록 조회
  • 알림 시스템 구현
    • 유저 알림 목록 조회
    • 특정 알림 읽음 처리 (토글)
    • 특정 유저에게 알림 전송 (SSE 방식)
    • 트리거와 저장 프로시저를 이용한 알림 생성 기능 개발
  • Fitmate AI 챗봇 구현
    • OpenAI API를 이용하여 맞춤형 운동 추천 챗봇 개발

3. 기술적 성과 (Technical Achievements)

  • AI 챗봇 구현
    • OpenAI ChatGPT-4-mini를 활용한 맞춤형 운동 추천 및 질의응답 기능 구현
    • 사용자 입력 분석을 최적화하여 자연스러운 한국어 문장으로 응답 제공
    • 프롬프트 엔지니어링을 통해 챗봇의 답변 품질 향상
  • SSE 기반 실시간 알림 시스템 구현
    • PostgreSQL LISTEN/NOTIFY와 RxJS를 활용하여 SSE(Server-Sent Events) 방식의 실시간 알림 처리
    • RxJS Subject를 활용한 사용자별 알림 스트림 관리 및 최적화
    • 레슨 요청, 견적 확정, 레슨 완료 등의 주요 이벤트 발생 시 실시간 알림 제공
  • 트리거 및 저장 프로시저 기반 알림 자동화
    • PostgreSQL 트리거 및 저장 프로시저를 활용하여 레슨 상태 변경, 견적 요청 등의 이벤트 발생 시 자동으로 알림 생성
    • LISTEN/NOTIFY 기능을 활용하여 서버와의 연동 없이 데이터베이스 레벨에서 실시간 알림 전송
  • NestJS 기반 백엔드 아키텍처 최적화
    • Dto(Data Transfer Object)를 활용하여 데이터 유효성 검증 및 타입 안전성 확보
    • 서비스(Service) 로직, 컨트롤러(Controller) 로직, 레포지토리(Repository) 로직을 분리하여 각각의 책임을 명확히 구분
    • 의존성 주입(Dependency Injection)과 모듈화 구조를 도입하여 유지보수성을 향상

4. 문제점 및 해결 과정 (Challenges & Solutions)

1) 발생 문제: 알림 생성 시간 오차 문제

  • API 응답에서 createdAt, updatedAt 값이 현재시간보다 9시간 늦게 표시됨
  • 프론트엔드에서 알림 시간이 현재시간보다 9시간 더해지는 문제 발생

2) 원인 분석

  • 저장 프로시저에서 now() 사용 시 OS 타임존(KST)이 적용되어 KST 기준으로 저장됨
  • 하지만 프론트엔드는 이를 UTC로 가정하고 KST 변환을 추가 수행, 결과적으로 9시간 차이 발생

3)해결 방법

  • 저장 프로시저에서 now()를 UTC로 변환하여 저장하도록 수정
BEGIN
  INSERT INTO "Notification" (
    "userId", "type", "message", "createdAt", "updatedAt"
  ) VALUES (
    user_id, type::"NotificationType", message,
    now() AT TIME ZONE 'UTC', -- UTC 변환하여 저장
    now() AT TIME ZONE 'UTC'
  );
END;
  • now()를 UTC 기준으로 변환하여 저장해 일관성 유지

4) 배운 점 및 개선 사항

  • 데이터베이스 레벨에서의 now()는 OS 타임존 영향을 받으므로, DB에서 직접 UTC 변환이 필요함
  • 애플리케이션 레이어에서 시간을 생성하면 UTC로 저장되지만, 트리거·저장 프로시저에서는 명확한 변환 적용 필요
  • API 응답에서 추가 변환 없이 UTC → KST 처리가 가능하도록 시간 동기화 전략을 명확히 설정해야 함
  •  

5. 협업 및 피드백 (Collaboration & Feedback)

  • 효율적인 협업
    • 코드 리뷰를 통해 서로의 코드를 검토하고 개선 사항을 공유하며 전체적인 코드 품질을 향상시켰습니다.
  • 지식 공유
    • 알림 시스템 구현 과정에서 PostgreSQL과 SSE 기반의 실시간 알림 처리 방식뿐만 아니라, 타임존 개념에 대한 이해도를 높였습니다.
    • 특히, UTC 기반 시간 저장 및 변환 방식에 대한 논의를 통해, API 응답에서의 일관된 시간 처리를 보장하는 방법을 공유하고 적용했습니다.
  • 문제 발생 시 신속한 대응
    • Zoom, Notion, Discord를 적극 활용하여 팀원 간 실시간 피드백을 주고받으며, 발생한 이슈를 빠르게 해결하였습니다.
    • 타임존 변환 오류 및 알림 데이터 전송 관련 문제 해결을 위해 지속적인 테스트와 코드 최적화를 진행했습니다.

6. 코드 품질 및 최적화 (Code Quality & Optimization)

  • NestJS 기반 아키텍처 최적화
    • Dto(Data Transfer Object)를 활용하여 데이터 유효성 검증 및 타입 안전성 확보
    • 인터페이스와 클래스를 적극 활용하여 의존성을 낮추고 재사용성을 높임
    • 서비스(Service) 로직, 컨트롤러(Controller) 로직, 레포지토리(Repository) 로직을 분리하여 각각의 책임을 명확히 구분
  • 서비스 계층 분리 및 유지보수성 향상
    • 컨트롤러에서는 요청을 받아 DTO를 검증하고, 비즈니스 로직은 서비스 계층에서 처리하도록 설계
    • 데이터베이스 접근 로직은 레포지토리 계층에서 관리하여 서비스 계층과 분리
  • 의존성 주입 및 모듈화
    • NestJS의 의존성 주입(Dependency Injection) 시스템을 활용하여 효율적인 모듈 관리를 구현
    • 기능별 모듈을 분리하여 코드의 유지보수성을 향상

7. 향후 개선 사항 및 제안 (Improvements & Recommendations)

  • 프롬프트 엔지니어링을 통한 챗봇 품질 개선
    • 사용자 입력 의도를 보다 정확하게 분석할 수 있도록 프롬프트 최적화
    • 운동 추천 응답의 정확도를 높이기 위해 다양한 예제 학습 데이터 반영
    • 대화 흐름을 더욱 자연스럽게 개선하여 사용자 경험 향상
    • 지속적인 피드백과 테스트를 통해 챗봇 응답 모델 최적화