프로젝트 회고

언교동·2025년 12월 27일

프로젝트

목록 보기
1/1

YumYumNote

1. 프로젝트 개요

프로젝트 이름: 냠냠 노트
진행 기간: 2025.12.01 - 2025.12.26
팀 구성 및 역할: 백 4 + 프론트 1
한 줄 요약: 식단·운동 기록과 AI 추천을 제공하는 프로젝트

2. 프로젝트를 시작하게 된 배경

자취를 시작한 이후, 스스로 건강을 잃어가고 있다는 느낌을 받았다.
영양학적인 지식이 부족했고, 경제적으로도 여유로운 편이 아니었기 때문에 영양소를 고려한 식단을 꾸준히 챙겨 먹는 것이 현실적으로 쉽지 않았다.

또한 초등학교 이후로 제대로 된 운동을 해본 적이 없는 몸 상태였기에, 어떤 운동이 나에게 적합한지 판단하기도 어려웠고, 직접 정보를 찾고 행동으로 옮기는 과정 자체가 큰 부담으로 느껴졌다.

이러한 경험을 통해 나에 대한 정보를 기반으로 식단과 운동을 맞춤형으로 제안해주는 서비스가 있다면, 건강 관리를 훨씬 지속 가능하게 할 수 있지 않을까라는 생각을 하게 되었다.
이 문제를 직접 해결해보고자 하는 마음에서 본 프로젝트를 시작하게 되었다.

3. 기술 스택 및 아키텍처

사용한 기술 스택

Backend

스택용도선택 이유근거
Spring Boot 4 / Java 17 / GroovyAPI 서버안정적이고 생산성 높은 서버 개발 스택backend/README.md, backend/build.gradle
MyBatis / MySQL데이터 접근 / RDBSQL 제어 용이, 운영 친화적 RDBbackend/README.md, backend/build.gradle
Spring Security / JWT인증·인가Stateless API에 적합, 표준 보안 스택backend/README.md, backend/build.gradle
AWS S3이미지 저장확장성 높은 오브젝트 스토리지backend/README.md
Docker Compose로컬 환경백엔드+DB 재현성 확보backend/README.md

Frontend

스택용도선택 이유근거
Vue 3 / Vite / TypeScriptSPA / 빌드빠른 개발 경험, 타입 안정성frontend/package.json
Vue Router / Pinia라우팅 / 상태관리SPA 표준 조합frontend/package.json
Tailwind CSS (+ CVA/clsx/tailwind-merge)UI 스타일링유틸리티 기반, 변형 관리 용이frontend/package.json
AxiosAPI 통신표준 HTTP 클라이언트frontend/package.json
Chart.js / vue-chartjs시각화통계·리포트 차트 구현 용이frontend/package.json
lucide-vue-next아이콘가볍고 일관된 아이콘셋frontend/package.json

AI

스택용도선택 이유근거
FastAPI / UvicornAI API 서버고성능 ASGI, 간결한 라우팅ai/AI/requirements.txt, ai/AI/app/main.py
Pydantic모델 검증요청/응답 검증 및 문서화ai/AI/requirements.txt, ai/AI/app/main.py
Ultralytics YOLO / PyTorch음식 이미지 탐지검증된 객체 탐지 모델/프레임워크ai/AI/requirements.txt, ai/AI/app/main.py
Pillow이미지 처리업로드 이미지 로딩/전처리ai/AI/requirements.txt, ai/AI/app/main.py
python-multipart파일 업로드이미지 업로드 처리ai/AI/requirements.txt, ai/AI/app/main.py
PyYAML라벨 맵클래스 라벨 매핑 유연화ai/AI/requirements.txt, ai/AI/app/main.py

4. Usecase Diagram

5. 주요 기능 소개

도메인Base Path기능 요약
Auth/api/auth로그인/회원가입, 토큰 갱신, 로그아웃, 탈퇴
Users/Follow/api/users, /api/users/{userId}/follow내 정보/프로필 조회, 팔로우/언팔로우, 팔로워/팔로잉 목록
Diet/api/foods, /api/me/diets음식 관리, 식단 기록 등록/조회/수정/삭제
Exercise/api/exercises, /api/me/exercise-records운동 목록/검색, 내 운동 기록 관리
Community/api/posts, /api/posts/{postId}/comments게시글/댓글 CRUD, 좋아요
Challenge/api/challenges챌린지 목록/상세, 참여/탈퇴
Title/api/users/me/title, /api/users/me/titles칭호 조회/설정
AI/api/ai음식 이미지 감지, 식단/운동 평가, 식단 추천
Stats/api/me/stats/week주간 요약 통계
Image/api/images/presignS3 업로드용 Presign URL
AI Chatbot/api/ai/chatbot챗봇 대화 시작/질문, 상태 조회

6. 내가 맡은 역할과 기여도

내가 맡은 역할 - 인증(Auth) 설계 및 구현

본인은 본 프로젝트에서 인증(Auth) 영역을 전담하였다.
인증방식으로는 JWT 인증방식을 채택하였으며, 가장 큰 이유는 서버 확장성과 인증 처리 비용이었다.

서버 확장성 고려 및 인증 처리 비용

초기에는 세션기반 인증 방식도 고려했으나, 사용자가 많아진다면 세션방식은 매 API 요청마다 세션 저장소를 조회하는 작업을 거쳐 트래픽이 증가하는 문제가 발생한다고 생각하였다. 따라서 헤더에 access token 을 전달하여 access token 의 유효성만 검증하면 되는 stateless 구조의 jwt 방식을 채택하였다.

7. 문제 해결 과정 (트러블 슈팅)

1. JWT 기반 인증에서 로그아웃 처리가 불가능한 문제

문제 상황

JWT 는 stateless 구조이기 때문에 서버에서 토큰 상태를 관리하지 않는다. 이로 인해 사용자가 로그아웃을 하더라도 이미 발급된 access token 을 즉시 무효화할 수 없는 상황에 마주했다.

원인 분석

JWT 는 토큰 자체의 payload 에 사용자 식별자, 권한, 만료 시간 등의 인증정보가 포함되어 있으며, 서버는 토큰의 유효성만 검증할 뿐 토큰을 폐기하는 개념이 없다. 따라서 클라이언트가 access token 을 보유하고 있고, 만료시점이 지나지 않은 한, 해당 access token 으로 계속 요청이 가능했다.

해결 과정

처음에는 access token 을 블랙리스트로 관리하는 방안도 고려하였다. 하지만 이렇게 설계하게 되면 매 요청마다 access token 이 블랙리스트에 포함되어있는지 조회하는 과정이 필요했다. 이는 곧 stateless 구조의 장점을 해치고, 추가적인 저장소 관리 비용이 발생한다고 판단하였다.

이에 따라 refresh token 을 db 에 저장하고, 로그아웃 또는 회원 탈퇴 시 해당 refresh token 을 삭제하여 토큰 재발급 경로 자체를 차단하는 방식을 선택하였다.

결과 및 배운 점

Refresht token 을 DB 에서 관리하는 구조를 도입함으로써, 로그아웃 시점에 사용자의 인증상태를 즉시 제어할 수 있게 되었다.

로그아웃은 단순히 클라이언트에서 토큰을 삭제하는 행위가 아니라, 서버가 해당 사용자의 인증을 더 이상 신뢰하지 않겠다는 명확한 의사 표현이라는 점을 이해하게 되었다.

JWT 를 사용한다고 해서 모든 것을 stateless 로 밀어붙이기보다는 로그아웃처럼 제어가 필요한 지점에서는 일부 상태를 받아들임으로써 기술적 한계 안에서 요구사항을 어떻게 충족시킬 것인가를 고민하는 경험을 할 수 있었다.

2. JWT 서명 키 자동 생성으로 인한 전체 로그아웃 문제

문제 상황

초기 구현단계에서는 라이브러리에서 제공하는 자동 키 생성 방식을 사용하였다. 그러나 개발 중 추가 기능 도입, 리팩토링 등의 이유로 서버를 재시작한 이후 기존에 발급된 모든 JWT 가 무효화되며 예고없이 로그아웃 되는 문제가 발생했다.

원인 분석

서버 실행 시마다 새로운 서명 키가 생성되었고, 결국 기존의 토큰 signature 를 검증할 수 없게 되었다. 결과적으로 서버 재시작 자체가 전체 로그아웃을 유발하였다.

해결 과정

서명 키를 서버 내부에서 매번 새로 생성하는 대신, openssl 명령어를 이용하여 랜덤한 키값을 발급받고, 이를 secret key 로 사용하였다. 해당 키를 .env 파일에 저장하여 환경 변수로 관리함으로써 서버 재시작 이후에도 동일한 키로 토큰을 검증할 수 있게 되었다.

결과 및 배운 점

이후 서버 재시작과 무관하게 기존 토큰이 정상적으로 유지되었고, 사용자 경험 측면에서도 불필요한 재로그인이 제거되었다.

서명 키 관리 방식을 개선함으로써, 작은 부분이지만 서비스의 안정성과 사용자 친화성을 함께 높일 수 있다는 점에서 뿌듯함을 느꼈다.

또한 Secret key 를 환경변수로 관리하는 경우 민감한 정보는 반드시 소스코드와 분리되어야 하며, .env 파일을 .gitignore 에 포함시켜야 한다는 점을 배웠다. 이는 단순한 습관이 아니라 보안을 위한 기본적인 책임이라는 점을 체감할 수 있었다.

8. 협업과 커뮤니케이션

Git 브랜치 전략

  • 기본 브랜치: main, develop
  • 기능 작업: feature/이슈번호-짧은설명

예시

  • feature/12-diet-record-api
  • feature/21-dashboard-ui

플로우

  1. develop에서 브랜치 생성
  2. feature/... 에서 작업 + 커밋
  3. 완료되면 develop으로 PR
  4. 일정 주기마다 develop → main 릴리즈

PR / 코드 리뷰 방식

PR 제목 형식

type(#이슈 번호): 한 줄 요약

type 예시

  • feat : 새 기능
  • fix : 버그 수정
  • refactor : 리팩토링
  • docs : 문서/README
  • chore : 설정, 빌드, 잡일

예시

feat(#8): 식단 기록 생성 API
fix(#12): 통계 화면 요일 선택 버그
refactor(#51): 식단 통계 계산 로직 분리

이슈 관리 방식

형식

Feature : 기능 이름
Bug : 버그 내용
Refactor : 리팩토링 내용
Docs : 문서/기획
Chore : 설정/배포/잡일

예시

  • Feature : 식단 기록 생성 API
  • Feature : 대시보드 오늘 요약 카드
  • Bug : 주간 통계 그래프 요일 클릭 안 됨
  • Refactor : 통계 계산 로직 서비스 분리
  • Chore : CI/CD 파이프라인 구성
  • Docs : ERD v1.1 수정

이슈 본문 템플릿 (팀 공통)

🌟 이슈 설명
- (왜 하는지, 무엇을 할 건지 한두 줄)
- 예) 식단 기록 화면에서 사용할 백엔드 API가 필요함.

📋 할 일 목록
- [ ] (할 작업 1)
- [ ] (할 작업 2)
- [ ] (할 작업 3)

✨ 참고 사항
- 관련 문서 / ERD / Figma / 레포 링크
- 주의할 점, 후속 이슈 등

협업하면서 배운 점

1. 잘 짠 코드보다, 잘 설명된 결정이 더 중요하다

JWT 서명 키 관리 방식을 자동 생성으로 결정하게 된 계기는 팀원의 제안이었다. 수업시간에 배운 방식을 실제 프로젝트에 적용해보자는 의견이었고, 당시에는 충분히 설득력 있다고 판단하여 해당 제안을 받아들였다.

이후 인증 부분을 개발하는 과정에서 서버 재시작 시 전체 사용자가 로그아웃되는 상황에 마주하였다. 해당 문제를 해결하기 위해 openssl 로 랜덤한 키 값을 생성해 환경변수로 저장한 후 사용하는 방식을 알게되었다. 기존 결정에 대해 다시 논의가 필요하다는 생각이 들어, 새로 알게된 방식을 팀원들에게 제안하였다.

이 때 단순히 방식을 바꾸자는 의견을 내기보다는, 기존 선택의 한계와 변경했을 때의 장점을 정리하여 팀원과 공유하였다. 또한 팀원이 처음 제안했던 선택을 부정하는 방법이 아니라, 프로젝트 맥락에서 더 적합한 대안을 함께 찾아보자는 방향으로 회의를 진행하였다.

그 결과 성공적으로 합의를 마칠 수 있었고, 이 경험을 통해 협업에서는 개인의 판단을 밀어붙이기보다 하나의 결정에 대한 근거를 공유하고 함께 결정하는 과정이 매우 중요하다는 것을 배웟다.

2. Auth 는 개인 작업이지만, 영향 범위는 팀 전체다

인증 로직은 특정 기능 하나에 국한된 작업이 아니라, 팀 전체의 개발 흐름과 밀접하게 연결되어 있다는 점을 체감했다.

첫 웹 프로젝트라 인증 영역을 구현하는 과정에서 많은 고민과 시행착오가 있었고, 그로 인해 Auth 의 개발이 다소 늦어졌다. 이 과정에서 인증이 선행되지 않으면 다른 팀원들의 기능 개발에도 영향을 미친다는 사실을 몸소 경험하게 되엇다.

이를 계기로, 내 작업이 팀 전체 일정에 어떤 영향을 미치는지를 먼저 고려한 후, 책임감을 가지는 것이 협업에서 매우 중요하다는 점을 느끼게 되었다. 또한 프로젝트 전체의 흐름을 고려하는 자세를 배울 수 있었다.

9. 아쉬웠던 점과 한계

이번 프로젝트에서 가장 아쉬웠던 부분은 시간적 제약으로 인해 인증 영역을 충분히 확장하지 못했다는 점이다.

먼저, OAuth 기반 소셜 로그인 기능을 구현하지 못하여 굉장히 아쉽다.
본인은 어떠한 웹이나 앱을 사용할 때 회원가입하기 귀찮아서 항상 소셜 로그인을 사용한다. 그래서 이 프로젝트에도 꼭 도입을 하고싶었으나, 프로젝트 일정과 우선순위를 고려하여 기본적인 JWT 기반 인증 구현에 집중하게 되었다.
그 결과 사용자 편의성을 높일 수 있는 소셜 로그인 기능을 실제로 적용해보지 못한 점이 아쉬움으로 남았다.

또한 Refresh Token 을 관리하는 과정에서, 디스크에 저장하는 DB 가 아닌 Redis 와 같이 초고속 조회가 가능한 인메모리 저장소를 활용해보고 싶었다. 하지만 Redis 에 대한 이해와 학습 시간이 충분하지 않아 적용하지 못하였다.
이로 인해 토큰 관리 구조를 보다 효율적으로 설계해볼 수 있는 기회를 놓친 점이 아쉽게 느껴졌다.

10. 개선하고 싶은 점 (리팩토링 & 확장 아이디어)

1. 인증 영역의 확장 및 구조 개선

OAuth 기반 로그인, Redis 를 사용한 Refresh Token 관리를 하지 못한 것에 대한 아쉬움이 남는 만큼, 이 둘을 개선하여 보다 편리하고 효율적인 인증 구조로 개선하고 싶다.

2. 회원 탈퇴 시 데이터 정합성 문제 개선

회원 탈퇴 시 해당 사용자의 데이터가 여러 테이블에 분산되어 있어 관련 데이터가 완전히 정리되지 않는 문제가 발생하였다. 이로 인해 탈퇴 처리 자체가 제대로 되지 않는 문제가 있었다.

이에 대한 개선 방안으로, 탈퇴한 사용자를 대체하는 더미 계정을 만든 후 커뮤니티 글, 댓글 등 삭제되지 않아야 하는 데이터는 해당 계정으로 소유자를 변경한 뒤 실제 사용자의 정보는 모두 삭제하는 방식을 생각해봤다.

하지만 이 방법이 데이터 정합성과 서비스 정책 측면에서 최선인지에 대한 확신이 아직 없어, 다른 방안들에 대해서도 조사하여 문제를 개선하고 싶다.

11. 마무리

최근 개발자로의 길을 선택한 것이 과연 맞는 선택이었을까 하는 의심이 내 마음 속에 조금 들었었다. 돌이켜보면 아직 잘하는 것도 많이 없다는 생각에 자신감을 살짝 잃어가고 있었던 것 같다.

하지만 이번 프로젝트를 통해 기술적으로 조금이나마 성장한 나 자신을 발견할 수 있었다. 덕분에 성장의 기쁨을 누릴 수 있었다.

완벽하지는 않았기에 프로젝트에 대한 아쉬움이 남아있지만, 그만큼 더욱 배우고 싶은 것들이 생겼고, 더 나은 서비스와 설계에 대해 고민할 수 있는 귀중한 시간이었다.

앞으로는 더욱 성장하여 더 좋은 서비스를 만들 수 있는, 더 나은 협업능력을 가진 개발자가 되고싶다.

0개의 댓글