[TIL] 확장성과 MVP 사이에서 고민한 ERD 설계
TodayPoor ERD 초안을 PRD와 비교하며 POOR_TITLE, 공개 범위, 카테고리, AI 결과 저장 구조를 MVP 범위에 맞게 조정한 기록입니다.
For the English version of this post, see here.
오늘 한 일
ERD 구상
BE 기획안 회의
ERD 확정
깃허브 오가니제이션 생성
BE 레포 생성
ERD 피드백 요청
기술 스택 결정
프로젝트 기초 세팅
- 폴더 구조
회의
AI를 통해 ERD 초안 작성
초안을 PRD 기획안의 서비스 기능과 비교
- POOR_TITLE 테이블이 필요한가
초기에는
RANKING_RESULT테이블에 바로 문자열 형태로 타이틀명을 저장하려고 함- 문제
문자열 중복 발생
타이틀 기준/확장 관리 어려움
코드와 DB 간 역할이 애매해짐
- 해결: 타이틀을 별도
POOR_TITLE테이블로 분리하고,RANKING_RESULT에서 title_id를 참조하도록 함
프라이버시 - 숨김 처리 어떻게 처리할지
숨김 처리를 어디서 어떻게 할지 고민
처음에는 단순히 프론트에서 “안 보이게” 처리하면 되는 것 아닌가 생각함
- 문제
API 응답에는 실제 데이터가 그대로 존재
개발자 도구나 네트워크 탭에서 확인 가능
실제 보안/프라이버시 처리가 아님
해결:
EXPENSE테이블에 공개 범위를 나타내는 enum 필드를 추가하기로 함visibility_type
1 2 3 4 5
PUBLIC AMOUNT_ONLY CATEGORY_ONLY HIDE_MERCHANT PRIVATE
category 테이블 필요한가 안 필요한가
처음에는 카테고리를 별도 테이블로 분리하려고 함
- 문제
카테고리 종류가 자주 바뀌지 않음
정해진 값만 사용
조회용 데이터 성격이 강함
해결: 결국 category는
EXPENSE테이블에서 enum으로 관리하기로 함category
1 2 3 4 5
CAFE DELIVERY SHOPPING FOOD ...
- 템플릿이 뭐지
AI 기능 설계 중 “템플릿”이라는 단어가 계속 등장함
처음에는 독설 문구 저장용? 랜덤 문장 모음? AI 프롬프트? 등 역할이 명확하지 않았음
해결
회의를 진행하면서 현재 서비스에서 필요한 것은 AI가 독설 스타일의 결과를 생성하는 기능이라는 점을 정리함
즉, 핵심은 “문장 템플릿 저장”보다
AI 입력 → 결과 생성 흐름자체
- AI 부분 테이블 어떻게 구상해야하지
- 처음에는 단순히 “AI를 사용한다” 정도로만 생각했지만, 실제 백엔드 구조를 설계하려다 보니 다음과 같은 고민이 생김
AI 프롬프트도 DB로 관리해야 할까?
AI 호출 결과는 어디까지 저장해야 할까?
- 초기에는 비교적 확장성을 고려해 다음과 같은 구조를 생각함
AI_PROMPT_TEMPLATE / AI_RESULT / AI_GENERATION_LOG
특히
AI_PROMPT_TEMPLATE테이블은 프롬프트 수정, 프롬프트 버전 관리, 여러 스타일 실험, 운영 중 문구 변경 등을 고려해 설계하려함
- 처음에는 단순히 “AI를 사용한다” 정도로만 생각했지만, 실제 백엔드 구조를 설계하려다 보니 다음과 같은 고민이 생김
- POOR_TITLE 테이블이 필요한가
프론트 와이어프레임이랑 비교하여 수정 필요
피드백 반영 필요
기술 스택 결정 및 프로젝트 기초 세팅
단순히 “유명한 기술”을 선택하는 것이 아니라, 현재 프로젝트 규모와 팀의 숙련도, MVP 범위를 기준으로 어떤 기술이 가장 적절한지 고민하는 과정이었음- OCR 방식 결정
서비스의 핵심 기능 중 하나는 소비 내역 이미지 업로드 후 OCR 분석을 통해 소비 데이터를 추출하는 기능
처음에는 GPT(OpenAI API)를 이용해 영수증 이미지를 GPT에게 전달하여 금액 / 가맹점 / 카테고리를 추출하는, 이미지 자체를 분석하는 방식도 고려함
- 문제
불필요한 토큰 사용량 증가: GPT 기반 이미지 분석은 일반 OCR보다 훨씬 많은 토큰을 사용함
역할 분리 애매: OCR의 목적은 정확한 텍스트 추출인 반면에 GPT는 추론과 생성에 더 강점이 있음
OCR → 텍스트 인식
GPT → 생성형 AI 역할
로 역할을 분리하는 것이 더 적절하다고 판단함
- 해결: 결국 OCR은 Google OCR API 같은 외부 OCR 서비스를 사용하는 방향으로 결정함
- 이미지 저장 방식과 S3 사용 여부
사용자가 소비 내역 이미지를 업로드하면 OCR 처리를 위해 이미지를 잠시 저장하거나 전달하는 과정이 필요함
하지만 우리 서비스에서는 OCR 분석이 끝난 뒤에는 원본 이미지 자체가 핵심 데이터로 남을 필요는 없다고 판단
서비스에서 실제로 필요한 데이터는 이미지가 아니라 OCR을 통해 추출된 소비 정보
해결: 이미지는 영구 저장하지 않고, OCR 처리 과정에서만 임시로 사용하기로 함
- DB에는 원본 이미지가 아니라 다음 데이터만 저장한다.
- OCR 결과 텍스트 / 사용자가 확정한 소비 금액 / 가맹점 / 카테고리 / 메모 / 소비 시간
이렇게 하면 불필요한 이미지 저장 공간을 줄일 수 있고, 개인정보가 포함될 수 있는 영수증 이미지를 오래 보관하지 않아도 됨
- 현재 MVP에서는 S3 같은 외부 이미지 저장소를 우선 도입하지 않기로 함
이미지는 OCR 처리 후 필요하지 않음
대용량 이미지 저장 요구가 없음
S3 연동으로 인한 인프라 복잡도 증가
개인정보가 포함될 수 있는 이미지 보관 부담 감소
즉, 이미지는 “저장해야 하는 데이터”가 아니라 “OCR 처리를 위한 입력값”으로만 사용하기로 함
- DB에는 원본 이미지가 아니라 다음 데이터만 저장한다.
- DB 및 백엔드 기술 선택
- Supabase도 고려했던 이유
빠른 MVP 개발 가능 / 프론트엔드와 연동 편리 / Flutter와 조합 사례가 많음 / 인증/DB 기능 제공과 같은 장점이 있음
- 문제
하지만 백엔드 팀원들은 Spring Boot + JPA 경험이 더 많았음
또한 이번 프로젝트는 단순히 서비스를 만드는 것뿐 아니라:
- 백엔드 구조 설계 / API 설계 / ERD 설계 / 서비스 계층 구조 / JPA 연관관계 등을 직접 구현하고 경험하는 것도 중요한 목표였음
즉, 빠른 개발보다 “백엔드 구조를 직접 설계하고 경험하는 것”이 더 중요하다고 판단
해결:
최종적으로는 다음 조합으로 확정- Backend: Spring Boot 3.x, Java 17, Gradle
- Spring Boot: 팀원들이 가장 익숙함 / 레이어드 아키텍처 적용 용이 / JPA 활용 가능 / 유지보수 구조 설계 경험 가능
- DB: MySQL, Spring Data JPA
- MySQL: Spring/JPA와 연동이 안정적 / 관계형 데이터 모델링에 적합 / ERD 기반 설계와 잘 맞음
- Backend: Spring Boot 3.x, Java 17, Gradle
- Supabase도 고려했던 이유
- OCR 방식 결정
배운 점
이번 회의를 통해 가장 크게 느낀 점은 좋은 설계가 반드시 복잡한 설계는 아니라는 점이었다.
처음에는 category를 별도 테이블로 분리, AI 프롬프트 테이블 추가, 메모 여부 boolean 관리 등 최대한 확장성을 고려한 방향으로 생각했지만, 논의를 진행하면서 MVP 단계에서는
“지금 실제로 필요한 기능인가?”를 기준으로 판단하는 것이 더 중요하다는 점을 느꼈다.또한 단순히 기능 구현만 생각하는 것이 아니라 데이터 중복 여부, 책임 분리, 프론트와 백엔드의 역할, 확장 가능성과 현재 복잡도의 균형까지 함께 고민해야 한다는 점을 배웠다.
특히 프라이버시 처리 부분에서
“숨기는 것”과 “실제로 접근을 제한하는 것”은 다르다는 점이 인상 깊었다. 단순 UI 처리가 아니라, 백엔드에서 데이터를 어떤 형태로 내려줄지까지 고려해야 한다는 점을 알게 되었다.AI 설계 부분에서도
AI를 사용한다고 해서 모든 것을 AI 전용 테이블로 관리할 필요는 없다는 점을 느꼈다. 기술적으로 가능한 구조보다, 현재 서비스 단계에 적절한 구조를 선택하는 것이 더 중요했다.이번 회의를 통해 단순히 “기능 구현”보다
왜 이런 구조를 선택했는가를 설명할 수 있는 설계가 중요하다는 점을 배울 수 있었다.
다음 할 일
ERD 피드백 반영 및 수정
API 명세 작성
프로젝트 공통 부분 설계
공통 응답
에러 처리
코드/커밋 컨벤션
