관리자페이지 작업

This commit is contained in:
mota
2025-10-31 16:27:04 +09:00
parent f444888f2d
commit 0827352e6b
14 changed files with 704 additions and 105 deletions

View File

@@ -0,0 +1,55 @@
-- CreateTable
CREATE TABLE "board_view_types" (
"id" TEXT NOT NULL PRIMARY KEY,
"key" TEXT NOT NULL,
"name" TEXT NOT NULL,
"scope" TEXT NOT NULL,
"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,
"mainPageViewTypeId" TEXT,
"listViewTypeId" 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,
CONSTRAINT "boards_mainPageViewTypeId_fkey" FOREIGN KEY ("mainPageViewTypeId") REFERENCES "board_view_types" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "boards_listViewTypeId_fkey" FOREIGN KEY ("listViewTypeId") REFERENCES "board_view_types" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_boards" ("allowAnonymousPost", "allowSecretComment", "categoryId", "createdAt", "description", "id", "isAdultOnly", "name", "readLevel", "requiredFields", "requiredTags", "requiresApproval", "slug", "sortOrder", "status", "type", "updatedAt", "writeLevel") SELECT "allowAnonymousPost", "allowSecretComment", "categoryId", "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");
CREATE INDEX "boards_mainPageViewTypeId_idx" ON "boards"("mainPageViewTypeId");
CREATE INDEX "boards_listViewTypeId_idx" ON "boards"("listViewTypeId");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;
-- CreateIndex
CREATE UNIQUE INDEX "board_view_types_key_key" ON "board_view_types"("key");
-- CreateIndex
CREATE INDEX "board_view_types_scope_idx" ON "board_view_types"("scope");

View File

@@ -0,0 +1,11 @@
-- CreateTable
CREATE TABLE "settings" (
"id" TEXT NOT NULL PRIMARY KEY,
"key" TEXT NOT NULL,
"value" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "settings_key_key" ON "settings"("key");

View File

@@ -141,6 +141,12 @@ model Board {
categoryId String?
category BoardCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
// 뷰 타입 설정 (동적 테이블 참조)
mainPageViewTypeId String?
mainPageViewType BoardViewType? @relation("MainPageViewType", fields: [mainPageViewTypeId], references: [id], onDelete: SetNull)
listViewTypeId String?
listViewType BoardViewType? @relation("ListViewType", fields: [listViewTypeId], references: [id], onDelete: SetNull)
posts Post[]
moderators BoardModerator[]
@@ -150,9 +156,29 @@ model Board {
@@index([status, sortOrder])
@@index([type, requiresApproval])
@@index([categoryId])
@@index([mainPageViewTypeId])
@@index([listViewTypeId])
@@map("boards")
}
// 게시판 뷰 타입 정의 (enum 대신 데이터 테이블)
model BoardViewType {
id String @id @default(cuid())
key String @unique // 예: preview, text, special_rank
name String // 표시용 이름
scope String // 용도 구분: 'main' | 'list' 등 자유 텍스트
// 역참조
mainBoards Board[] @relation("MainPageViewType")
listBoards Board[] @relation("ListViewType")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([scope])
@@map("board_view_types")
}
// 게시판 운영진 매핑
model BoardModerator {
id String @id @default(cuid())
@@ -703,3 +729,14 @@ model PartnerRequest {
@@index([status, createdAt])
@@map("partner_requests")
}
// 시스템 설정 (key-value 형태)
model Setting {
id String @id @default(cuid())
key String @unique
value String // JSON 문자열로 저장
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("settings")
}

View File

@@ -207,6 +207,28 @@ async function upsertBoards(admin, categoryMap) {
return created;
}
async function upsertViewTypes() {
const viewTypes = [
// main scope
{ key: "main_default", name: "기본", scope: "main" },
{ key: "main_text", name: "텍스트", scope: "main" },
{ key: "main_preview", name: "미리보기", scope: "main" },
{ key: "main_special_rank", name: "특수랭킹", scope: "main" },
// list scope
{ key: "list_default", name: "기본", scope: "list" },
{ key: "list_text", name: "텍스트", scope: "list" },
{ key: "list_preview", name: "미리보기", scope: "list" },
{ key: "list_special_rank", name: "특수랭킹", scope: "list" },
];
for (const vt of viewTypes) {
await prisma.boardViewType.upsert({
where: { key: vt.key },
update: { name: vt.name, scope: vt.scope },
create: vt,
});
}
}
async function seedPolicies() {
// 금칙어 예시
const banned = [
@@ -241,6 +263,7 @@ async function main() {
await upsertRoles();
const admin = await upsertAdmin();
const categoryMap = await upsertCategories();
await upsertViewTypes();
const boards = await upsertBoards(admin, categoryMap);
// 샘플 글 하나