Files
travelplanning/backend/prisma/schema.prisma
T

350 lines
10 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"
previewFeatures = ["driverAdapters"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// --- Enums ---
enum ParticipantRole {
OWNER
MANAGER
MEMBER
MEMBER_NO_FINANCE
VIEWER_ONLY
}
enum JoinRequestStatus {
PENDING
ACCEPTED
REJECTED
}
enum ExpenseCategory {
ACCOMMODATION
FOOD
TRANSPORT
TICKET
OTHER
}
enum LocationStatus {
PENDING
COMPLETED
}
enum LocationType {
MOVE
VISIT
REST
EAT
}
enum PrivacyLevel {
PUBLIC
TOUR_ONLY
PRIVATE
}
// --- Models ---
model User {
id String @id @default(uuid())
email String? @unique
passwordHash String?
name String?
phone String?
address String?
avatar String?
createdAt DateTime @default(now())
isAdmin Boolean @default(false)
isBlocked Boolean @default(false)
isAnonymous Boolean @default(false)
createdTours Tour[] @relation("TourCreator")
tourParticipations TourParticipant[]
requestedJoinRequests JoinRequest[] @relation("JoinRequestUser")
receivedJoinRequests JoinRequest[] @relation("JoinRequester")
uploadedPhotos Photo[]
paidExpenses Expense[] @relation("ExpensePaidBy")
comments Comment[]
sentConnections UserConnection[] @relation("ConnectionRequester")
receivedConnections UserConnection[] @relation("ConnectionReceiver")
sentMessages DirectMessage[] @relation("MessageSender")
receivedMessages DirectMessage[] @relation("MessageReceiver")
tourMessages TourMessage[]
receivedRatings TourRating[] @relation("RatedUser")
sentRatings TourRating[] @relation("RatingUser")
}
model Tour {
id String @id @default(uuid())
title String
description String?
startDate DateTime?
endDate DateTime?
createdAt DateTime @default(now())
totalCost Decimal @default(0) @db.Decimal(15, 2)
adultCount Int @default(1)
childCount Int @default(0)
childDiscount Int @default(30)
tags String[]
createdById String
creator User @relation("TourCreator", fields: [createdById], references: [id])
participants TourParticipant[]
joinRequests JoinRequest[]
legs Leg[]
photos Photo[]
invitations TourInvitation[]
tourMessages TourMessage[]
ratings TourRating[]
share TourShare?
}
model JoinRequest {
id String @id @default(uuid())
tourId String
userId String
requestedById String
status JoinRequestStatus @default(PENDING)
createdAt DateTime @default(now())
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
user User @relation("JoinRequestUser", fields: [userId], references: [id], onDelete: Cascade)
requestedBy User @relation("JoinRequester", fields: [requestedById], references: [id], onDelete: Cascade)
@@index([tourId, status])
@@index([userId])
}
model TourParticipant {
id String @id @default(uuid())
tourId String
userId String?
role ParticipantRole @default(MEMBER)
displayName String?
adultCount Int @default(1)
childCount Int @default(0)
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([tourId, userId])
}
model Leg {
id String @id @default(uuid())
tourId String
sequence Int
note String? @db.Text
startDate DateTime?
endDate DateTime?
description String? @db.Text
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
locations Location[]
expenses Expense[]
}
model Location {
id String @id @default(uuid())
legId String
name String
address String?
latitude Float
longitude Float
plannedStart DateTime?
plannedEnd DateTime?
actualStart DateTime?
actualEnd DateTime?
status LocationStatus @default(PENDING)
type LocationType @default(VISIT)
leg Leg @relation(fields: [legId], references: [id], onDelete: Cascade)
expenses Expense[]
photos Photo[]
comments Comment[]
createdAt DateTime @default(now())
}
model Expense {
id String @id @default(uuid())
legId String @map("leg_id")
locationId String? @map("location_id")
category ExpenseCategory
amount Decimal @db.Decimal(15, 2)
description String? @db.Text
note String? @db.Text
paidById String? @map("paid_by_id")
leg Leg @relation(fields: [legId], references: [id], onDelete: Cascade)
location Location? @relation(fields: [locationId], references: [id], onDelete: Cascade)
paidBy User? @relation("ExpensePaidBy", fields: [paidById], references: [id], onDelete: SetNull)
}
model Photo {
id String @id @default(uuid())
tourId String?
locationId String?
uploaderId String
imageUrl String?
originalUrl String?
capturedAt DateTime @default(now())
metadata Json?
privacy PrivacyLevel @default(TOUR_ONLY)
tour Tour? @relation(fields: [tourId], references: [id], onDelete: SetNull)
location Location? @relation(fields: [locationId], references: [id], onDelete: SetNull)
uploader User @relation(fields: [uploaderId], references: [id])
comments Comment[]
}
model Comment {
id String @id @default(uuid())
content String
createdAt DateTime @default(now())
locationId String?
location Location? @relation(fields: [locationId], references: [id], onDelete: Cascade)
photoId String?
photo Photo? @relation(fields: [photoId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model TourInvitation {
id String @id @default(uuid())
tourId String
email String
role ParticipantRole @default(MEMBER)
token String @unique
createdAt DateTime @default(now())
expiredAt DateTime
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
@@unique([tourId, email])
}
enum ConnectionStatus {
PENDING
ACCEPTED
REJECTED
}
enum ConnectionType {
FRIEND
FAMILY
}
model UserConnection {
id String @id @default(uuid())
requesterId String
receiverId String
status ConnectionStatus @default(PENDING)
type ConnectionType @default(FRIEND)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
requester User @relation("ConnectionRequester", fields: [requesterId], references: [id], onDelete: Cascade)
receiver User @relation("ConnectionReceiver", fields: [receiverId], references: [id], onDelete: Cascade)
@@unique([requesterId, receiverId])
@@index([requesterId])
@@index([receiverId])
}
model DirectMessage {
id String @id @default(uuid())
senderId String
receiverId String
content String @db.Text
attachmentUrl String?
latitude Float?
longitude Float?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sender User @relation("MessageSender", fields: [senderId], references: [id], onDelete: Cascade)
receiver User @relation("MessageReceiver", fields: [receiverId], references: [id], onDelete: Cascade)
@@index([senderId])
@@index([receiverId])
}
model TourMessage {
id String @id @default(uuid())
tourId String
senderId String
content String @db.Text
attachmentUrl String?
latitude Float?
longitude Float?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
sender User @relation(fields: [senderId], references: [id], onDelete: Cascade)
@@index([tourId])
@@index([senderId])
}
model WordFilter {
id String @id @default(uuid())
word String @unique
replacement String
createdAt DateTime @default(now())
}
model ModerationSetting {
id String @id @default(uuid())
blockNsfw Boolean @default(false)
blurFaces Boolean @default(false)
}
model TourRating {
id String @id @default(uuid())
tourId String
targetUserId String
raterUserId String
honesty Int @default(5)
transparency Int @default(5)
enthusiasm Int @default(5)
cheerfulness Int @default(5)
seriousness Int @default(5)
planning Int @default(5)
survival Int @default(5)
averageScore Float @default(5.0)
comment String? @db.Text
createdAt DateTime @default(now())
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
targetUser User @relation("RatedUser", fields: [targetUserId], references: [id], onDelete: Cascade)
raterUser User @relation("RatingUser", fields: [raterUserId], references: [id], onDelete: Cascade)
@@unique([tourId, targetUserId, raterUserId])
}
model TourShare {
id String @id @default(uuid())
tourId String @unique
token String @unique @default(uuid())
isEnabled Boolean @default(true)
createdAt DateTime @default(now())
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
}