Files
marketplace/server/prisma/schema.prisma
delta-lynx-89e8 b37b734c82 Initial marketplace implementation
Full-stack marketplace for buying/selling second-hand items.
React 19 + TypeScript + Tailwind CSS v4 frontend with 17 screens,
Express + Prisma + Socket.io backend, Stripe payments, JWT auth.

Deployed at https://marketplace.173.212.212.157.sslip.io/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 07:00:44 -08:00

263 lines
6.6 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum Category {
ELECTRONICS
FURNITURE
CLOTHING
HOME_GARDEN
SPORTS
BOOKS
GAMES
VEHICLES
OTHER
}
enum ListingCondition {
NEW
LIKE_NEW
GENTLY_USED
USED
FAIR
}
enum ListingStatus {
DRAFT
ACTIVE
SOLD
DELETED
}
enum OfferStatus {
PENDING
ACCEPTED
DECLINED
COUNTERED
}
enum NotificationType {
NEW_OFFER
OFFER_ACCEPTED
OFFER_DECLINED
ITEM_SOLD
NEW_MESSAGE
ITEM_FAVORITED
}
enum PaymentStatus {
PENDING
COMPLETED
FAILED
REFUNDED
}
model User {
id String @id @default(cuid())
email String @unique
passwordHash String
fullName String
nickname String?
avatar String?
phone String?
location String?
bio String?
rating Float @default(0)
ratingCount Int @default(0)
showEmail Boolean @default(false)
showPhone Boolean @default(true)
showLocation Boolean @default(true)
showOnline Boolean @default(true)
showRating Boolean @default(true)
twoFactorEnabled Boolean @default(false)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sessions Session[]
listings Listing[]
images ListingImage[]
sentOffers Offer[] @relation("BuyerOffers")
receivedOffers Offer[] @relation("SellerOffers")
conversations1 Conversation[] @relation("User1Conversations")
conversations2 Conversation[] @relation("User2Conversations")
messages Message[]
favorites Favorite[]
notifications Notification[]
payments Payment[]
blockedUsers BlockedUser[] @relation("Blocker")
blockedBy BlockedUser[] @relation("Blocked")
}
model Session {
id String @id @default(cuid())
userId String
refreshToken String @unique
userAgent String?
ipAddress String?
expiresAt DateTime
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
}
model Listing {
id String @id @default(cuid())
title String
description String
price Float
obo Boolean @default(false)
category Category
condition ListingCondition
status ListingStatus @default(DRAFT)
location String
viewCount Int @default(0)
sellerId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
seller User @relation(fields: [sellerId], references: [id], onDelete: Cascade)
images ListingImage[]
offers Offer[]
conversations Conversation[]
favorites Favorite[]
payments Payment[]
@@index([sellerId])
@@index([category])
@@index([status])
@@index([createdAt])
}
model ListingImage {
id String @id @default(cuid())
url String
order Int @default(0)
listingId String
uploadedBy String
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
user User @relation(fields: [uploadedBy], references: [id], onDelete: Cascade)
@@index([listingId])
}
model Offer {
id String @id @default(cuid())
amount Float
message String?
status OfferStatus @default(PENDING)
counterAmount Float?
buyerId String
sellerId String
listingId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
buyer User @relation("BuyerOffers", fields: [buyerId], references: [id], onDelete: Cascade)
seller User @relation("SellerOffers", fields: [sellerId], references: [id], onDelete: Cascade)
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
@@index([buyerId])
@@index([sellerId])
@@index([listingId])
}
model Conversation {
id String @id @default(cuid())
user1Id String
user2Id String
listingId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user1 User @relation("User1Conversations", fields: [user1Id], references: [id], onDelete: Cascade)
user2 User @relation("User2Conversations", fields: [user2Id], references: [id], onDelete: Cascade)
listing Listing? @relation(fields: [listingId], references: [id], onDelete: SetNull)
messages Message[]
@@unique([user1Id, user2Id, listingId])
@@index([user1Id])
@@index([user2Id])
}
model Message {
id String @id @default(cuid())
content String
senderId String
conversationId String
isRead Boolean @default(false)
offerAmount Float?
createdAt DateTime @default(now())
sender User @relation(fields: [senderId], references: [id], onDelete: Cascade)
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
@@index([conversationId])
@@index([senderId])
}
model Favorite {
id String @id @default(cuid())
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)
@@unique([userId, listingId])
}
model Notification {
id String @id @default(cuid())
userId String
type NotificationType
title String
body String
data Json?
isRead Boolean @default(false)
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([createdAt])
}
model Payment {
id String @id @default(cuid())
userId String
listingId String
stripePaymentId String? @unique
amount Float
status PaymentStatus @default(PENDING)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([listingId])
}
model BlockedUser {
id String @id @default(cuid())
blockerId String
blockedId String
createdAt DateTime @default(now())
blocker User @relation("Blocker", fields: [blockerId], references: [id], onDelete: Cascade)
blocked User @relation("Blocked", fields: [blockedId], references: [id], onDelete: Cascade)
@@unique([blockerId, blockedId])
}