diff --git a/.claude/commands/purge-cache.md b/.claude/commands/purge-cache.md
new file mode 100644
index 0000000..139b198
--- /dev/null
+++ b/.claude/commands/purge-cache.md
@@ -0,0 +1,35 @@
+---
+description: 로컬(.next)과 Vercel의 Data/CDN 캐시를 제거해 stale 데이터를 해소
+---
+
+로컬과 Vercel의 캐시를 제거한다. Sanity Studio에서 직접 편집한 내용이 사이트에 반영 안 될 때 사용.
+
+**인자**: `$ARGUMENTS` — `local` | `vercel` | 비어있으면 둘 다.
+
+## 절차
+
+### 로컬 (`local` 또는 인자 없음)
+
+1. `rm -rf .next` 실행 — Next.js Data Cache는 `.next/cache/fetch-cache`에 파일로 저장되므로 dev 서버 재시작만으로는 사라지지 않는다.
+2. 실행 후 사용자에게 안내: **dev 서버가 돌고 있었다면 재시작 필요** (`pnpm dev`). Claude가 띄운 서버가 아니면 직접 재시작을 요청한다.
+
+### Vercel (`vercel` 또는 인자 없음)
+
+프로젝트는 `.vercel/project.json`으로 이미 연결되어 있다 (`ram-blog-jul5`).
+
+```bash
+vercel cache purge --type data --yes
+vercel cache purge --type cdn --yes
+```
+
+- Data Cache: `client.fetch`의 `force-cache` 결과 (Sanity 응답) — stale의 주범
+- CDN: Full Route Cache로 페이지 자체가 남아있을 수 있어 함께 제거
+
+### 마무리
+
+- 두 명령의 성공 출력(`Successfully purged ...`)을 확인하고 결과를 한 줄로 보고
+- 실패 시(로그인 만료 등) `vercel whoami`로 인증 상태를 확인하고 사용자에게 `vercel login` 안내
+
+## 배경
+
+읽기 서비스가 전부 태그 기반 `force-cache`인데, `revalidateTag`는 앱 API mutation에서만 호출된다. Sanity Studio 직접 편집은 어떤 revalidate도 트리거하지 않아 환경별 캐시가 stale해진다 (근본 해결은 Sanity 웹훅 → `/api/revalidate`, 백로그).
diff --git a/sanity-studio/schemas/user.js b/sanity-studio/schemas/user.js
index cce077c..6548f09 100644
--- a/sanity-studio/schemas/user.js
+++ b/sanity-studio/schemas/user.js
@@ -33,11 +33,6 @@ export default {
name: 'image',
type: 'string',
},
- {
- title: 'Blog Name',
- name: 'blogName',
- type: 'string',
- },
{
title: 'Profile Title',
name: 'title',
diff --git a/src/components/common/Header.tsx b/src/components/common/Header.tsx
index 6a8231d..279f70f 100644
--- a/src/components/common/Header.tsx
+++ b/src/components/common/Header.tsx
@@ -59,7 +59,7 @@ export default function Header() {
{params.user ? (
- {userProfile?.blogName}
+ {userProfile?.title}
) : (
diff --git a/src/components/setting/ProfileForm.tsx b/src/components/setting/ProfileForm.tsx
index 83e8579..0b66002 100644
--- a/src/components/setting/ProfileForm.tsx
+++ b/src/components/setting/ProfileForm.tsx
@@ -85,6 +85,7 @@ export default function ProfileForm({ userData }: Props) {
.then(() => {
router.refresh();
mutate(`/api/${userData.slug}/me`);
+ mutate(`/api/${userData.slug}`);
router.push(`/${userData.slug}`);
})
.catch((err) => setError(err.toString()))
diff --git a/src/model/user.ts b/src/model/user.ts
index ff3b964..722954e 100644
--- a/src/model/user.ts
+++ b/src/model/user.ts
@@ -16,9 +16,7 @@ export type AuthUser = {
image?: string;
};
-export type UserData = AuthUser & {
- blogName: string;
-};
+export type UserData = AuthUser;
export type SimpleUser = {
id: string;
@@ -32,7 +30,6 @@ export type SimpleUser = {
export type ProfileUser = AuthUser & {
following: number;
followers: number;
- blogName: string;
title: string;
introduce: string;
links: Links;
@@ -40,7 +37,6 @@ export type ProfileUser = AuthUser & {
};
export type HomeUser = AuthUser & {
- blogName: string;
title: string;
introduce: string;
links: Links;
diff --git a/src/sanity/types.ts b/src/sanity/types.ts
index 453ce00..2ded9cd 100644
--- a/src/sanity/types.ts
+++ b/src/sanity/types.ts
@@ -245,7 +245,6 @@ export type User = {
email?: string;
password?: string;
image?: string;
- blogName?: string;
title?: string;
introduce?: string;
links?: {
@@ -884,7 +883,6 @@ export type CheckUsernameValidQueryResult = {
email?: string;
password?: string;
image?: string;
- blogName?: string;
title?: string;
introduce?: string;
links?: {
@@ -931,7 +929,6 @@ export type CheckSlugValidQueryResult = {
email?: string;
password?: string;
image?: string;
- blogName?: string;
title?: string;
introduce?: string;
links?: {
@@ -978,7 +975,6 @@ export type CheckEmailValidQueryResult = {
email?: string;
password?: string;
image?: string;
- blogName?: string;
title?: string;
introduce?: string;
links?: {
@@ -1026,14 +1022,13 @@ export type LoginWithEmailQueryResult = {
// Query: *[_type=='user' && _id == $id][0].slug
export type UserSlugByIdQueryResult = string | null;
// Variable: userDataQuery
-// Query: *[_type=='user' && _id == $userId][0] {"id":_id,name,username,email,image,blogName}
+// Query: *[_type=='user' && _id == $userId][0] {"id":_id,name,username,email,image}
export type UserDataQueryResult = {
id: string;
name: string | null;
username: string | null;
email: string | null;
image: string | null;
- blogName: string | null;
} | null;
// Variable: userBySlugQuery
// Query: *[_type == "user" && slug == $slug][0]{ ..., "id":_id, following[]->{"id":_id,username,slug,name,image,title}, followers[]->{"id":_id,username,slug,name,image,title}, "bookmarks":bookmarks[]->_id }
@@ -1049,7 +1044,6 @@ export type UserBySlugQueryResult = {
email?: string;
password?: string;
image?: string;
- blogName?: string;
title?: string;
introduce?: string;
links?: {
@@ -1093,7 +1087,6 @@ export type UserForProfileQueryResult = {
email?: string;
password?: string;
image?: string;
- blogName?: string;
title?: string;
introduce?: string;
links?: {
@@ -1143,7 +1136,7 @@ declare module '@sanity/client' {
"\n *[_type=='user' && email == $email][0]\n": CheckEmailValidQueryResult;
'\n *[_type==\'user\' && email == $email][0]{\n "id":_id,\n email,\n name,\n username,\n slug,\n password,\n image,\n }\n': LoginWithEmailQueryResult;
"\n *[_type=='user' && _id == $id][0].slug\n": UserSlugByIdQueryResult;
- '\n *[_type==\'user\' && _id == $userId][0]\n {"id":_id,name,username,email,image,blogName}\n': UserDataQueryResult;
+ '\n *[_type==\'user\' && _id == $userId][0]\n {"id":_id,name,username,email,image}\n': UserDataQueryResult;
'\n *[_type == "user" && slug == $slug][0]{\n ...,\n "id":_id,\n following[]->{"id":_id,username,slug,name,image,title},\n followers[]->{"id":_id,username,slug,name,image,title},\n "bookmarks":bookmarks[]->_id\n }\n': UserBySlugQueryResult;
'\n *[_type==\'user\' && slug == $slug][0]{\n ...,\n "id":_id,\n "following":count(following),\n "followers":count(followers),\n "posts":count(*[_type=="post" && author->slug == $slug])\n }\n': UserForProfileQueryResult;
}
diff --git a/src/service/user.ts b/src/service/user.ts
index 26b434e..413a375 100644
--- a/src/service/user.ts
+++ b/src/service/user.ts
@@ -33,7 +33,7 @@ const userSlugByIdQuery = defineQuery(`
const userDataQuery = defineQuery(`
*[_type=='user' && _id == $userId][0]
- {"id":_id,name,username,email,image,blogName}
+ {"id":_id,name,username,email,image}
`);
const userBySlugQuery = defineQuery(`
@@ -72,7 +72,6 @@ export async function addUser({
email,
name,
image,
- blogName: name,
title: `${name}`,
introduce: `안녕하세요 ${name}의 멋진 블로그입니다 :)`,
following: [],
@@ -101,7 +100,6 @@ export async function addEmailUser({
password,
name,
image: '',
- blogName: name,
title: `${name}`,
introduce: `안녕하세요 ${name}의 멋진 블로그입니다 :)`,
following: [],
@@ -200,7 +198,7 @@ export async function getUserBySlug(slug: string): Promise {
{ slug },
{
cache: 'force-cache',
- next: { tags: ['following', 'bookmark'] },
+ next: { tags: ['following', 'bookmark', `profile/${slug}`] },
}
);
@@ -213,7 +211,6 @@ export async function getUserBySlug(slug: string): Promise {
slug: user.slug ?? '',
email: user.email ?? '',
image: user.image,
- blogName: user.blogName ?? '',
title: user.title ?? '',
introduce: user.introduce ?? '',
links: user.links ?? defaultLinks,
@@ -246,7 +243,6 @@ export async function getUserForProfile(
image: user.image,
following: user.following ?? 0,
followers: user.followers ?? 0,
- blogName: user.blogName ?? '',
title: user.title ?? '',
introduce: user.introduce ?? '',
links: user.links ?? defaultLinks,