Add comprehensive plant trading marketplace with: - Prisma schema with marketplace models (Listing, Offer, SellerProfile, WishlistItem) - Service layer for listings, offers, search, and matching - API endpoints for CRUD operations, search, and recommendations - Marketplace pages: home, listing detail, create, my-listings, my-offers - Reusable UI components: ListingCard, ListingGrid, OfferForm, SearchFilters, etc. Features: - Browse and search listings by category, price, tags - Create and manage listings (draft, active, sold, cancelled) - Make and manage offers on listings - Seller and buyer views with statistics - Featured and recommended listings - In-memory store (ready for database migration via Agent 2)
284 lines
6.9 KiB
Text
284 lines
6.9 KiB
Text
// Prisma Schema for LocalGreenChain
|
|
// Note: This requires Agent 2 (Database) to set up the database connection
|
|
// For now, marketplace uses in-memory storage in lib/marketplace/store.ts
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ===========================================
|
|
// User & Authentication Models (Agent 1)
|
|
// ===========================================
|
|
|
|
enum Role {
|
|
USER
|
|
GROWER
|
|
SELLER
|
|
ADMIN
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
emailVerified DateTime?
|
|
passwordHash String?
|
|
name String?
|
|
image String?
|
|
role Role @default(USER)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
plants Plant[]
|
|
farms VerticalFarm[]
|
|
listings Listing[]
|
|
offers Offer[]
|
|
wishlistItems WishlistItem[]
|
|
sellerProfile SellerProfile?
|
|
auditLogs AuditLog[]
|
|
}
|
|
|
|
// ===========================================
|
|
// Plant & Blockchain Models
|
|
// ===========================================
|
|
|
|
model Plant {
|
|
id String @id @default(cuid())
|
|
name String
|
|
species String
|
|
variety String?
|
|
parentId String?
|
|
generation Int @default(1)
|
|
registeredAt DateTime @default(now())
|
|
ownerId String
|
|
locationLat Float?
|
|
locationLng Float?
|
|
blockHash String?
|
|
|
|
owner User @relation(fields: [ownerId], references: [id])
|
|
parent Plant? @relation("PlantLineage", fields: [parentId], references: [id])
|
|
children Plant[] @relation("PlantLineage")
|
|
transportEvents TransportEvent[]
|
|
environmentRecords EnvironmentRecord[]
|
|
listings Listing[]
|
|
}
|
|
|
|
model TransportEvent {
|
|
id String @id @default(cuid())
|
|
plantId String
|
|
eventType String
|
|
fromLat Float?
|
|
fromLng Float?
|
|
toLat Float?
|
|
toLng Float?
|
|
distance Float?
|
|
carbonKg Float?
|
|
timestamp DateTime @default(now())
|
|
metadata Json?
|
|
|
|
plant Plant @relation(fields: [plantId], references: [id])
|
|
}
|
|
|
|
model EnvironmentRecord {
|
|
id String @id @default(cuid())
|
|
plantId String
|
|
temperature Float?
|
|
humidity Float?
|
|
light Float?
|
|
soilMoisture Float?
|
|
recordedAt DateTime @default(now())
|
|
|
|
plant Plant @relation(fields: [plantId], references: [id])
|
|
}
|
|
|
|
// ===========================================
|
|
// Vertical Farm Models
|
|
// ===========================================
|
|
|
|
model VerticalFarm {
|
|
id String @id @default(cuid())
|
|
name String
|
|
ownerId String
|
|
totalArea Float
|
|
zones Int
|
|
createdAt DateTime @default(now())
|
|
|
|
owner User @relation(fields: [ownerId], references: [id])
|
|
farmZones FarmZone[]
|
|
batches CropBatch[]
|
|
}
|
|
|
|
model FarmZone {
|
|
id String @id @default(cuid())
|
|
farmId String
|
|
name String
|
|
area Float
|
|
lightType String
|
|
status String
|
|
|
|
farm VerticalFarm @relation(fields: [farmId], references: [id])
|
|
batches CropBatch[]
|
|
}
|
|
|
|
model CropBatch {
|
|
id String @id @default(cuid())
|
|
farmId String
|
|
zoneId String
|
|
cropType String
|
|
plantedAt DateTime @default(now())
|
|
harvestedAt DateTime?
|
|
status String
|
|
|
|
farm VerticalFarm @relation(fields: [farmId], references: [id])
|
|
zone FarmZone @relation(fields: [zoneId], references: [id])
|
|
}
|
|
|
|
// ===========================================
|
|
// Marketplace Models (Agent 9)
|
|
// ===========================================
|
|
|
|
enum ListingCategory {
|
|
seeds
|
|
seedlings
|
|
mature_plants
|
|
cuttings
|
|
produce
|
|
supplies
|
|
}
|
|
|
|
enum ListingStatus {
|
|
draft
|
|
active
|
|
sold
|
|
expired
|
|
cancelled
|
|
}
|
|
|
|
enum OfferStatus {
|
|
pending
|
|
accepted
|
|
rejected
|
|
withdrawn
|
|
expired
|
|
}
|
|
|
|
model Listing {
|
|
id String @id @default(cuid())
|
|
sellerId String
|
|
plantId String?
|
|
title String
|
|
description String @db.Text
|
|
price Decimal @db.Decimal(10, 2)
|
|
currency String @default("USD")
|
|
quantity Int
|
|
category ListingCategory
|
|
status ListingStatus @default(draft)
|
|
locationLat Float?
|
|
locationLng Float?
|
|
locationCity String?
|
|
locationRegion String?
|
|
tags String[]
|
|
viewCount Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
expiresAt DateTime?
|
|
|
|
seller User @relation(fields: [sellerId], references: [id])
|
|
plant Plant? @relation(fields: [plantId], references: [id])
|
|
offers Offer[]
|
|
images ListingImage[]
|
|
wishlistItems WishlistItem[]
|
|
|
|
@@index([sellerId])
|
|
@@index([category])
|
|
@@index([status])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
model ListingImage {
|
|
id String @id @default(cuid())
|
|
listingId String
|
|
url String
|
|
alt String?
|
|
isPrimary Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
|
|
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([listingId])
|
|
}
|
|
|
|
model Offer {
|
|
id String @id @default(cuid())
|
|
listingId String
|
|
buyerId String
|
|
amount Decimal @db.Decimal(10, 2)
|
|
message String? @db.Text
|
|
status OfferStatus @default(pending)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
expiresAt DateTime?
|
|
|
|
listing Listing @relation(fields: [listingId], references: [id])
|
|
buyer User @relation(fields: [buyerId], references: [id])
|
|
|
|
@@index([listingId])
|
|
@@index([buyerId])
|
|
@@index([status])
|
|
}
|
|
|
|
model SellerProfile {
|
|
id String @id @default(cuid())
|
|
userId String @unique
|
|
displayName String
|
|
bio String? @db.Text
|
|
locationCity String?
|
|
locationRegion String?
|
|
rating Float @default(0)
|
|
reviewCount Int @default(0)
|
|
totalSales Int @default(0)
|
|
verified Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
user User @relation(fields: [userId], references: [id])
|
|
}
|
|
|
|
model WishlistItem {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
listingId String
|
|
addedAt DateTime @default(now())
|
|
|
|
user User @relation(fields: [userId], references: [id])
|
|
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, listingId])
|
|
@@index([userId])
|
|
}
|
|
|
|
// ===========================================
|
|
// Transparency & Audit Models
|
|
// ===========================================
|
|
|
|
model AuditLog {
|
|
id String @id @default(cuid())
|
|
userId String?
|
|
action String
|
|
entityType String
|
|
entityId String
|
|
details Json?
|
|
ipAddress String?
|
|
userAgent String?
|
|
createdAt DateTime @default(now())
|
|
|
|
user User? @relation(fields: [userId], references: [id])
|
|
|
|
@@index([entityType, entityId])
|
|
@@index([createdAt])
|
|
}
|