138 lines
3.9 KiB
Markdown
138 lines
3.9 KiB
Markdown
# DB 설계(1차)
|
|
|
|
## 핵심 엔티티
|
|
- Campaign(종목), LandingPage, LandingRoute, RouteCondition, Lead, User
|
|
- 역할: ADMIN / LEAD_MANAGER
|
|
|
|
## 엔티티 관계
|
|
- Campaign 1:N LandingPage
|
|
- Campaign 1:N LandingRoute
|
|
- LandingRoute 1:N RouteCondition
|
|
- LandingRoute N:1 LandingPage(기본 페이지)
|
|
- RouteCondition N:1 LandingPage(조건 매칭 페이지)
|
|
- LandingPage 1:N Lead
|
|
- Campaign 1:N Lead
|
|
|
|
## 권한 정책
|
|
- ADMIN: 모든 관리자 기능
|
|
- LEAD_MANAGER: 리드 조회만 가능
|
|
|
|
## Prisma 스키마 (SQLite 기준)
|
|
```prisma
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "sqlite"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
enum UserRole {
|
|
ADMIN
|
|
LEAD_MANAGER
|
|
}
|
|
|
|
model Campaign {
|
|
id String @id @default(cuid())
|
|
name String
|
|
description String?
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
landingPages LandingPage[]
|
|
routes LandingRoute[]
|
|
leads Lead[]
|
|
}
|
|
|
|
model LandingPage {
|
|
id String @id @default(cuid())
|
|
campaignId String
|
|
campaign Campaign @relation(fields: [campaignId], references: [id], onDelete: Cascade)
|
|
name String
|
|
slug String?
|
|
blocks Json
|
|
isDefault Boolean @default(false)
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
defaultRoutes LandingRoute[] @relation("RouteDefaultPage")
|
|
conditions RouteCondition[]
|
|
leads Lead[]
|
|
|
|
@@index([campaignId, isActive])
|
|
}
|
|
|
|
model LandingRoute {
|
|
id String @id @default(cuid())
|
|
campaignId String
|
|
campaign Campaign @relation(fields: [campaignId], references: [id], onDelete: Cascade)
|
|
host String
|
|
path String
|
|
defaultPageId String
|
|
defaultPage LandingPage @relation("RouteDefaultPage", fields: [defaultPageId], references: [id], onDelete: Restrict)
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
conditions RouteCondition[]
|
|
leads Lead[]
|
|
|
|
@@unique([host, path])
|
|
}
|
|
|
|
model RouteCondition {
|
|
id String @id @default(cuid())
|
|
routeId String
|
|
route LandingRoute @relation(fields: [routeId], references: [id], onDelete: Cascade)
|
|
pageId String
|
|
page LandingPage @relation(fields: [pageId], references: [id], onDelete: Restrict)
|
|
label String
|
|
priority Int @default(0)
|
|
isActive Boolean @default(true)
|
|
|
|
startDate DateTime?
|
|
endDate DateTime?
|
|
timezone String @default("Asia/Seoul")
|
|
weekMask String @default("0000000")
|
|
startMinute Int?
|
|
endMinute Int?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model Lead {
|
|
id String @id @default(cuid())
|
|
campaignId String
|
|
campaign Campaign @relation(fields: [campaignId], references: [id], onDelete: Cascade)
|
|
pageId String
|
|
page LandingPage @relation(fields: [pageId], references: [id], onDelete: Restrict)
|
|
routeId String?
|
|
route LandingRoute? @relation(fields: [routeId], references: [id], onDelete: SetNull)
|
|
payload Json
|
|
sourceMeta Json?
|
|
submittedAt DateTime @default(now())
|
|
|
|
@@index([campaignId, submittedAt])
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
name String?
|
|
password String
|
|
role UserRole @default(ADMIN)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
```
|
|
|
|
### 참고
|
|
- `defaultRoutes`는 `@relation("RouteDefaultPage")`로 라우트 기본 페이지 역참조입니다.
|
|
- 동일 엔티티에서 기본 라우트를 찾을 때는 `LandingRoute.defaultPageId`가 FK입니다.
|
|
- PostgreSQL 전환 시 datasource `provider`만 교체하지 않고 nullable/시간대 처리 포함 마이그레이션 검증이 필요하다.
|