Schema Reference
Complete Prisma schema for Y3NKO.
Users & Authentication
User
model User {
id String @id @default(cuid())
email String @unique
phone String? @unique
emailVerified DateTime?
phoneVerified DateTime?
passwordHash String?
role UserRole @default(USER)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
profile Profile?
bookings Booking[]
favorites Favorite[]
@@index([email])
@@index([phone])
}
enum UserRole {
USER
HOST
ADMIN
SUPER_ADMIN
}Profile
model Profile {
id String @id @default(cuid())
userId String @unique
firstName String
lastName String
displayName String?
avatarUrl String?
bio String?
nationality String?
language String @default("en")
currency Currency @default(GHS)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
enum Currency {
GHS
USD
EUR
GBP
}Listings
Listing
model Listing {
id String @id @default(cuid())
type ListingType
status ListingStatus @default(DRAFT)
// Basic Info
title String
slug String @unique
description String @db.Text
highlights String[]
// Location
region String
city String
area String?
address String
latitude Float?
longitude Float?
// Pricing
priceGHS Decimal @db.Decimal(10, 2)
priceUSD Decimal? @db.Decimal(10, 2)
priceUnit PriceUnit @default(PER_NIGHT)
// Accommodation-specific
propertyType PropertyType?
bedrooms Int?
bathrooms Int?
maxGuests Int?
checkInTime String?
checkOutTime String?
// Activity-specific
duration Int?
difficulty Difficulty?
minParticipants Int?
maxParticipants Int?
// Meta
featured Boolean @default(false)
viewCount Int @default(0)
bookingCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
publishedAt DateTime?
// Host
hostId String?
images ListingImage[]
amenities ListingAmenity[]
bookings Booking[]
favorites Favorite[]
availability Availability[]
@@index([type, status])
@@index([region, city])
@@index([slug])
@@index([featured])
@@index([hostId])
}
enum ListingType {
ACCOMMODATION
ACTIVITY
EXPERIENCE
RESTAURANT
}
enum ListingStatus {
DRAFT
PENDING_REVIEW
PUBLISHED
ARCHIVED
}
enum PropertyType {
HOTEL
GUEST_HOUSE
APARTMENT
VILLA
HOSTEL
RESORT
BOUTIQUE_HOTEL
AIRBNB_STYLE
}
enum PriceUnit {
PER_NIGHT
PER_PERSON
PER_GROUP
FIXED
}
enum Difficulty {
EASY
MODERATE
CHALLENGING
}ListingImage
model ListingImage {
id String @id @default(cuid())
listingId String
url String
publicId String // Cloudinary public ID
alt String?
caption String?
order Int @default(0)
isPrimary Boolean @default(false)
createdAt DateTime @default(now())
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
@@index([listingId])
}Amenities
model Amenity {
id String @id @default(cuid())
name String @unique
icon String
category String
listings ListingAmenity[]
}
model ListingAmenity {
listingId String
amenityId String
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
amenity Amenity @relation(fields: [amenityId], references: [id], onDelete: Cascade)
@@id([listingId, amenityId])
}Availability
model Availability {
id String @id @default(cuid())
listingId String
date DateTime @db.Date
available Boolean @default(true)
priceGHS Decimal? @db.Decimal(10, 2)
note String?
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
@@unique([listingId, date])
@@index([listingId, date])
}Bookings & Payments
Booking
model Booking {
id String @id @default(cuid())
reference String @unique
userId String
listingId String
status BookingStatus @default(PENDING)
// Dates
checkIn DateTime @db.Date
checkOut DateTime @db.Date
nights Int
// Guests
adults Int @default(1)
children Int @default(0)
// Pricing (snapshot at booking time)
pricePerNight Decimal @db.Decimal(10, 2)
subtotal Decimal @db.Decimal(10, 2)
serviceFee Decimal @db.Decimal(10, 2)
taxes Decimal @db.Decimal(10, 2)
total Decimal @db.Decimal(10, 2)
currency Currency @default(GHS)
// Guest Info
guestName String
guestEmail String
guestPhone String
specialRequests String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
confirmedAt DateTime?
cancelledAt DateTime?
cancelReason String?
user User @relation(fields: [userId], references: [id])
listing Listing @relation(fields: [listingId], references: [id])
payments Payment[]
@@index([userId])
@@index([listingId])
@@index([reference])
@@index([status])
@@index([checkIn, checkOut])
}
enum BookingStatus {
PENDING
CONFIRMED
CANCELLED
COMPLETED
NO_SHOW
}Payment
model Payment {
id String @id @default(cuid())
bookingId String
status PaymentStatus @default(PENDING)
amount Decimal @db.Decimal(10, 2)
currency Currency @default(GHS)
method PaymentMethod?
paystackRef String? @unique
paystackAuth String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
paidAt DateTime?
failedAt DateTime?
failureReason String?
booking Booking @relation(fields: [bookingId], references: [id])
@@index([bookingId])
@@index([paystackRef])
}
enum PaymentStatus {
PENDING
PROCESSING
COMPLETED
FAILED
REFUNDED
}
enum PaymentMethod {
CARD
MOBILE_MONEY
BANK_TRANSFER
}User Interactions
Favorite
model Favorite {
userId String
listingId String
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
@@id([userId, listingId])
}Content
Destination
model Destination {
id String @id @default(cuid())
name String
slug String @unique
region String
description String @db.Text
imageUrl String
featured Boolean @default(false)
order Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([slug])
@@index([featured])
}Ghana Regions
const GHANA_REGIONS = [
"Greater Accra",
"Ashanti",
"Western",
"Central",
"Eastern",
"Volta",
"Northern",
"Upper East",
"Upper West",
"Brong-Ahafo",
"Oti",
"Bono East",
"Ahafo",
"Western North",
"North East",
"Savannah",
]