기획자가 알아야 할 데이터베이스(DB) 기초: 테이블과 관계 이해하기
[기획자 가이드] 개발자와 말이 통하는 데이터베이스(DB) 기초: 테이블과 관계
서비스 기획을 하다 보면 이런 고민이 튀어나옵니다.
“유저 한 명이 여러 개의 배송지를 가질 수 있게 하려면 기획서를 어떻게 써야 하지?”
“쿠폰 정보는 회원 정보 안에 넣어야 할까, 따로 빼야 할까?”
정답은 화면(UI)에서만 나오지 않습니다. 대부분 데이터베이스(DB) 구조 쪽에 숨어 있어요.
기획자가 DB를 설계할 필요는 없습니다. 대신 테이블과 관계를 이해하면, 화면 설계(W/F)와 정책 정의가 동시에 단단해집니다. 말하자면, UI는 무대고 DB는 무대 뒤 소품 창고입니다. 창고가 엉키면 무대도 넘어집니다. 🎭
1) DB는 엑셀 파일과 비슷하다: 테이블(Table)의 이해
DB를 가장 쉽게 이해하는 방법은 “거대한 엑셀”이라고 생각하는 것입니다. 엑셀의 시트 하나가 DB에서는 테이블(Table)이 됩니다. (엑셀은 실수하면 되돌릴 수 있는데, DB는 되돌리기 전에 회의가 먼저 열릴 수 있습니다) 🙂
Column 세로줄. 이름, 이메일, 가입일 같은 “항목”
Row 가로줄. 유저 A, 유저 B 같은 “실제 데이터 한 줄”
PK Primary Key. 각 Row를 구분하는 고유 번호(예: user_id). 절대 중복 불가
기획자에게 PK가 중요한 순간
목록(리스트) → 상세(디테일) 흐름에서 서버는 보통 “어느 항목?”을 PK로 구분합니다.
기획서에 “상세 진입 시 필요한 ID”를 적어두면 개발 대화가 빨라집니다.
예: 상품 상세는 product_id, 주문 상세는 order_id
2) 기획자가 알아야 할 3가지 관계(Relationship)
실제 서비스 데이터는 테이블 하나로 끝나지 않습니다. 테이블들은 줄로 연결됩니다. 그 줄의 모양이 곧 관계(Relationship)입니다. 관계를 이해하면 “기능이 된다/안 된다”가 아니라 “어떤 화면이 필요하다/어떤 정책이 붙는다”로 바뀝니다.
① 1:1 관계 (One-to-One)
상황: 유저 한 명당 하나의 프로필 정보만 가질 때
예시: 유저 테이블 ↔ 상세 프로필 테이블
보안(민감정보 분리)이나 성능(자주 쓰는 필드/덜 쓰는 필드 분리) 때문에 정보를 쪼갤 때 사용합니다.
② 1:N 관계 (One-to-Many) - 가장 많이 쓰임
상황: 유저 한 명이 여러 개의 주문을 하거나 배송지를 여러 개 등록할 때
예시: 유저(1) ↔ 주문(N), 유저(1) ↔ 배송지(N), 유저(1) ↔ 쿠폰(N)
유저 1명은 N개를 가질 수 있다.
하지만 N 중 하나는 유저 1명에게만 속한다.
③ N:M 관계 (Many-to-Many)
상황: 학생 여러 명이 여러 개의 강의를 듣는 경우처럼 “양쪽 모두 여러 개”가 가능한 때
예시: 학생 ↔ 강의, 유저 ↔ 좋아요한 게시물, 주문 ↔ 상품(라인아이템)
이때는 중간에 “수강 신청”, “주문상품(라인아이템)” 같은 연결 테이블이 거의 항상 필요합니다. 관계 자체에 수량, 상태, 시간 같은 속성이 붙기 때문입니다.
+ FK(Foreign Key) 한 줄만 챙기기
FK(외래키)는 “다른 테이블의 PK를 참조하는 값”입니다. 예를 들어 배송지 테이블에 user_id가 있다면, “이 배송지는 누구 유저의 것인가?”를 연결해 줍니다.
3) 기획자가 DB 구조를 이해하면 얻는 이득
1) 데이터 유실 없는 화면 설계
1:N을 이해하면 “단일 값”으로 끝낼지 “목록 UI”가 필요한지 즉시 판단됩니다.
예: 쿠폰은 보통 쿠폰함(리스트), 배송지는 배송지 관리(리스트)로 갑니다.
2) 정책 정의가 논리적으로 변함
“주문 취소 시 쿠폰은?” 같은 질문은 연결(FK)을 알면 답이 깔끔해집니다.
데이터가 어디에 붙어 있는지 알면, 정책도 어디에 붙여야 하는지 보입니다.
3) 개발 소통 비용 감소
“유저 테이블에 마지막 로그인 일시 컬럼 추가”처럼 정확히 말할 수 있습니다.
개발자는 기획이 구조를 고려했다는 걸 바로 알아챕니다. (대화의 온도가 내려갑니다)
4) 일정이 현실적으로 잡힘
1:N이면 목록/정렬/대표값/삭제조건이 따라옵니다.
이걸 초기에 적으면 QA에서 구멍이 줄고, 일정이 덜 흔들립니다.
4) [템플릿] 배송지(1:N) 기능을 한 번에 정리하는 화면 명세 + 정책
“유저는 배송지를 여러 개 가질 수 있다” 한 줄로 끝내면, 구현 단계에서 질문 폭탄이 옵니다. 그래서 아래 템플릿은 목록/상세/등록/수정/삭제에 필요한 정책을 한 번에 묶어 둡니다. 기획서에 그대로 붙여 넣고 값만 채우면 됩니다.
전제(데이터 구조 상상)
User user_id(PK)
Address address_id(PK), user_id(FK), recipient_name, phone, zipcode, addr1, addr2, memo, is_default, created_at, updated_at
4-1) 화면 목록(IA) 템플릿
| 구분 | 화면 | 핵심 목적 |
|---|---|---|
| List | 배송지 목록 | 등록된 배송지 N개를 조회하고, 대표 배송지 표시 및 관리 진입(상세/수정/삭제/대표설정) |
| Create | 배송지 등록 | 새 배송지 생성(필수 입력 검증, 기본값 처리, 대표 설정 옵션) |
| Update | 배송지 수정 | 기존 배송지 정보 수정(대표 배송지 변경 정책 포함) |
| Delete | 배송지 삭제 | 삭제 가능 조건 체크 후 삭제, 대표 배송지 재지정 규칙 적용 |
4-2) 정책 템플릿(값만 채우면 됨)
- 최대 등록 개수: 유저 1명당 최대
[N]개까지 등록 가능 - 대표 배송지: 유저는 대표 배송지
1개를 가진다 - 대표 자동 지정: 첫 배송지 등록 시
[자동으로 대표 지정 / 사용자 선택] - 대표 변경: 목록에서 대표 변경
[가능/불가], 변경 시 즉시 저장[예/아니오] - 삭제 조건:
- 진행 중 주문이 해당 배송지를 참조하면 삭제
[불가/가능] - 대표 배송지 삭제 시:
[다음 배송지를 자동 대표로 / 삭제 불가 / 사용자가 새 대표 선택]
- 진행 중 주문이 해당 배송지를 참조하면 삭제
- 주문과의 연결: 주문 생성 시 주문은 배송지
address_id를 참조한다(주문 시점 스냅샷 여부:[예/아니오])
4-3) 화면별 상세 명세 템플릿
| 화면 | 필수 요소 | 정책/동작(기대 결과) |
|---|---|---|
| 배송지 목록 |
배송지 카드/행 대표 배지 CTA: 등록, 수정, 삭제, 대표설정 |
- 목록은 최신순 [예/아니오] 또는 대표 우선 정렬 [예/아니오]- 대표 배송지는 상단 고정 [예/아니오]- 삭제 클릭 시 확인 팝업 노출(문구 포함) - 최대 개수 도달 시 “등록” 버튼 [비활성/숨김] + 안내 문구
|
| 배송지 등록 |
수령인명 연락처 우편번호/주소 상세주소 배송메모(선택) 대표로 설정(옵션) |
- 필수 입력 미충족 시 저장 버튼 [비활성/에러 표시]- 연락처 포맷 검증(예: 숫자/하이픈 정책) [정의]- 저장 성공 시 목록으로 이동 + 신규 항목 강조 [예/아니오]- 첫 등록이면 대표 자동 지정 [예/아니오]
|
| 배송지 수정 |
등록과 동일 필드 대표 설정 변경(옵션) |
- 수정 저장 후 목록 복귀 + 변경사항 반영 - 대표 변경 시 기존 대표는 자동 해제 - 진행 중 주문 참조 여부와 무관하게 수정 가능 [예/아니오]
|
| 배송지 삭제 |
삭제 확인 팝업 삭제 불가 안내(필요 시) |
- 삭제 불가 조건이면 안내 팝업 + 대안(예: “다른 배송지로 주문 변경 후 삭제”) - 대표 배송지 삭제 시 처리 규칙 적용(자동 대표/선택/불가) - 삭제 성공 시 목록 갱신 + 토스트 메시지 |
4-4) 예외 케이스(현장 자주 등장)
- 주소 검색 실패: 외부 주소 검색이 실패하면 수동 입력 허용
[예/아니오] - 동시 클릭: 저장 버튼 연타 시 버튼 Disabled + 로딩 표시
- 데이터 경합: 다른 기기에서 대표 배송지가 바뀌었을 때 목록 진입 시 최신값으로 재조회
- 삭제 직후 주문: 삭제한 배송지를 주문에서 선택하려 할 때, “삭제된 배송지” 안내 후 목록 재선택 유도
기획서에 붙이는 한 문장(회의 단축 주문)
“배송지는 유저 기준 1:N이며, 대표 배송지 1개를 유지한다. 등록/수정/삭제/대표변경은 배송지 관리 화면에서 수행하며, 주문은 address_id를 참조한다(주문 스냅샷 정책: [작성]).”
5) 실무 적용: 쿠폰/주문까지 관계로 기획서 쓰는 법
배송지 템플릿을 이해했다면, 쿠폰과 주문도 같은 방식으로 정리할 수 있습니다. 포인트는 “몇 개가 가능한가(관계)”와 “그럼 어떤 화면과 정책이 따라오는가”입니다.
쿠폰(유저 1:N)
- 쿠폰함(목록) 필요
- 상태: 사용가능/사용완료/만료
- 정책: 주문 취소 시 상태 복구 여부
주문-상품(N:M)
- 중간 개념: 주문상품(라인아이템)
- 라인아이템 속성: 수량, 옵션, 결제 시점 가격
- 정책: 부분취소, 옵션 변경, 품절 처리
6) 결론: 화면 뒤의 흐름을 보세요
화면(UI)은 데이터(DB)를 보여주는 껍데기입니다. 껍데기를 만들기 전에 알맹이가 어떤 주머니(테이블)에 담겨 있고, 주머니끼리 어떤 줄(관계)로 이어져 있는지 떠올려 보세요. 그 순간 기획서는 “설명서”가 아니라 “구현 가능한 지도”가 됩니다. 🗺️
오늘의 결론 한 줄:
관계(1:1, 1:N, N:M)를 먼저 정리하면, 화면 IA와 정책이 자연스럽게 따라온다.
FAQ
Q쿠폰은 회원 정보 안에 넣는 게 좋나요, 따로 빼는 게 좋나요?
A 대부분은 “따로 빼는” 방식(1:N)이 자연스럽습니다. 유저 1명이 쿠폰 N장을 가질 수 있고, 쿠폰은 상태 변화가 많기 때문입니다. 유저는 기본정보에 집중하고, 쿠폰은 쿠폰 테이블에서 관리하면 확장에 유리합니다.
Q1:N 관계를 기획서에 어떻게 표현하면 개발자와 소통이 쉬워지나요?
A “여러 개 가능”이라고만 쓰지 말고, 목록 UI, 대표 규칙, 최대 개수, 삭제 조건, 그리고 어느 기능이 어떤 ID(PK/FK)를 참조하는지까지 같이 적으면 구현 기준이 선명해집니다.
QN:M 관계는 왜 중간 테이블이 필요한가요?
A 관계 자체에 수량, 상태, 시간 같은 속성이 붙기 때문입니다. “주문상품(라인아이템)”이 있어야 수량/옵션/가격을 안전하게 담고, 부분취소 같은 정책도 논리적으로 설계됩니다.
Q배송지에서 ‘주문 스냅샷’이란 게 왜 중요하죠?
A 주문 이후 유저가 배송지를 수정하거나 삭제할 수 있기 때문입니다. 주문 레코드가 배송지 정보를 “그대로 복사해 저장(스냅샷)”하면, 과거 주문의 배송 정보가 흔들리지 않습니다. 반대로 배송지 테이블만 참조하면, 수정 시 과거 주문 화면이 바뀌는 문제가 생길 수 있습니다.