CK Blog

개발 및 설계 이야기를 공유합니다.

프로젝트를 빌드하면서 배운 경험, 트러블슈팅, 아키텍처 고민 등을 아카이빙합니다.

PostgreSQL 기반 CMS에서 블로그와 정책 콘텐츠를 하나의 구조로 운영한 이유

개발2026-08-287회 조회by CK Apps
블로그와 앱 정책 문서를 별도 테이블로 나누는 대신 contents, content_categories, content_versions 구조로 통합한 이유와 실제 운영 과정에서 얻은 설계 경험을 정리합니다.

콘텐츠가 몇 개 되지 않을 때는 글 하나를 별도 테이블에 저장해도 큰 문제가 없습니다. 하지만 블로그 글, 앱 정책 문서, 공지와 안내 페이지가 함께 늘어나기 시작하면 제목·본문·공개 상태·언어·작성일처럼 공통으로 필요한 필드가 여러 곳에 반복됩니다.

CK Apps Factory에서는 이 문제를 해결하기 위해 콘텐츠의 공통 속성은 하나의 CMS 구조로 모으고, 실제 화면에서 어떤 종류의 문서인지 구분하는 정보만 별도로 관리하는 방식을 선택했습니다. 이 글에서는 그 구조를 선택한 이유와 화면에 안정적으로 보여 주기 위해 함께 고려한 내용을 정리합니다.

1. 별도 테이블을 계속 늘릴 때 생기는 문제

블로그와 정책 문서를 각각 다른 테이블에 저장하면 처음에는 이해하기 쉽습니다. 그러나 시간이 지나면 게시 상태를 처리하는 방식, slug 중복을 검사하는 방식, 버전을 저장하는 방식이 테이블마다 달라지기 쉽습니다.

특히 운영 화면에서 콘텐츠를 한꺼번에 검색하거나, 작성 중인 문서를 미리 보고, 수정 이력을 남기려면 각각의 테이블에 비슷한 기능을 반복해서 구현해야 합니다. 기능이 늘어날수록 데이터 구조보다 예외 처리가 더 복잡해지는 순간이 옵니다.

2. 세 가지 테이블로 역할을 나누기

현재 구조에서는 콘텐츠 본문과 메타데이터를 contents에 저장하고, 분류 체계는 content_categories, 수정 이력은 content_versions가 담당합니다.

- contents: 제목, slug, 요약, 본문, 공개 상태, 언어, 대표 이미지와 SEO 정보를 보관합니다.

- content_categories: blog, policy 같은 콘텐츠 유형별 카테고리 이름과 정렬 순서를 관리합니다.

- content_versions: 저장 시점의 제목과 본문을 버전 번호와 함께 기록해 이전 내용을 확인할 수 있게 합니다.

이렇게 나누면 블로그 글은 content_typeblog로 저장하고, category_id개발이나 설계 같은 분류를 연결할 수 있습니다. 정책 문서는 같은 콘텐츠 테이블을 사용하면서도 앱과 언어를 별도로 연결할 수 있습니다.

3. 저장된 콘텐츠가 블로그 화면에 나타나는 흐름

블로그 목록은 공개 상태인 blog 콘텐츠를 조회한 뒤 카테고리 테이블을 조인합니다. 화면에서 사용하는 분류명은 본문에 직접 적어 두는 값이 아니라 카테고리의 이름으로 가져오기 때문에, 카테고리명을 관리 화면에서 바꾸더라도 콘텐츠와의 관계는 유지됩니다.


SELECT p.title, c.name AS category
FROM contents AS p
LEFT JOIN content_categories AS c
  ON c.id = p.category_id
WHERE p.content_type = 'blog'
  AND p.status = 'Published'
ORDER BY p.published_at DESC;

본문은 저장 전에 정규화하고, 화면에 출력할 때 허용된 HTML과 Markdown만 렌더링합니다. 이 경계를 두면 편집기에서 사용하는 임시 DOM이 데이터베이스에 섞이지 않고, 본문 안에 의도하지 않은 요소가 들어오는 문제도 줄일 수 있습니다.

4. 읽기 좋은 화면을 만들기 위한 본문 규칙

데이터 구조만 정리해도 글이 자동으로 읽기 좋아지는 것은 아닙니다. 현재 블로그 화면은 제목과 요약을 본문 바깥에서 보여 주고, 본문은 카드 안에서 일정한 폭으로 읽도록 구성되어 있습니다.

그래서 본문을 작성할 때는 다음 원칙을 지키는 것이 효과적입니다.

- 본문 첫 줄에 제목을 다시 넣지 않고 짧은 도입 문장으로 시작합니다.

- 한 문단에 너무 많은 내용을 넣지 않고, 주제가 바뀔 때 소제목을 사용합니다.

- 긴 설명은 목록으로 나누고, 코드는 필요한 부분만 작은 예제로 보여 줍니다.

- 요약문은 목록 카드에서도 잘리지 않도록 한두 문장으로 정리합니다.

- 외부 자료를 참고했다면 원문을 복사하지 않고, 실제 적용 과정과 판단을 함께 설명합니다.

이 규칙은 검색엔진을 위한 형식이라기보다, 방문자가 글의 내용을 빠르게 파악하고 끝까지 읽을 수 있도록 하기 위한 편집 기준입니다.

5. 실제 운영에서 배운 점

통합 CMS의 가장 큰 장점은 새로운 문서 유형을 추가할 때 공통 저장·미리보기·버전 처리 로직을 다시 만들 필요가 없다는 점입니다. 반대로 모든 콘텐츠를 하나의 테이블에 넣는 만큼 content_type, 언어, 앱 연결 관계를 저장할 때 정확하게 검증해야 합니다.

또한 AI나 자동화 도구를 활용하더라도 생성된 글을 그대로 공개하는 방식은 적합하지 않습니다. 실제 구현 화면, 선택한 이유, 실패했던 접근, 독자가 따라 할 수 있는 예제를 추가해야 글이 단순한 요약문이 아니라 경험 기반의 자료가 됩니다.

마무리

콘텐츠 테이블을 통합하는 목적은 테이블 수를 줄이는 데 있지 않습니다. 저장 규칙과 공개 규칙을 일관되게 만들고, 운영자가 콘텐츠에 집중할 수 있는 구조를 만드는 데 있습니다.

앞으로도 CK Apps Factory의 블로그에는 실제 앱과 CMS를 만들면서 확인한 설계 선택, 시행착오, 운영 방법을 중심으로 기록해 보려고 합니다.

참고 자료

- PostgreSQL 공식 문서

- Next.js 공식 문서