feat(schema): 게시판 대분류 BoardCategory 및 보드-카테고리 연동 추가\nchore(seed): 기본 카테고리 시드 및 보드 매핑 반영\ndocs(erd): ERD 업데이트
This commit is contained in:
62
prisma/migrations/20251012204802_add_category/migration.sql
Normal file
62
prisma/migrations/20251012204802_add_category/migration.sql
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- A unique constraint covering the columns `[name]` on the table `partners` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "board_categories" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"slug" TEXT NOT NULL,
|
||||||
|
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"status" TEXT NOT NULL DEFAULT 'active',
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- RedefineTables
|
||||||
|
PRAGMA defer_foreign_keys=ON;
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
CREATE TABLE "new_boards" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"slug" TEXT NOT NULL,
|
||||||
|
"description" TEXT,
|
||||||
|
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"status" TEXT NOT NULL DEFAULT 'active',
|
||||||
|
"type" TEXT NOT NULL DEFAULT 'general',
|
||||||
|
"requiresApproval" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"allowAnonymousPost" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"allowSecretComment" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"isAdultOnly" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"requiredTags" JSONB,
|
||||||
|
"requiredFields" JSONB,
|
||||||
|
"readLevel" TEXT NOT NULL DEFAULT 'public',
|
||||||
|
"writeLevel" TEXT NOT NULL DEFAULT 'member',
|
||||||
|
"categoryId" TEXT,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL,
|
||||||
|
CONSTRAINT "boards_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "board_categories" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO "new_boards" ("allowAnonymousPost", "allowSecretComment", "createdAt", "description", "id", "isAdultOnly", "name", "readLevel", "requiredFields", "requiredTags", "requiresApproval", "slug", "sortOrder", "status", "type", "updatedAt", "writeLevel") SELECT "allowAnonymousPost", "allowSecretComment", "createdAt", "description", "id", "isAdultOnly", "name", "readLevel", "requiredFields", "requiredTags", "requiresApproval", "slug", "sortOrder", "status", "type", "updatedAt", "writeLevel" FROM "boards";
|
||||||
|
DROP TABLE "boards";
|
||||||
|
ALTER TABLE "new_boards" RENAME TO "boards";
|
||||||
|
CREATE UNIQUE INDEX "boards_slug_key" ON "boards"("slug");
|
||||||
|
CREATE INDEX "boards_status_sortOrder_idx" ON "boards"("status", "sortOrder");
|
||||||
|
CREATE INDEX "boards_type_requiresApproval_idx" ON "boards"("type", "requiresApproval");
|
||||||
|
CREATE INDEX "boards_categoryId_idx" ON "boards"("categoryId");
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
|
PRAGMA defer_foreign_keys=OFF;
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "board_categories_name_key" ON "board_categories"("name");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "board_categories_slug_key" ON "board_categories"("slug");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "board_categories_status_sortOrder_idx" ON "board_categories"("status", "sortOrder");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "partners_name_key" ON "partners"("name");
|
||||||
@@ -101,6 +101,23 @@ enum Action {
|
|||||||
|
|
||||||
// ==== Models ====
|
// ==== Models ====
|
||||||
|
|
||||||
|
// 게시판 대분류
|
||||||
|
model BoardCategory {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String @unique
|
||||||
|
slug String @unique
|
||||||
|
sortOrder Int @default(0)
|
||||||
|
status String @default("active")
|
||||||
|
|
||||||
|
boards Board[]
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
@@index([status, sortOrder])
|
||||||
|
@@map("board_categories")
|
||||||
|
}
|
||||||
|
|
||||||
// 게시판 정의(관리자 생성/정렬)
|
// 게시판 정의(관리자 생성/정렬)
|
||||||
model Board {
|
model Board {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
@@ -120,6 +137,10 @@ model Board {
|
|||||||
readLevel AccessLevel @default(public) // 읽기 권한
|
readLevel AccessLevel @default(public) // 읽기 권한
|
||||||
writeLevel AccessLevel @default(member) // 글쓰기 권한
|
writeLevel AccessLevel @default(member) // 글쓰기 권한
|
||||||
|
|
||||||
|
// 대분류
|
||||||
|
categoryId String?
|
||||||
|
category BoardCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
|
||||||
|
|
||||||
posts Post[]
|
posts Post[]
|
||||||
moderators BoardModerator[]
|
moderators BoardModerator[]
|
||||||
|
|
||||||
@@ -128,6 +149,7 @@ model Board {
|
|||||||
|
|
||||||
@@index([status, sortOrder])
|
@@index([status, sortOrder])
|
||||||
@@index([type, requiresApproval])
|
@@index([type, requiresApproval])
|
||||||
|
@@index([categoryId])
|
||||||
@@map("boards")
|
@@map("boards")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,25 @@ const { PrismaClient } = require("@prisma/client");
|
|||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
|
async function upsertCategories() {
|
||||||
|
const categories = [
|
||||||
|
{ name: "운영", slug: "ops", sortOrder: 1, status: "active" },
|
||||||
|
{ name: "커뮤니티", slug: "community", sortOrder: 2, status: "active" },
|
||||||
|
{ name: "특수", slug: "special", sortOrder: 3, status: "active" },
|
||||||
|
{ name: "제휴", slug: "partners", sortOrder: 4, status: "active" },
|
||||||
|
];
|
||||||
|
const map = {};
|
||||||
|
for (const c of categories) {
|
||||||
|
const created = await prisma.boardCategory.upsert({
|
||||||
|
where: { slug: c.slug },
|
||||||
|
update: { name: c.name, sortOrder: c.sortOrder, status: c.status },
|
||||||
|
create: c,
|
||||||
|
});
|
||||||
|
map[c.slug] = created;
|
||||||
|
}
|
||||||
|
return map; // { slug: category }
|
||||||
|
}
|
||||||
|
|
||||||
async function upsertRoles() {
|
async function upsertRoles() {
|
||||||
const roles = [
|
const roles = [
|
||||||
{ name: "admin", description: "관리자" },
|
{ name: "admin", description: "관리자" },
|
||||||
@@ -85,7 +104,7 @@ async function upsertAdmin() {
|
|||||||
return admin;
|
return admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function upsertBoards(admin) {
|
async function upsertBoards(admin, categoryMap) {
|
||||||
const boards = [
|
const boards = [
|
||||||
// 일반
|
// 일반
|
||||||
{ name: "공지사항", slug: "notice", description: "공지", type: "general", sortOrder: 1, writeLevel: "moderator" },
|
{ name: "공지사항", slug: "notice", description: "공지", type: "general", sortOrder: 1, writeLevel: "moderator" },
|
||||||
@@ -111,6 +130,13 @@ async function upsertBoards(admin) {
|
|||||||
|
|
||||||
const created = [];
|
const created = [];
|
||||||
for (const b of boards) {
|
for (const b of boards) {
|
||||||
|
// 카테고리 매핑 규칙
|
||||||
|
let categorySlug = "community";
|
||||||
|
if (["notice", "bug-report"].includes(b.slug)) categorySlug = "ops";
|
||||||
|
if (["attendance", "nearby-partners", "ranking", "free-coupons", "monthly-stats"].includes(b.slug)) categorySlug = "special";
|
||||||
|
if (["partners-photos"].includes(b.slug)) categorySlug = "partners";
|
||||||
|
|
||||||
|
const category = categoryMap[categorySlug];
|
||||||
const board = await prisma.board.upsert({
|
const board = await prisma.board.upsert({
|
||||||
where: { slug: b.slug },
|
where: { slug: b.slug },
|
||||||
update: {
|
update: {
|
||||||
@@ -120,6 +146,7 @@ async function upsertBoards(admin) {
|
|||||||
requiresApproval: !!b.requiresApproval,
|
requiresApproval: !!b.requiresApproval,
|
||||||
allowAnonymousPost: !!b.allowAnonymousPost,
|
allowAnonymousPost: !!b.allowAnonymousPost,
|
||||||
readLevel: b.readLevel || undefined,
|
readLevel: b.readLevel || undefined,
|
||||||
|
categoryId: category ? category.id : undefined,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
name: b.name,
|
name: b.name,
|
||||||
@@ -130,6 +157,7 @@ async function upsertBoards(admin) {
|
|||||||
requiresApproval: !!b.requiresApproval,
|
requiresApproval: !!b.requiresApproval,
|
||||||
allowAnonymousPost: !!b.allowAnonymousPost,
|
allowAnonymousPost: !!b.allowAnonymousPost,
|
||||||
readLevel: b.readLevel || undefined,
|
readLevel: b.readLevel || undefined,
|
||||||
|
categoryId: category ? category.id : undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
created.push(board);
|
created.push(board);
|
||||||
@@ -181,7 +209,8 @@ async function seedPolicies() {
|
|||||||
async function main() {
|
async function main() {
|
||||||
await upsertRoles();
|
await upsertRoles();
|
||||||
const admin = await upsertAdmin();
|
const admin = await upsertAdmin();
|
||||||
const boards = await upsertBoards(admin);
|
const categoryMap = await upsertCategories();
|
||||||
|
const boards = await upsertBoards(admin, categoryMap);
|
||||||
|
|
||||||
// 샘플 글 하나
|
// 샘플 글 하나
|
||||||
const free = boards.find((b) => b.slug === "free") || boards[0];
|
const free = boards.find((b) => b.slug === "free") || boards[0];
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 781 KiB After Width: | Height: | Size: 795 KiB |
Reference in New Issue
Block a user