템플릿 둘러보기/블로그 / CMS 플랫폼

블로그 / CMS 플랫폼

워드프레스와 같은 플랫폼을 위해 설계된 블로그 및 콘텐츠 관리 시스템 데이터베이스입니다. 역할 기반 액세스를 제공하는 다중 작성자 지원, 계층적 카테고리, 다대다 태그 관계, 중첩된 댓글(대댓글) 및 콘텐츠 버전 관리 기능을 포함합니다. 맞춤형 CMS 솔루션, 블로깅 플랫폼 또는 지식 베이스 구축에 적합합니다.

PostgreSQL10개 테이블웹 앱
blogcmscontentwordpresspublishing
ERD Studio로 제작

이 스키마에 대하여

편집이 취미가 아니라 일이 되면 콘텐츠 시스템은 이 모양으로 자리 잡습니다. posts 는 지금의 글을, post_revisions 는 그 전의 모든 판본을 담고, 둘이 나뉘어 있어서 블로그를 읽는 동안에는 히스토리를 건드리지 않습니다.

댓글은 계정이 없는 사람이 씁니다. author_name 과 author_email 이 users 를 가리키지 않고 댓글 행에 그대로 있고, is_approved 가 공개를 막습니다. 이것이 회원제 사이트가 아니라 공개 블로그인 지점입니다 — 익명 댓글이 급조된 사용자 레코드가 아니라 그 자체로 온전한 행입니다.

나머지는 대체로 흔한 살림살이인데, 하나는 눈여겨볼 만합니다. settings 가 updated_by 를 가진 키-값 테이블입니다. 사이트 설정이 파일이 아니라 데이터베이스에 있어서 편집자가 바꿀 수 있고, 누가 바꿨는지를 컬럼이 기록합니다.

눈여겨볼 관계

posts → post_revisions
글은 현재, 리비전은 역사이고 revision_number 가 순서를 줍니다. editor_id 가 리비전에 있는 이유는 마지막으로 고친 사람이 대개 글쓴이가 아니기 때문입니다.
categories → categories
parent_id 로 트리가 됩니다. 글은 분류를 정확히 하나 갖는데, 그 점이 여기서 분류와 태그를 가릅니다.
posts ↔ tags (post_tags)
다대다이고, 이 연결 테이블에는 자기 id 가 없습니다 — 쌍이 곧 키입니다. 글은 분류 하나와 태그 여럿을 갖습니다.
comments → comments
parent_id 로 답글이 중첩됩니다. is_approved 가 댓글마다 있어서, 부모는 공개된 채 답글만 보류할 수 있습니다.
media → users
업로드는 올린 사람의 것이지 글에 매이지 않습니다. 같은 이미지를 여러 글에서 쓸 수 있고, 글을 지워도 사진이 따라 지워지지 않습니다.

설계 판단

리비전은 차이가 아니라 행 전체

post_revisions 는 매번 제목과 본문을 통째로 저장합니다. 저장 공간을 쓰는 대신 중요한 것을 얻습니다 — 어느 판본이든 질의 한 번으로 읽고 되돌릴 수 있고, 되감기가 없습니다. 글 정도 크기에서는 거의 언제나 맞는 거래입니다. 차이 사슬은 문서가 아주 크거나 리비전이 아주 많을 때 값어치가 있는데, 블로그는 둘 다 아닙니다.

댓글 작성자는 계정이 아니라 필드

댓글마다 사용자 행을 요구하면 아무도 원하지 않은 계정이 생기고, 스팸을 지우는 일이 회원 탈퇴가 됩니다. 이름과 이메일을 댓글에 두면 신원이 쓰이는 자리에 그대로 있고, 계정이 아예 없어도 검수가 됩니다.

분류는 하나, 태그는 여럿

category_id 는 글의 컬럼이고 태그는 연결 테이블을 거칩니다. 일부러 비대칭으로 뒀습니다. 분류는 글이 사는 곳이라 URL 과 내비게이션을 정하고, 태그는 붙이는 이름표라 여럿일 수 있습니다. 둘 다 다대다로 만들면 "모든 글은 집이 하나" 라는 보장이 사라집니다.

status 와 published_at 을 따로 둔다

status 는 초안·예약·공개를, published_at 은 시각을 말합니다. 둘 다 있으면 예약이 그냥 미래 시각이 되고, 내렸다가 다시 올린 글도 원래 날짜를 지킵니다. 상태 컬럼 하나만 두면 예약이 생기는 순간 어차피 두 번째 컬럼이 필요해집니다.

이 템플릿의 테이블

users작성자
9 cols
categories카테고리
6 cols
posts포스트
10 cols
post_revisions포스트 버전
7 cols
tags태그
3 cols
post_tags포스트-태그 연결
2 cols
comments댓글
8 cols
media미디어
8 cols
settings설정
5 cols
subscribers구독자
6 cols

자주 묻는 것

리비전에 왜 차이가 아니라 본문 전체를 담나요?
판본을 되돌리는 일이 되감기가 아니라 읽기여야 하기 때문입니다. 글은 저장 공간이 문제 될 만큼 크지 않고, 차이 사슬은 중간 하나가 깨지면 그 뒤가 전부 무너집니다.
댓글이 users 를 가리키게 해야 하나요?
댓글에 로그인이 필요하다면 그렇게 하세요. author_name·author_email 대신 user_id 를 두면 됩니다. 필요 없다면 필드로 두는 편이 한 번 쓰고 마는 사람을 위해 사용자 행을 만들어 내지 않습니다 — 로그인한 독자용으로 nullable user_id 를 더해 둘 다 가질 수도 있습니다.
post_tags 에 왜 id 컬럼이 없나요?
(post_id, tag_id) 쌍이 키이고, 이 관계에 대해 더 할 말이 없기 때문입니다. 대리 id 를 두면 어차피 유니크 제약을 걸지 않는 한 같은 태그가 한 글에 두 번 붙을 수 있습니다.
예약 발행은 어떻게 되나요?
status 를 예약으로 두고 published_at 을 미래로 둡니다. 시각이 되면 상태를 바꿔 줄 무언가가 필요하거나, 읽기 질의가 "published_at 이 과거" 를 조건으로 삼아야 합니다. 뒤쪽이 단순하고 작업이 필요 없습니다.
키-값 설정 테이블이 괜찮은 방법인가요?
사이트 옵션 몇 개라면 괜찮습니다 — 배포 없이 편집자가 바꿀 수 있습니다. 값에 타입이나 검증이나 관계가 필요해지는 순간 좋은 방법이 아니게 됩니다. 그때부터는 읽는 쪽마다 문자열을 파싱하고 서로 해석이 달라집니다.