Skip to content

Commit 7f22a39

Browse files
committed
바이브 코딩을 통한 프로젝트 전체 리팩토링
1 parent 0f6c4e2 commit 7f22a39

File tree

26 files changed

+402
-221
lines changed

26 files changed

+402
-221
lines changed

auth.config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export const authConfig = {
66
},
77
callbacks: {
88
authorized({ auth, request: { nextUrl } }) {
9-
console.log('authorized', auth, nextUrl);
109
const isLoggedIn = !!auth?.user;
1110
const isOnDashboard = nextUrl.pathname.startsWith('/dashboard');
1211

auth.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ export const {
1818
callbacks: {
1919
async signIn({ user }) {
2020
try {
21-
console.log(user);
21+
// 사용자 로그인 처리
2222
return true;
2323
} catch (error) {
2424
console.error("Error handling signIn:", error);
25-
return false; // 에러가 발생해도 세션을 반환합니다.
25+
return false;
2626
}
2727
},
2828
async session({ session }) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export { GET, POST } from "../../../../../auth";
1+
export { GET, POST } from "@/auth";
22

33
export const runtime = "edge";

src/app/api/image/upload/route.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ export async function POST(request: Request): Promise<NextResponse> {
2323
};
2424
},
2525
onUploadCompleted: async ({ blob, tokenPayload }) => {
26-
console.log("blob upload completed", blob, tokenPayload);
27-
2826
try {
2927
// Blob 업로드 완료 후 처리 로직 추가
28+
// 필요시 여기에 추가 로직 구현
3029
} catch (error) {
31-
throw new Error("Could not update user");
30+
console.error("Error in onUploadCompleted:", error);
31+
// 에러가 발생해도 업로드는 완료되었으므로 계속 진행
3232
}
3333
},
3434
});

src/app/api/posts/deletePost.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,47 @@
33
import { sql } from "@vercel/postgres";
44
import { unstable_noStore as noStore, revalidatePath } from "next/cache";
55
import { redirect } from "next/navigation";
6+
import { auth } from "@/auth";
67

78
/**
89
* 게시물을 삭제 상태로 변경합니다.
9-
* @param id 게시물 ID
10+
* @param index 게시물 index
1011
*/
1112
export async function deletePost(index: number) {
1213
noStore();
1314

14-
const date = new Date().toISOString().split("T")[0];
15+
// 인증 체크
16+
const session = await auth();
17+
if (!session?.user) {
18+
throw new Error("Unauthorized: 로그인이 필요합니다.");
19+
}
1520

16-
await sql.query(
17-
`
21+
try {
22+
// 게시물 존재 여부 확인
23+
const { rows: existingPost } = await sql`
24+
SELECT id FROM posts WHERE index = ${index} AND status != 'deleted'
25+
`;
26+
27+
if (!existingPost[0]) {
28+
throw new Error("게시물을 찾을 수 없습니다.");
29+
}
30+
31+
await sql`
1832
UPDATE posts
19-
SET status = 'deleted', deleted_at = $1
20-
WHERE index = $2
21-
`,
22-
[date, index]
23-
);
33+
SET status = 'deleted', deleted_at = CURRENT_TIMESTAMP
34+
WHERE index = ${index}
35+
`;
2436

25-
revalidatePath(`/posts/${index}`);
26-
redirect("/posts");
37+
revalidatePath(`/posts/${index}`);
38+
revalidatePath("/posts");
39+
revalidatePath("/");
40+
redirect("/posts");
41+
} catch (error) {
42+
console.error("Database Error:", error);
43+
throw new Error(
44+
error instanceof Error
45+
? error.message
46+
: "게시물 삭제 중 오류가 발생했습니다."
47+
);
48+
}
2749
}

src/app/api/posts/getPost.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,22 @@ export async function getPost(index: number): Promise<IPost> {
1313
noStore();
1414

1515
try {
16-
const { rows } = await sql`SELECT * FROM posts WHERE index = ${index}`;
16+
const { rows } = await sql`
17+
SELECT * FROM posts
18+
WHERE index = ${index} AND status = 'published'
19+
`;
20+
21+
if (!rows[0]) {
22+
throw new Error("게시물을 찾을 수 없습니다.");
23+
}
1724

1825
return camelcaseKeys(rows[0], { deep: true }) as IPost;
1926
} catch (error) {
2027
console.error("Database Error:", error);
21-
throw new Error("Failed to fetch post data by index.");
28+
throw new Error(
29+
error instanceof Error
30+
? error.message
31+
: "게시물을 불러오는 중 오류가 발생했습니다."
32+
);
2233
}
2334
}

src/app/api/posts/getPrevNextPost.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ export async function getPrevNextPost(index: number): Promise<{
1717

1818
try {
1919
const [previousPost, nextPost] = await Promise.all([
20-
sql`SELECT * FROM posts WHERE index < ${index} AND status = 'published' ORDER BY index DESC LIMIT 1`,
21-
sql`SELECT * FROM posts WHERE index > ${index} AND status = 'published' ORDER BY index ASC LIMIT 1`,
20+
sql`SELECT * FROM posts WHERE index < ${index} AND status = 'published' ORDER BY index DESC LIMIT 1`,
21+
sql`SELECT * FROM posts WHERE index > ${index} AND status = 'published' ORDER BY index ASC LIMIT 1`,
2222
]);
2323

2424
return {
@@ -31,6 +31,6 @@ export async function getPrevNextPost(index: number): Promise<{
3131
};
3232
} catch (error) {
3333
console.error("Database Error:", error);
34-
throw new Error("Failed to fetch adjacent post data.");
34+
throw new Error("이전/다음 게시물을 불러오는 중 오류가 발생했습니다.");
3535
}
3636
}

src/app/api/posts/getSearchedPost.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,25 @@ import camelcaseKeys from "camelcase-keys";
99
* @param search 게시물의 title과 content에서 찾아볼 search
1010
* @returns 게시물 데이터
1111
*/
12-
export async function getSearchedPost(search: string) {
12+
export async function getSearchedPost(search: string): Promise<IPost[]> {
1313
noStore();
1414

15+
if (!search || !search.trim()) {
16+
return [];
17+
}
18+
1519
try {
20+
const searchTerm = `%${search.trim()}%`;
1621
const { rows } = await sql`
1722
SELECT * FROM posts
18-
WHERE (title ILIKE '%' || ${search} || '%'
19-
OR content ILIKE '%' || ${search} || '%')
23+
WHERE (title ILIKE ${searchTerm} OR content ILIKE ${searchTerm})
2024
AND status = 'published'
25+
ORDER BY created_at DESC
2126
`;
2227

2328
return camelcaseKeys(rows, { deep: true }) as IPost[];
2429
} catch (error) {
2530
console.error("Database Error:", error);
26-
throw new Error("Failed to fetch post data by index.");
31+
throw new Error("게시물 검색 중 오류가 발생했습니다.");
2732
}
2833
}

src/app/api/posts/incrementPostViews.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,15 @@ export async function incrementPostViews(index: number) {
1111
noStore();
1212

1313
try {
14-
await sql.query(
15-
`
14+
await sql`
1615
UPDATE posts
1716
SET views = views + 1
18-
WHERE index = $1
19-
`,
20-
[index]
21-
);
17+
WHERE index = ${index} AND status = 'published'
18+
`;
2219

2320
revalidatePath(`/posts/${index}`);
2421
} catch (error) {
2522
console.error("Database Error:", error);
26-
throw new Error("Failed to increment post views.");
23+
// 조회수 증가 실패는 치명적이지 않으므로 에러를 던지지 않음
2724
}
2825
}

src/app/api/posts/postPost.ts

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { sql } from "@vercel/postgres";
44
import { unstable_noStore as noStore, revalidatePath } from "next/cache";
55
import { redirect } from "next/navigation";
66
import camelcaseKeys from "camelcase-keys";
7+
import { auth } from "@/auth";
78

89
/**
910
* 게시물을 생성합니다.
@@ -19,41 +20,42 @@ export async function postPost({
1920
}) {
2021
noStore();
2122

22-
try {
23-
await sql`
24-
CREATE TABLE IF NOT EXISTS posts (
25-
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
26-
index SERIAL,
27-
title TEXT NOT NULL,
28-
content TEXT NOT NULL,
29-
tags TEXT[] DEFAULT '{}',
30-
comments UUID[] DEFAULT '{}',
31-
created_at DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,
32-
updated_at DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,
33-
deleted_at DATE DEFAULT NULL,
34-
status TEXT NOT NULL DEFAULT 'published',
35-
likes INT DEFAULT 0,
36-
views INT DEFAULT 0
37-
)
38-
`;
23+
// 인증 체크
24+
const session = await auth();
25+
if (!session?.user) {
26+
throw new Error("Unauthorized: 로그인이 필요합니다.");
27+
}
3928

40-
await sql.query(
41-
`
42-
INSERT INTO posts (title, content)
43-
VALUES ($1, $2)
44-
`,
45-
[title, markdownValue]
46-
);
29+
// 입력 검증
30+
if (!title || !title.trim()) {
31+
throw new Error("제목을 입력해주세요.");
32+
}
33+
if (!markdownValue || !markdownValue.trim()) {
34+
throw new Error("내용을 입력해주세요.");
35+
}
4736

48-
const { rows } =
49-
await sql`SELECT index FROM posts ORDER BY index DESC LIMIT 1`;
37+
try {
38+
const { rows } = await sql`
39+
INSERT INTO posts (title, content)
40+
VALUES (${title.trim()}, ${markdownValue.trim()})
41+
RETURNING index
42+
`;
5043

51-
revalidatePath(`/posts/${rows[0].index}`);
52-
redirect(`/posts/${rows[0].index}`);
44+
if (!rows[0]?.index) {
45+
throw new Error("게시물 생성에 실패했습니다.");
46+
}
5347

54-
return camelcaseKeys(rows[0], { deep: true }) as IPost;
48+
const postIndex = rows[0].index;
49+
revalidatePath(`/posts/${postIndex}`);
50+
revalidatePath("/posts");
51+
revalidatePath("/");
52+
redirect(`/posts/${postIndex}`);
5553
} catch (error) {
5654
console.error("Database Error:", error);
57-
throw new Error("Failed to fetch recent posts data.");
55+
throw new Error(
56+
error instanceof Error
57+
? error.message
58+
: "게시물 생성 중 오류가 발생했습니다."
59+
);
5860
}
5961
}

0 commit comments

Comments
 (0)