
노션 CMS의 DB는 어떻게 생겼나
블로그·프로젝트 통합 DB, 홈 프로필용
profile-cms, 잔디 기록용 tracking-jandi.처음부터 세 개를 만든 건 아니었다.
블로그 포스팅을 담을 DB 하나에서 시작했고, 홈을 꾸미다 보니 유동적으로 업데이트 할 수 있는 데이터로 관리하고 싶은 니즈가 생겼다. 자기소개, 기술 스택, 요즘 읽는 책. 한 페이지의 카드 하나 하나는 구성 항목이 다르지만, 구조화하여 cms DB를 추가했다.
잔디는 또 별개다. 기록 / 개발 / 독서 / 운동 날짜와 타입만 있으면 되는 로그성 데이터라 별도의 테이블이 필요하다고 판단했다.
블로그·프로젝트 통합 DB는
page 프로퍼티 하나로 구분한다. blog냐 projects냐. 별도 DB를 만들어야 하나 고민도 했는데, 관리 포인트를 줄이는 게 낫다고 판단했다. 프로퍼티도 겹치는 게 많았고.필수 프로퍼티는 다섯 가지.
page, title, category, path, published_at. 이 중에서 path가 URL 식별자 역할을 한다. Notion 페이지 ID나 한글 제목을 URL에 쓰지 않으려고 직접 슬러그를 관리하는 방식을 택했다. path가 비어있거나 중복이면 노출하지 않는다. 미완성 글도 DB에는 넣어두되, 서비스 화면에는 안 잡히게 하는 간단한 정책이다.tags는 Multi-select로 달아뒀는데, 지금은 상세 페이지 메타 정보 표시 용도로만 쓴다. 태그 기반 필터링은 v2로 미뤘다. 지금 당장 필요한 기능이 아닌데, DB 구조에서는 열어두는 것만으로 충분했다.tracking-jandi (활동 기록 테이블)
프로퍼티 | 타입 | 정책 |
title | Title | 미사용, 데이터 생성용 |
type | Select | 활동 성격 구분 (읽기, 개발, 기록, 수영 등 동적 확장 가능) |
created_at | Date | 활동이 기록되거나 수행된 날짜 |
profile-cms (프로필 콘텐츠 관리 테이블)
프로퍼티 | 타입 | 정책 |
title | Title | 항목의 대제목 (예: Overview) |
category | Select | 콘텐츠의 분류 (intro, skills, book, now 4종 고정) |
content | Text | 핵심 문구 또는 요약된 내용 |
description | Text | 상세 설명 및 구체적인 본문 내용 |
start_date | Date | 해당 이력/활동의 시작일 |
end_date | Date | 해당 이력/활동의 종료일 |
img | Files & Media | 관련 이미지 또는 썸네일 파일 링크 (book, now 위젯만 대응) |
joyfive-blog (블로그/프로젝트 콘텐츠 관리 테이블)
블로그/프로젝트 단일 DB 사용. 블로그·프로젝트는 page (Select) 값으로 구분한다.
프로퍼티 | 타입 | 필수여부 | 정책 |
page | Select | 필수 | 블로그·프로젝트 구분 (blog, projects / 상세는 project) |
title | Title | 필수 | 콘텐츠 제목 |
category | Select | 필수 | 블로그용 단일 선택·필수. 프로젝트는 사용 방식만 상이 |
path | Text URL | 필수 | 블로그·프로젝트 상세 식별자 |
published_at | Date | 필수 | 정렬 기준 |
tags | Multi-select | 선택 | 페이지 내 렌더링 / 추후 검색 확장 |
잔디로 더 작은 기록 습관화하기
이전 포스팅에서 잠깐 소개한 바가 있지만, 한번 더 소개하자면 깃허브의 잔디 위젯을 모티브로 루틴 업무를 기록하고자 했다.
노션 DB에서 날짜와 타입을 읽어서 하루를 타입을 통합한 블럭으로 표현한 위젯 형태로 기획했지만, 막상 기록을 시작하니 노션 앱에 진입하여 직접 row를 추가하는건 생각보다 귀찮아서 어드민 페이지까지 만들었다. 귀찮은건 생략하고, 조금 더 쉽게 남길 수 있는 방안을 고민했다.
잔디 DB(
tracking-jandi)는 단순하게 유지했다. type, created_at, 그리고 Notion이 요구하는 title 세 개. type은 Select라 옵션을 동적으로 추가할 수 있고, 어드민 페이지에서 DB를 직접 읽어서 버튼으로 뿌린다. 타입을 하나 추가하면 버튼도, 위젯의 UI 블럭도 자동으로 늘어나는 구조로 최소 1개에서 9개의 타입을 관리할 수 있도록 개발했다. 기록, 개발, 읽기, 운동. 지금은 네 가지인데 앞으로 뭔가 더 꾸준하게 하고싶은 일이 생길지도 모르니까.
잔디 위젯을 추가한건 꽤나 성공적인 솔루션이었다. 아주 작은 기록이지만 문서를 작성하는것보다 작게라도 기록하는 날이 늘어났다.
의외로 얼타게 됐던 포인트
GA4, GTM 연결
순서가 꼬였다.
GA4 먼저 세팅하고 코드를 직접 삽입했다가, GTM에 GA4를 연결하는 게 맞다는 걸 알고 다시 GTM 코드로 교체했다. 별거 아닌 것 같지만 "어, 그럼 GA4 코드는 빼야 하나? GTM이 GA4를 대신하는 건가?" 하고 잠깐 멍해지는 순간이 있었다. GTM 컨테이너 안에 GA4 태그를 넣고, 페이지엔 GTM 스크립트만 남기는 구조. 개인 프로젝트니까 일단 GA4 직접 박고 나중에 GTM 붙이려 했는데, 순서가 틀렸다.
그리고 바이브 코딩의 고질적인 문제가 여기서도 터졌다. "GTM 연결해줘" 하고 푸시하고 배포 기다렸는데 데이터가 안 잡혔다. 코드가 제대로 들어갔는지 직접 확인하지 않고 바로 배포하고, 다시 "왜 안 되지?" 하고 코드를 열어보면서 뒤늦게 확인하는 루프. 개인 작업이라고 대충 넘어가려고 했다가 바로 업보를 마주했다. 중간 검수를 건너뛰면 꼭 이런 식으로 돌아온다.
OG 태그를 만들거라니까요?
기본 OG는 어렵지 않았다. 정적 페이지에 공통 이미지 하나 박아두는 건 금방 끝났다.
문제는 동적 OG였다. 게시글마다 본문 첫 번째 이미지를 OG 이미지로 쓰는 구조였는데, Next.js에서 Notion 이미지를 제대로 못 받아오는 이슈가 계속 생겼다. Notion S3 이미지 URL은 만료 시간이 있어서 그냥 가져다 쓰면 깨지고,
next/image로 처리하려면 도메인 설정도 따로 잡아줘야 하고. 클로드를 다그치면서 코드를 여러 차례 수정했다. "이거 왜 또 안 돼?" 를 몇 번 반복하고 나서야 제대로 잡혔다.결국 이미지 추출 로직, 도메인 허용 설정, fallback 처리까지 세트로 손봐야 했다. 기능 하나인데 연결된 게 생각보다 많았다.
Google / Naver 사이트 등록하기
사이트맵은 이미
sitemap.ts에서 Notion DB를 동적으로 읽어 자동 생성하도록 구현해뒀다. 정적 페이지부터 블로그 전체 포스팅, 프로젝트까지 path가 있는 것들은 전부 포함된다.근데 여기서 한 가지 놓친 게 있었다. 새 포스팅을 Notion에 올려도 사이트맵에 자동 반영이 안 됐다. 알고 보니
sitemap.ts에 별도 revalidate 설정이 없어서 배포 시 정적으로 굳어버리는 구조였다. 재배포 없이 반영되게 하려면 export const revalidate = 86400 한 줄이 필요했다. 24시간 주기로 Notion을 새로 읽어서 사이트맵을 갱신하는 방식.Google Search Console 등록은 별 탈 없이 넘어갔다. 진짜 문제는 그 다음이었다.
웹 Claude Code 환경에서
git push가 계속 403으로 막혔다. 알고 보니 Claude Code가 자동으로 잡아둔 git 계정이 noreply@anthropic.com. 내 계정이 아니니 권한이 없는 게 당연했다. GitHub PAT 토큰을 발급해서 인증하고 나서야 push가 됐다.Naver Search Advisor도 마찬가지였다. 인증 메타태그를
<head>에 넣어야 하는데, 이것도 Claude Code한테 "이거 추가해줘" 한 마디로 처리하고 다시 push. 보안 인증 태그 하나 붙이는 데 git 권한 삽질을 한 번 더 했다.게다가 Google, Naver 모두 로봇이 사이트를 읽어들이는데 시간이 필요하기 때문에, 초기에 제대로 설정이 되었는지, 잘 읽어들이고 있는지 점검하는데 기다리는 시간이 가장 길었다.
운영 세팅 업무에서는 늘 승인을 기다리는 시간이 가장 길다.
그래도 이제 제법 블로그 같죠?
기록을 못 하는 건 의지가 아니라 시스템 문제라고 했다. 스스로의 선언을 믿고, 기록할 수 있는 환경을 만드는데 집중을 했다. 만들고 나니 제법 그럴싸하다.
쉽게 기록할 수 있는 플랫폼. 더 작은 단위로 남길 수 있는 잔디. 요즘 읽는 책, 요즘 하는 것들을 올려두는 프로필 위젯. 사이드 프로젝트 페이지, 잡다한 로그부터 아티클까지 구겨 넣을 수 있는 블로그. 그리고 마스킹 테이프와 손으로 찢은 듯한 테두리, 나만의 디자인.
이제야 내 공간이 생긴 것만 같다.
안녕하세요? 오래 기다리셨죠? 드디어 나온 기쁨의 블로그, “오늘의 기쁨”입니다. ✌️
여전히 풀지 못한 숙제들도 있다. 블로그를 만들었더니 정말 매일 기록하는 습관까지 만들어졌냐고 하면, 아직이다. 프로덕트로 해결해줄 수 없는
사용자의 니즈와 의지. 이건 앞으로도 계속 노력해봐야겠지.본격적인 콘텐츠 발행에 대한 고민은 SEO로 이어진다. 사이트맵, OG 태그, Search Console.
기술적인 설정은 건드렸는데, 검색에 잡히려면 결국 콘텐츠가 쌓여야 한다. 만들고 나서야 다시 실감하는 것들이다.
도메인은 아직 고민 중이다.
vercel.app이 딱히 불편하진 않은데, 브랜딩이 필요할지 독자 자연 유입이 필요할지 아직 고민해보지 않은 영역들이 잔뜩.일단 오늘은 여기까지. 오늘의 기쁨, 제법 멋지지 않나요?