From 45cc1c0271d6e1430473c5f5ceb01a5fd4ec3335 Mon Sep 17 00:00:00 2001 From: koreacomp5 Date: Wed, 8 Oct 2025 23:44:21 +0900 Subject: [PATCH] =?UTF-8?q?db=20=EC=A0=95=EC=9D=98=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- prisma/schema.prisma | 160 +++++++++++++++++++++++++++++++++++++++---- prisma/seed.js | 47 +++++++++++-- 2 files changed, 188 insertions(+), 19 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 847eb4d..733ca3e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -10,19 +10,153 @@ datasource db { url = env("DATABASE_URL") } -model User { - id Int @id @default(autoincrement()) - email String @unique - name String? - messages Message[] - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt +// schema.prisma (MySQL) + +// ==== Enums ==== +enum BoardStatus { + active + hidden + archived } -model Message { - id Int @id @default(autoincrement()) - content String - createdAt DateTime @default(now()) - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - userId Int +enum AccessLevel { + public // 비회원도 접근 + member // 로그인 필요 + moderator // 운영진 이상 + admin // 관리자만 +} + +enum PostStatus { + published + hidden + deleted +} + +enum BoardModRole { + MODERATOR + MANAGER +} + +enum UserStatus { + active + suspended + withdrawn +} + +enum AuthLevel { + USER + MOD + ADMIN +} + +// ==== Models ==== + +// 게시판 정의(관리자 생성/정렬) +model Board { + id String @id @default(cuid()) + name String + slug String @unique // URL용 + description String? + sortOrder Int @default(0) // 원하는 순서 + status BoardStatus @default(active) + isAdultOnly Boolean @default(false) // 성인 인증 필요 여부 + + readLevel AccessLevel @default(public) // 읽기 권한 + writeLevel AccessLevel @default(member) // 글쓰기 권한 + + posts Post[] + moderators BoardModerator[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@map("boards") + @@index([status, sortOrder]) +} + +// 게시판 운영진 매핑 +model BoardModerator { + id String @id @default(cuid()) + boardId String + userId String + role BoardModRole @default(MODERATOR) + + board Board @relation(fields: [boardId], references: [id], onDelete: Cascade) + user User @relation(fields: [userId], references: [userId], onDelete: Cascade) + + createdAt DateTime @default(now()) + + @@map("board_moderators") + @@unique([boardId, userId]) // 한 게시판당 1회 매핑 + @@index([userId]) +} + +// 게시글(게시판 내 컨텐츠) +model Post { + id String @id @default(cuid()) + boardId String + authorId String? + title String + content String + status PostStatus @default(published) + + isPinned Boolean @default(false) + pinnedOrder Int? // 상단 고정 정렬 + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + lastActivityAt DateTime @default(now()) + + board Board @relation(fields: [boardId], references: [id], onDelete: Cascade) + author User? @relation(fields: [authorId], references: [userId], onDelete: SetNull) + comments Comment[] + + @@map("posts") + @@index([boardId, status, createdAt]) + @@index([boardId, isPinned, pinnedOrder]) +} + +// ---- 참고: 기존 User 모델 예시 ---- +model User { + userId String @id @default(cuid()) + nickname String @unique + passwordHash String? + name String + birth DateTime + phone String @unique + rank Int @default(0) + + status UserStatus @default(active) + authLevel AuthLevel @default(USER) + profileImage String? + lastLoginAt DateTime? + isAdultVerified Boolean @default(false) + loginFailCount Int @default(0) + agreementTermsAt DateTime + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + posts Post[] + boardModerations BoardModerator[] + comments Comment[] + + @@map("users") + @@index([status]) + @@index([createdAt]) +} + +model Comment { + id String @id @default(cuid()) + postId String + authorId String? + content String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + post Post @relation(fields: [postId], references: [id], onDelete: Cascade) + author User? @relation(fields: [authorId], references: [userId], onDelete: SetNull) + + @@map("comments") + @@index([postId, createdAt]) } diff --git a/prisma/seed.js b/prisma/seed.js index 36d6e11..4806e34 100644 --- a/prisma/seed.js +++ b/prisma/seed.js @@ -3,17 +3,52 @@ const { PrismaClient } = require("@prisma/client"); const prisma = new PrismaClient(); async function main() { - await prisma.user.upsert({ - where: { email: "test@example.com" }, + const user = await prisma.user.upsert({ + where: { nickname: "tester" }, update: {}, create: { - email: "test@example.com", + nickname: "tester", name: "Tester", - messages: { - create: [{ content: "Hello world" }, { content: "Second message" }] - } + birth: new Date("1990-01-01"), + phone: "010-0000-0000", + agreementTermsAt: new Date() } }); + + const board = await prisma.board.upsert({ + where: { slug: "general" }, + update: {}, + create: { + name: "General", + slug: "general", + description: "일반 게시판", + sortOrder: 0 + } + }); + + const post = await prisma.post.create({ + data: { + boardId: board.id, + authorId: user.userId, + title: "첫 글", + content: "Hello SQLite + Prisma", + isPinned: false, + status: "published" + } + }); + + await prisma.boardModerator.upsert({ + where: { boardId_userId: { boardId: board.id, userId: user.userId } }, + update: {}, + create: { boardId: board.id, userId: user.userId, role: "MODERATOR" } + }); + + await prisma.comment.createMany({ + data: [ + { postId: post.id, authorId: user.userId, content: "첫 댓글" }, + { postId: post.id, authorId: user.userId, content: "두번째 댓글" } + ] + }); } main()