153 lines
3.9 KiB
Plaintext
153 lines
3.9 KiB
Plaintext
// This is your Prisma schema file,
|
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
}
|
|
|
|
// --- Enums ---
|
|
|
|
enum MemberRole {
|
|
OWNER
|
|
EDITOR
|
|
MEMBER_PLAN_ONLY
|
|
MEMBER_PHOTO_ONLY
|
|
VIEWER_EXTERNAL
|
|
}
|
|
|
|
enum ExpenseCategory {
|
|
LODGING
|
|
DINING
|
|
TRANSPORT
|
|
OTHER
|
|
}
|
|
|
|
enum TriggerType {
|
|
AUTO_BY_TIME
|
|
MANUAL_BY_USER
|
|
}
|
|
|
|
enum PrivacyLevel {
|
|
PUBLIC_IN_TOUR
|
|
PRIVATE_OWNER
|
|
}
|
|
|
|
// --- Models ---
|
|
|
|
model User {
|
|
id Int @id @default(autoincrement())
|
|
email String @unique
|
|
passwordHash String
|
|
name String?
|
|
avatar String?
|
|
createdAt DateTime @default(now())
|
|
isAdmin Boolean @default(false)
|
|
|
|
createdTours Tour[] @relation("TourCreator")
|
|
tourMemberships TourMember[]
|
|
uploadedPhotos Photo[]
|
|
}
|
|
|
|
model Tour {
|
|
id Int @id @default(autoincrement())
|
|
title String
|
|
startDate DateTime?
|
|
endDate DateTime?
|
|
createdAt DateTime @default(now())
|
|
|
|
creatorId Int
|
|
creator User @relation("TourCreator", fields: [creatorId], references: [id])
|
|
|
|
members TourMember[]
|
|
legs Leg[]
|
|
tasks Task[]
|
|
photos Photo[]
|
|
}
|
|
|
|
model TourMember {
|
|
tourId Int
|
|
userId Int
|
|
role MemberRole @default(MEMBER_PLAN_ONLY)
|
|
|
|
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([tourId, userId])
|
|
}
|
|
|
|
model Leg {
|
|
id Int @id @default(autoincrement())
|
|
tourId Int
|
|
sequenceNumber Int
|
|
notes String? @db.Text
|
|
|
|
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
|
|
places Place[]
|
|
expenses Expense[]
|
|
tasks Task[]
|
|
}
|
|
|
|
model Place {
|
|
id Int @id @default(autoincrement())
|
|
legId Int
|
|
name String
|
|
address String?
|
|
|
|
// Sử dụng Float cho Lat/Lng để dễ thao tác ở Frontend.
|
|
// Nếu bạn muốn dùng PostGIS chuyên sâu, có thể dùng Unsupported("geography(Point, 4326)")
|
|
latitude Float
|
|
longitude Float
|
|
|
|
sequenceInLeg Int
|
|
arrivalTime DateTime?
|
|
departureTime DateTime?
|
|
|
|
leg Leg @relation(fields: [legId], references: [id], onDelete: Cascade)
|
|
expenses Expense[]
|
|
photos Photo[]
|
|
}
|
|
|
|
model Expense {
|
|
id Int @id @default(autoincrement())
|
|
legId Int
|
|
placeId Int?
|
|
category ExpenseCategory
|
|
amount Decimal @db.Decimal(15, 2)
|
|
currency String @default("VND")
|
|
description String? @db.Text
|
|
|
|
leg Leg @relation(fields: [legId], references: [id], onDelete: Cascade)
|
|
place Place? @relation(fields: [placeId], references: [id], onDelete: Cascade)
|
|
}
|
|
|
|
model Task {
|
|
id Int @id @default(autoincrement())
|
|
tourId Int
|
|
legId Int?
|
|
title String
|
|
plannedTimestamp DateTime
|
|
isCompleted Boolean @default(false)
|
|
completedAt DateTime?
|
|
triggerType TriggerType @default(MANUAL_BY_USER)
|
|
|
|
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
|
|
leg Leg? @relation(fields: [legId], references: [id])
|
|
}
|
|
|
|
model Photo {
|
|
id Int @id @default(autoincrement())
|
|
tourId Int
|
|
placeId Int?
|
|
uploaderId Int
|
|
imageUrl String
|
|
capturedAt DateTime @default(now())
|
|
privacyLevel PrivacyLevel @default(PUBLIC_IN_TOUR)
|
|
|
|
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
|
|
place Place? @relation(fields: [placeId], references: [id], onDelete: SetNull)
|
|
uploader User @relation(fields: [uploaderId], references: [id])
|
|
} |