포스트

[TIL] 확장성과 MVP 사이에서 고민한 ERD 설계

TodayPoor ERD 초안을 PRD와 비교하며 POOR_TITLE, 공개 범위, 카테고리, AI 결과 저장 구조를 MVP 범위에 맞게 조정한 기록입니다.

For the English version of this post, see here.
[TIL] 확장성과 MVP 사이에서 고민한 ERD 설계

오늘 한 일

  • 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 테이블은 프롬프트 수정, 프롬프트 버전 관리, 여러 스타일 실험, 운영 중 문구 변경 등을 고려해 설계하려함

  • 최종 ERD 초안 image

  • 프론트 와이어프레임이랑 비교하여 수정 필요

  • 피드백 반영 필요

  • 기술 스택 결정 및 프로젝트 기초 세팅
    단순히 “유명한 기술”을 선택하는 것이 아니라, 현재 프로젝트 규모와 팀의 숙련도, 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 및 백엔드 기술 선택
      • 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 기반 설계와 잘 맞음

배운 점

  • 이번 회의를 통해 가장 크게 느낀 점은 좋은 설계가 반드시 복잡한 설계는 아니라는 점이었다.

  • 처음에는 category를 별도 테이블로 분리, AI 프롬프트 테이블 추가, 메모 여부 boolean 관리 등 최대한 확장성을 고려한 방향으로 생각했지만, 논의를 진행하면서 MVP 단계에서는 “지금 실제로 필요한 기능인가?”를 기준으로 판단하는 것이 더 중요하다는 점을 느꼈다.

  • 또한 단순히 기능 구현만 생각하는 것이 아니라 데이터 중복 여부, 책임 분리, 프론트와 백엔드의 역할, 확장 가능성과 현재 복잡도의 균형까지 함께 고민해야 한다는 점을 배웠다.

  • 특히 프라이버시 처리 부분에서 “숨기는 것”과 “실제로 접근을 제한하는 것”은 다르다는 점이 인상 깊었다. 단순 UI 처리가 아니라, 백엔드에서 데이터를 어떤 형태로 내려줄지까지 고려해야 한다는 점을 알게 되었다.

  • AI 설계 부분에서도 AI를 사용한다고 해서 모든 것을 AI 전용 테이블로 관리할 필요는 없다는 점을 느꼈다. 기술적으로 가능한 구조보다, 현재 서비스 단계에 적절한 구조를 선택하는 것이 더 중요했다.

  • 이번 회의를 통해 단순히 “기능 구현”보다 왜 이런 구조를 선택했는가를 설명할 수 있는 설계가 중요하다는 점을 배울 수 있었다.

다음 할 일

  • ERD 피드백 반영 및 수정

  • API 명세 작성

  • 프로젝트 공통 부분 설계

    • 공통 응답

    • 에러 처리

    • 코드/커밋 컨벤션