게시물 추천과 관리자 목록 필터 정리

This commit is contained in:
2026-05-15 11:49:12 +09:00
parent 59a50a0c97
commit 2768975752
20 changed files with 258 additions and 46 deletions

View File

@@ -22,6 +22,8 @@ const mapPostRow = (row) => ({
content: row.content,
excerpt: row.excerpt,
featuredImage: row.featured_image,
isFeatured: Boolean(row.is_featured),
commentCount: Number(row.comment_count || 0),
seoTitle: row.seo_title || '',
seoDescription: row.seo_description || '',
canonicalUrl: row.canonical_url || '',
@@ -193,6 +195,12 @@ export const listPosts = async () => {
const rows = await sql`
SELECT
posts.*,
(
SELECT COUNT(*)::int
FROM comments
WHERE comments.post_id = posts.id
AND comments.status = 'published'
) AS comment_count,
COALESCE(array_agg(tags.slug) FILTER (WHERE tags.slug IS NOT NULL), '{}') AS tags
FROM posts
LEFT JOIN post_tags ON post_tags.post_id = posts.id
@@ -223,6 +231,12 @@ export const listAdminPosts = async () => {
const rows = await sql`
SELECT
posts.*,
(
SELECT COUNT(*)::int
FROM comments
WHERE comments.post_id = posts.id
AND comments.status = 'published'
) AS comment_count,
COALESCE(array_agg(tags.slug) FILTER (WHERE tags.slug IS NOT NULL), '{}') AS tags
FROM posts
LEFT JOIN post_tags ON post_tags.post_id = posts.id
@@ -249,6 +263,12 @@ export const getAdminPostById = async (id) => {
const rows = await sql`
SELECT
posts.*,
(
SELECT COUNT(*)::int
FROM comments
WHERE comments.post_id = posts.id
AND comments.status = 'published'
) AS comment_count,
COALESCE(array_agg(tags.slug) FILTER (WHERE tags.slug IS NOT NULL), '{}') AS tags
FROM posts
LEFT JOIN post_tags ON post_tags.post_id = posts.id
@@ -281,6 +301,7 @@ export const createAdminPost = async (input) => {
content,
excerpt,
featured_image,
is_featured,
seo_title,
seo_description,
canonical_url,
@@ -295,6 +316,7 @@ export const createAdminPost = async (input) => {
${input.content},
${input.excerpt},
${input.featuredImage},
${input.isFeatured},
${input.seoTitle},
${input.seoDescription},
${input.canonicalUrl},
@@ -336,6 +358,7 @@ export const updateAdminPost = async (id, input) => {
content = ${input.content},
excerpt = ${input.excerpt},
featured_image = ${input.featuredImage},
is_featured = ${input.isFeatured},
seo_title = ${input.seoTitle},
seo_description = ${input.seoDescription},
canonical_url = ${input.canonicalUrl},
@@ -396,6 +419,12 @@ export const getPostBySlug = async (slug) => {
const rows = await sql`
SELECT
posts.*,
(
SELECT COUNT(*)::int
FROM comments
WHERE comments.post_id = posts.id
AND comments.status = 'published'
) AS comment_count,
COALESCE(array_agg(tags.slug) FILTER (WHERE tags.slug IS NOT NULL), '{}') AS tags
FROM posts
LEFT JOIN post_tags ON post_tags.post_id = posts.id

View File

@@ -8,6 +8,7 @@ export const adminPostInputSchema = z.object({
content: z.preprocess(normalizeMarkdownContent, z.string()).default(''),
excerpt: z.string().default(''),
featuredImage: z.string().trim().nullable().default(null),
isFeatured: z.boolean().default(false),
seoTitle: z.string().trim().default(''),
seoDescription: z.string().trim().default(''),
canonicalUrl: z.string().trim().url().or(z.literal('')).default(''),

View File

@@ -9,6 +9,8 @@ export const postSchema = z.object({
content: z.string(),
excerpt: z.string().default(''),
featuredImage: z.string().nullable().default(null),
isFeatured: z.boolean().default(false),
commentCount: z.number().int().default(0),
seoTitle: z.string().default(''),
seoDescription: z.string().default(''),
canonicalUrl: z.string().default(''),