템플릿 둘러보기/넷플릭스 (Netflix)

넷플릭스 (Netflix)

콘텐츠 관리, 다중 프로필 지원, 구독 결제, 시청 기록, 평점, 추천 엔진 및 다운로드 기능을 포함하는 넷플릭스 스타일의 비디오 스트리밍 플랫폼을 위한 전체 데이터베이스 스키마입니다.

PostgreSQL15개 테이블웹 앱
streamingvideosubscriptioncontentrecommendation
ERD Studio로 제작

이 스키마에 대하여

이 스키마를 가르는 구분은 계정과 시청자입니다. users 는 결제하고 로그인하는 주체, profiles 는 보고 있는 사람입니다. 개인적인 것 — 시청 기록, 찜, 평가, 다운로드 — 이 전부 프로필에 붙고, 그래서 한 집의 추천이 다른 사람에게 새지 않습니다.

카탈로그는 둘이 아니라 타입을 가진 한 테이블입니다. content 가 영화와 시리즈를 함께 담고, seasons 와 episodes 는 타입이 요구할 때만 붙습니다. 영화는 시즌이 없는 content 행이고 시리즈는 있는 content 행입니다. 검색·평가·찜이 전부 content 위에서 돌고 어느 쪽인지 알 필요가 없습니다.

watch_history 가 content 와 episode 를 둘 다 가리키는데, 시리즈의 이어보기가 이것으로 됩니다. content_id 가 "무엇을 보는 중인가", episode_id 가 "어디까지 왔나", progress_seconds 가 "그 안에서 얼마나" 에 답합니다.

눈여겨볼 관계

users → profiles
계정이 결제하고 프로필이 봅니다. 요금제의 max_profiles 가 한도이고, is_kids 와 maturity_level 이 프로필마다 있어서 아이 계정이 따로 로그인하지 않고도 제한됩니다.
content → seasons → episodes
시리즈만 씁니다. 영화는 시즌 없이 러닝타임만 가진 content 행이고, 그래서 duration_minutes 가 content 와 episodes 양쪽에 있습니다.
profiles → watch_history
프로필×작품마다 한 행이고 progress_seconds 를 듭니다. 제자리에서 갱신되므로 이어보기가 로그를 훑는 것이 아니라 조회입니다.
content ↔ people (content_cast)
role 과 character_name 이 연결 테이블에 있습니다. 사람과 작품의 관계가 작품마다 달라지기 때문입니다 — 같은 사람이 한 편은 연출하고 다른 편에는 출연합니다.
profiles → downloads
expires_at 이 라이선스가 아니라 다운로드에 있습니다. 오프라인 사본은 스튜디오와의 계약으로 기한이 정해지고 스스로 사라져야 하기 때문입니다.

설계 판단

영화와 시리즈가 카탈로그 한 테이블을 쓴다

영화 테이블과 시리즈 테이블로 나누면 카탈로그 질의가 전부 두 배가 됩니다 — 검색·장르·찜·평가가 모두 union 이 됩니다. 타입 컬럼을 두고 시즌·에피소드를 시리즈만 쓰게 하면 카탈로그가 하나로 유지됩니다. 대가는 content 의 duration_minutes 가 시리즈에서는 의미가 없다는 것인데, nullable 컬럼 하나와 질의 표면의 중복을 맞바꾼 셈입니다.

개인 데이터는 계정이 아니라 프로필의 것

시청 기록과 평가가 users 에 있으면 한 집이 하나의 뒤섞인 취향과 하나의 이어보기 지점을 갖게 됩니다. profiles 에 두는 것이 프로필이 존재하는 이유 전부입니다. 결과적으로 프로필을 지우면 그 기록이 사라지는데, 사람들이 프로필을 지울 때 기대하는 것이 그것입니다.

출연 정보가 역할을 든다

배우 테이블과 감독 테이블을 따로 두지 않고 content_cast 가 role·character_name·billing_order 를 듭니다. 같은 사람이 작품마다 다른 자격으로 등장하므로, 자격은 크레딧의 속성입니다. billing_order 를 저장하는 이유는 작품 페이지의 순서가 가나다순이 아니라 편집 결정이기 때문입니다.

요금제 한도는 요금제에 있다

max_profiles·max_streams·video_quality 를 코드에 박지 않고 subscription_plans 에 둡니다. 등급이 포함하는 것을 바꾸는 일이 행 갱신이 되고, 옛 요금제 행을 가리키는 구독은 옮기기 전까지 옛 조건을 유지합니다.

이 템플릿의 테이블

users사용자 계정
9 cols
profiles프로필
9 cols
subscription_plans구독 요금제
8 cols
subscriptions구독 내역
10 cols
genres장르
5 cols
content콘텐츠
14 cols
content_genres콘텐츠 장르 연결
5 cols
seasons시즌
8 cols
episodes에피소드
10 cols
watch_history시청 기록
9 cols
watchlist시청 목록 (찜)
6 cols
ratings평가 (평점)
7 cols
people인물 (배우/감독)
8 cols
content_cast출연진 및 제작진
7 cols
downloads다운로드
9 cols

자주 묻는 것

프로필을 users 와 왜 따로 두나요?
한 집이 계정은 공유해도 취향은 공유하지 않기 때문입니다. 프로필이 있어야 결제 하나로 네 사람이 각자의 이어보기·찜·추천을 갖고, 아이 프로필이 두 번째 로그인 없이 자기 시청 등급을 갖습니다.
시리즈의 이어보기는 어떻게 되나요?
watch_history 에 content_id 와 episode_id 가 둘 다 있습니다. content 가 어느 시리즈인지, episode 가 어느 화인지, progress_seconds 가 그 안에서 어디까지인지를 말합니다. 이어보기는 그 작품의 가장 최근 행을 읽는 것입니다.
영화와 시리즈를 정말 한 테이블에 둬도 되나요?
공유하는 것이 거의 없지 않다면 그렇습니다. 여기서는 검색·장르·출연·평가·찜·아트워크 여섯 가지를 공유하고 에피소드 유무 하나가 다릅니다. 그 비율이 결정합니다.
"이것을 봤기 때문에" 추천은 어디서 오나요?
이 스키마에서 바로 나오지는 않습니다. watch_history·ratings·content_genres 가 입력이고, 추천 자체는 바깥에서 계산해 캐시합니다. 프로필의 전체 기록을 훑는 조인은 페이지를 여는 동안 돌릴 질의가 아닙니다.
downloads 에 expires_at 이 왜 있나요?
오프라인 권리는 라이선스로 기한이 정해져 있어서 내려받은 파일이 스스로 멈춰야 합니다. 만료를 여기 저장해 두면 클라이언트가 서버에 묻지 않고 지킬 수 있는데, 그것이 다운로드의 요점입니다.