ERD
프로젝트를 시작하기 앞서 ERD를 먼저 그려서 도메인 영역을 정의했다. 아래 항목들을 명심하며 그린다.
- 도메인 설계하기 → 한 눈에 보이도록 영역 분리하여 구분
- 컨벤션 지킬 것
- 테이블 레벨의 PK와 FK가 아닌, 연관 관계를 맺어준다. (JPA의 연관 관계 생각)
- 큼직하게 관계를 맺어주고 디테일 한 관계까지는 그리지 않는다.
- 그룹으로 묶어주는 것이 목적이다.
- 경계를 나누는 것!
💡 https://dbdiagram.io/
여러 툴이 있었는데, 그 중 dbdiagram이라는 사이트에서 ERD를 그릴 수 있었다. 이 사이트를 고른 이유는 다음과 같다.
- 코드로 작성할 수 있다.
- 다른 사용자에게 공유가 가능하다.
- MySQL, MS-SQL, SQL-Server 를 대상으로 export 할 수 있다.
Naming Conventions
💡 MySQL 스타일 가이드와 멘토님의 컨펌을 통해 정했습니다.
https://www.sqlstyle.guide/
공통
- 예약된 키워드를 피하여, 고유한 이름을 부여한다.
- 이름의 길이는 최대 30 바이트이다.
- 이름에는 문자, 숫자, 밑줄만 사용하라.
- 문자로 시작해야 하며, 밑줄로 끝날 수 없다.
- 여러 개의 연속된 밑줄은 사용하지 마라.
- 이름의 공백은 밑줄로 표시한다.
- 예를 들어, “사용자 정보”는 “사용자_정보”로 작성
- 약어는 피하되, 사용해야 한다면 일반적으로 이해할 수 있는지 확인하라.
- PK는 auto_increment를 사용한다. 이를 사용하는 것이 페이징, 무한 스크롤, 조회 등에 편리하다.
- 모든 테이블에는 생성일자(created_at)와 수정일자(updated_at)이 있어야 한다.
- 통계를 내거나 정보를 확인할 때 요긴하게 쓰인다.
다음은 SQL에서 보편적인 의미를 갖는 접미사들이다.
- _id: 기본 키와 같은 고유 식별자
- _key: PK 대신 외부에 유출할 키 값
- _seq: 연속된 값 시퀀스
- _status: 플래그 값 혹은 어떠한 타입의 상태
- _code: 회원 상태처럼 어떠한 것을 나타내는 코드 값
- _total: 값의 합계 또는 total
- _num: 모든 종류의 숫자가 포함되어 있음
- _name: 이름
- _date: 어떤 항목의 날짜가 포함된 열
- 나는 DateTime일 때 이 접미사를 사용했다.
- _at: Timestamp 타입의 날짜
- _tolly: 카운트
- _size: 파일이나 사물의 크기
- _addr: 기록의 주소, 물리적인 주소뿐만 아니라 논리적인 주소(IP 주소)를 말하기도 한다.
열(column)에 적용되는 접두사이다. 일반적으로 접두사는 잘 사용하지 않는다.
- {테이블명}_id: 식별자를 표시할 때는 테이블의 명을 앞에 붙인다.
- is_: true/false 값을 표현하는 tinyint(1)
Tables
- 집합적인 이름을 사용하거나 복수형으로 사용한다.
- tbl과 같은 접두사(prefix)는 사용하지 마라.
- 테이블의 열 중 하나와 동일한 이름은 지정하지 마라.
- 가능한 관계 테이블의 이름은 두 테이블의 이름을 연결하여 사용하지 마라.
- 이건 연관된 두 테이블을 서로 매핑 시켜주는 테이블일 경우, 두 테이블의 이름을 이어 붙이게 사용하기로 했다.
- ERD를 봤을 때 이 테이블이 무슨 테이블인지 알 수 있어야 하기 때문이다.
Columns
- 항상 단수형 이름을 사용하라.
- 기본 식별자로 단순히 “id”라고 적는 것은 피하라.
- 테이블과 이름이 같은 열을 추가하지 마라.
- 고유 명사와 같이 의미가 없는 경우를 제외하고는 항상 소문자를 사용하라.
- 다른 테이블에서 가져오는 값(FK로 설정하지 않더라도)은 원래의 열 이름을 그대로 사용한다.
전체 ERD
영역을 확실히 구분하기 위해 테이블 간의 거리를 떨어뜨렸다.
크게 5가지 영역으로 구분되고, 위의 세 영역이 핵심 영역(도메인)이다.

회원 영역

회원 정보 테이블
- 회원은 이메일과 비밀번호로 가입 및 로그인 가능하다.
- 외부 계정 연동을 할 경우, 이메일만 저장한다.
- 회원 상태는 정상, 정지, 휴면, 탈퇴 상태가 있다.
- auto_increments로 user_id를 만들었는데, 이 PK는 외부로 노출하지 않는다. 따라서 외부용 키(user_key)를 따로 저장한다.
- 외부용 키는 Base64나 Hash 등을 이용해서 생성한다. 정책은 개발하면서 고민해봐야겠다.
- 자세한 내용은 참고 사이트를 확인할 것.
회원 토큰 테이블
FCM 푸시를 이용해 사용자에게 일대일 문의(채팅)나 펀딩 상태에 따른 알림이 발송할 것이다.
푸시 발송에 필요한 핵심 정보는 다음 두 가지이다.
- 안드로이드인지 아이폰인지 구분하는 타입 값
- 디바이스의 토큰 정보 (APP에서 전달해줘야 한다)
문제는 이 토큰 값은 만료가 되었는지 체크해 따로 관리해줘야 한다.
실무에서 유효하지 않은 토큰은 주로 아래 두 경우가 있었다.
- 앱 삭제 시 유효하지 않은 토큰 값이 된다.
- 일정 기간(2개월 정도)이 지나면 토큰이 만료된다.
따라서, 주기적으로 확인 후 변경되는 테이블이기에 회원 정보 테이블에서 분리하여 토큰 테이블을 생성했다.
이 토큰 테이블은 추후 Redis를 연동하여 사용할 수 있다.
회원 배송지 테이블
- 각 회원은 배송지를 여러 군데 등록할 수 있다.
- 여러 배송지 중 하나를 대표로 설정할 수 있다.
- 우편번호와 주소를 입력한다.
- 받는 사람의 이름과 핸드폰 번호를 입력한다.
회원 결제수단 테이블
- 각 회원은 결제수단을 여러 군데 등록할 수 있다.
- 여러 결제 수단 중 하나를 대표로 설정할 수 있다.
- 카드인지 은행인지 구분하여, 카드 번호나 은행 번호를 입력한다.
펀딩 테이블

펀딩 테이블
- 각 항목은 주로 텀블벅을 참고하여 작성했다.
- 요금제, 펀딩 분류, 목표 금액, 시작일과 종료일은 필수 값이다.
- 펀딩 상태는 등록 → 심사 대기 → 심사 종료 → 오픈 예정 → 오픈 → 종료(성공/실패)가 있다.
- 심사 중이거나 심사가 끝난 후에 오픈 예정으로 돌입한다면, 대부분의 정보는 수정할 수 없다.
창작자 정보 테이블
텀블벅과 와디즈는 프로젝트 별로 정보를 기입할 수 있게 되어 있다. 오히려 그래서 정책을 알기 제일 까다로웠다.
- 각 프로젝트(펀딩)에 창작자 정보를 입력해야 한다. (1:1)
- 창작자 정보는 본인인증을 해야 하며, 사업자일 경우 사업자 번호를 등록한다.
- 원래는 제출해야할 서류나 다른 항목(입금 계좌 등)이 있지만, 고도화 영역으로 넘기고 간소하게 잡았다.
- 펀딩 글에 보이는 창작자 정보이다.
- 프로젝트의 창작자를 다른 사용자의 창작자 정보로 변경할 수 있다.
- 이건 따로 관리자 페이지를 만들어 관리해야 한다.
펀딩 태그 테이블
- 펀딩 글에는 검색에 용이하게 할 수 있도록 키워드를 입력할 수 있다.
- 키워드는 15자 이내여야 한다.
펀딩 아이템 테이블
- 펀딩에서 판매할 상품들의 정보가 담겨 있다.
- 각 상품의 이름과 옵션이 있는지 구분한다.
- 옵션 상태는 없음/주관식/객관식 총 3개이다.
예를 들어, 쥬얼리 펀딩 글이 있다고 하자. 그렇다면 펀딩 아이템은 각각 다음과 같이 있을 수 있다.
펀딩 아이템 옵션 테이블
위의 예시와 같을 때는, 다음과 같은 옵션이 있을 수 있다.
펀딩 리워드 테이블
- 실제 사용자가 후원할 수 있는 항목이다.
- 낱개로 등록된 아이템들을 조합하여 가격을 책정해 매긴다.
- 각 리워드는 개인 구매 가능 수량 혹은 전체 수량을 설정할 수 있다.
- 리워드는 온라인으로 전달될 수도 있고 실물로 배송될 수도 있다.
예를 들어 다음과 같은 리워드들이 있을 수 있다.
- 리워드 A
- 리워드 B
- 리워드 C
- 리워드 ALL 1
- 은 귀걸이 1개
- 금 귀걸이 1개
- 보석 귀걸이 1개
- 리워드 ALL 2
- 은 귀걸이 2개
- 금 귀걸이 2개
- 보석 귀걸이 2개
리워드-아이템 매핑 테이블
- 흐름 상 아이템을 먼저 등록한 후에 리워드를 등록해야 한다.
- 리워드는 여러 개의 아이템을 가지고 있을 수 있다.
따라서 매핑 테이블을 따로 만들었다.
후원 테이블

후원 (정보) 테이블
- 사용자는 여러 펀딩을 후원할 수 있다.
- 펀딩은 여러 후원 내역을 가질 수 있다.
- 누가, 어떤 펀딩에서, 어떤 리워드를 선택했는지 정보를 가진다.
- 후원번호를 사용자(창작자/후원자)에게 보여주기 위해, 외부에 보여줄 용도의 열을 만들었다.
- support_key: 총 7글자로, 숫자나 영문을 섞어 만들 생각이다.
- 후원 상태는 후원예약/후원성공/후원무산 총 3개가 있다.
후원 결제 테이블
- 후원이 성공하면 펀딩 종료 후 다음날에 자동 결제된다.
- 결제 실패하면 일정 일 뒤에 다시 시도한다.
- 이때, 결제 수단은 사용자가 선택하여 등록해야 한다.
- 여기서 선택한 결제 수단의 ‘회원 결제 수단 테이블’의 하나이다.
- 결제 상태는 결제대기/결제성공/결제실패 총 3개가 있다.
후원 배송 테이블
- 결제가 완료되면 지정된 일(펀딩 테이블의 발송일)
- 예상 전달일(각 리워드 별로 지정)에 배송이 시작된다.
- 배송은 창작자가 직접 업데이트 한다.
- 배송 업체를 끼고 할 수도 있다.
- 이건 좀 더 알아봐야 할 거 같다.
- 배송 상태는 전달예정/배송시작/배송종료 총 3개가 있다.
1:1 채팅 테이블

후원자가 창작자에게 일대일로 문의를 넣을 수 있다. 채팅 형식으로 되어 있으며, 이를 위해 간략하게 구상해봤다.
FCM 푸시를 연동하면서 변경될 수 있다.
기타
파일 테이블

펀딩을 등록할 때 썸네일 이미지나, 본문에 이미지 혹은 영상 등을 넣을 수 있다. 이러한 파일 정보를 저장하기 위한 테이블이다.
- 각 파일은 서버에 저장하고, 파일 정보를 테이블에 저장한다.
- 파일 이름은 저장될 때 UUID로 변환하여 저장한다.
- 파일의 원래 이름, 파일의 변환된 이름, 파일 경로는 필수로 존재해야 한다.
- 파일은 그룹으로 크게 묶이고, 그룹 안에서 식별자를 주어 구분한다.
- 그룹: 사용자 프로필 사진/펀딩 썸네일 이미지/펀딩 본문 이미지 등
- 식별자: 사용자 회원번호/펀딩 번호/펀딩 번호
로그 테이블
원래는 증적 자료를 위해 로그를 쌓아야 한다. 통계에 사용하기도 하고, 배송 상태나 접속 로그 등 이곳 저곳에 사용된다.
그러나 처음부터 설계를 디테일하게 잡는 것보다는 핵심 기능(도메인)에 집중해서 개발하고 이후에 차례차례 덧붙여 나가는 게 좋을 거 같아서 지금은 제외했다.
Reference
SQL style guide by Simon Holywell
Table column(attribute) 네이밍
MySQL 데이터베이스명, 테이블명, 컬럼명은 어떻게 지어야 할까?
MySQL Naming Convention (번역)