localgreenchain/prisma/schema.prisma
Claude 3d2ccdc29a
feat(db): implement PostgreSQL database integration with Prisma ORM
Agent 2 - Database Integration (P0 Critical):

- Add Prisma ORM with PostgreSQL for persistent data storage
- Create comprehensive database schema with 20+ models:
  - User & authentication models
  - Plant & lineage tracking
  - Transport events & supply chain
  - Vertical farming (farms, zones, batches, recipes)
  - Demand & market matching
  - Audit logging & blockchain storage

- Implement complete database service layer (lib/db/):
  - users.ts: User CRUD with search and stats
  - plants.ts: Plant operations with lineage tracking
  - transport.ts: Transport events and carbon tracking
  - farms.ts: Vertical farm and crop batch management
  - demand.ts: Consumer preferences and market matching
  - audit.ts: Audit logging and blockchain integrity

- Add PlantChainDB for database-backed blockchain
- Create development seed script with sample data
- Add database documentation (docs/DATABASE.md)
- Update package.json with Prisma dependencies and scripts

This provides the foundation for all other agents to build upon
with persistent, scalable data storage.
2025-11-23 03:56:40 +00:00

1084 lines
22 KiB
Text

// LocalGreenChain Database Schema
// Prisma ORM configuration for PostgreSQL
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// ============================================
// USER & AUTHENTICATION
// ============================================
model User {
id String @id @default(cuid())
email String @unique
name String
walletAddress String? @unique
passwordHash String?
// Profile
avatarUrl String?
bio String?
// Location
latitude Float?
longitude Float?
address String?
city String?
country String?
// User type
userType UserType @default(CONSUMER)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lastLoginAt DateTime?
// Relations
ownedPlants Plant[]
verticalFarms VerticalFarm[]
consumerPreferences ConsumerPreference[]
supplyCommitments SupplyCommitment[]
sentTransportEvents TransportEvent[] @relation("Sender")
receivedTransportEvents TransportEvent[] @relation("Receiver")
seasonalPlans SeasonalPlan[]
auditLogs AuditLog[]
@@index([email])
@@index([userType])
}
enum UserType {
CONSUMER
GROWER
DISTRIBUTOR
PROCESSOR
ADMIN
}
// ============================================
// PLANT & LINEAGE TRACKING
// ============================================
model Plant {
id String @id @default(cuid())
// Plant identification
commonName String
scientificName String?
species String?
genus String?
family String?
// Lineage tracking
parentPlantId String?
parentPlant Plant? @relation("PlantLineage", fields: [parentPlantId], references: [id])
childPlants Plant[] @relation("PlantLineage")
propagationType PropagationType @default(ORIGINAL)
generation Int @default(0)
// Lifecycle
plantedDate DateTime
harvestedDate DateTime?
status PlantStatus @default(SPROUTED)
// Location
latitude Float
longitude Float
address String?
city String?
country String?
// Owner
ownerId String
owner User @relation(fields: [ownerId], references: [id])
// Environmental data (JSON for flexibility)
environment Json?
growthMetrics Json?
// Metadata
notes String?
images String[]
plantsNetId String?
// Blockchain integration
blockIndex Int?
blockHash String?
// Timestamps
registeredAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
transportEvents TransportEvent[]
cropBatches CropBatch[]
@@index([ownerId])
@@index([commonName])
@@index([status])
@@index([parentPlantId])
@@index([latitude, longitude])
}
enum PropagationType {
SEED
CLONE
CUTTING
DIVISION
GRAFTING
ORIGINAL
}
enum PlantStatus {
SPROUTED
GROWING
MATURE
FLOWERING
FRUITING
DORMANT
DECEASED
}
// ============================================
// TRANSPORT & SUPPLY CHAIN
// ============================================
model TransportEvent {
id String @id @default(cuid())
// Event type
eventType TransportEventType
// Locations
fromLatitude Float
fromLongitude Float
fromAddress String?
fromCity String?
fromCountry String?
fromLocationType LocationType
fromFacilityId String?
fromFacilityName String?
toLatitude Float
toLongitude Float
toAddress String?
toCity String?
toCountry String?
toLocationType LocationType
toFacilityId String?
toFacilityName String?
// Distance and duration
distanceKm Float
durationMinutes Int
// Environmental impact
transportMethod TransportMethod
carbonFootprintKg Float
// Parties
senderId String
sender User @relation("Sender", fields: [senderId], references: [id])
receiverId String
receiver User @relation("Receiver", fields: [receiverId], references: [id])
// Verification signatures
senderSignature String?
receiverSignature String?
verifierSignature String?
// Status
status TransportStatus @default(PENDING)
// Metadata
notes String?
photos String[]
documents String[]
// Extended event data (JSON for type-specific fields)
eventData Json?
// Blockchain integration
blockIndex Int?
blockHash String?
cumulativeCarbonKg Float?
cumulativeFoodMiles Float?
// Timestamps
timestamp DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
plants Plant[]
seedBatch SeedBatch? @relation(fields: [seedBatchId], references: [id])
seedBatchId String?
harvestBatch HarvestBatch? @relation(fields: [harvestBatchId], references: [id])
harvestBatchId String?
@@index([eventType])
@@index([senderId])
@@index([receiverId])
@@index([status])
@@index([timestamp])
}
enum TransportEventType {
SEED_ACQUISITION
PLANTING
GROWING_TRANSPORT
HARVEST
PROCESSING
DISTRIBUTION
CONSUMER_DELIVERY
SEED_SAVING
SEED_SHARING
}
enum LocationType {
FARM
GREENHOUSE
VERTICAL_FARM
WAREHOUSE
HUB
MARKET
CONSUMER
SEED_BANK
OTHER
}
enum TransportMethod {
WALKING
BICYCLE
ELECTRIC_VEHICLE
HYBRID_VEHICLE
GASOLINE_VEHICLE
DIESEL_TRUCK
ELECTRIC_TRUCK
REFRIGERATED_TRUCK
RAIL
SHIP
AIR
DRONE
LOCAL_DELIVERY
CUSTOMER_PICKUP
}
enum TransportStatus {
PENDING
IN_TRANSIT
DELIVERED
VERIFIED
DISPUTED
}
// Seed Batch for tracking seeds through the system
model SeedBatch {
id String @id @default(cuid())
// Seed info
species String
variety String?
quantity Float
quantityUnit String @default("seeds")
// Lineage
geneticLineageId String?
parentPlantIds String[]
generation Int @default(0)
// Quality
germinationRate Float?
purityPercentage Float?
harvestDate DateTime?
expirationDate DateTime?
// Certifications
certifications String[]
certificationDocs String[]
// Storage
storageTemperature Float?
storageHumidity Float?
containerType String?
// Status
status SeedBatchStatus @default(AVAILABLE)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
transportEvents TransportEvent[]
cropBatches CropBatch[]
@@index([species])
@@index([status])
}
enum SeedBatchStatus {
AVAILABLE
PARTIALLY_USED
DEPLETED
EXPIRED
}
// Harvest Batch for tracking harvested produce
model HarvestBatch {
id String @id @default(cuid())
// Harvest info
produceType String
harvestType String @default("full")
// Quantities
grossWeight Float
netWeight Float
weightUnit String @default("kg")
itemCount Int?
// Quality
qualityGrade String?
qualityNotes String?
// Storage
packagingType String?
shelfLifeHours Int?
temperatureMin Float?
temperatureMax Float?
// Timestamps
harvestedAt DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
transportEvents TransportEvent[]
cropBatch CropBatch? @relation(fields: [cropBatchId], references: [id])
cropBatchId String?
@@index([produceType])
@@index([harvestedAt])
}
// ============================================
// VERTICAL FARMING
// ============================================
model VerticalFarm {
id String @id @default(cuid())
name String
// Owner
ownerId String
owner User @relation(fields: [ownerId], references: [id])
// Location
latitude Float
longitude Float
address String
city String
country String
timezone String @default("UTC")
// Facility specs (JSON for complex nested structure)
specs Json
// Systems configuration (JSON for flexibility)
environmentalControl Json?
irrigationSystem Json?
lightingSystem Json?
nutrientSystem Json?
// Automation
automationLevel AutomationLevel @default(MANUAL)
automationSystems Json?
// Status
status FarmStatus @default(OFFLINE)
operationalSince DateTime?
lastMaintenanceDate DateTime?
// Performance metrics
capacityUtilization Float?
yieldEfficiency Float?
energyEfficiencyScore Float?
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
zones GrowingZone[]
cropBatches CropBatch[]
resourceUsage ResourceUsage[]
farmAnalytics FarmAnalytics[]
@@index([ownerId])
@@index([status])
@@index([city, country])
}
enum AutomationLevel {
MANUAL
SEMI_AUTOMATED
FULLY_AUTOMATED
}
enum FarmStatus {
OFFLINE
STARTING
OPERATIONAL
MAINTENANCE
EMERGENCY
}
model GrowingZone {
id String @id @default(cuid())
name String
level Int
// Dimensions
areaSqm Float
lengthM Float?
widthM Float?
// Growing system
growingMethod GrowingMethod
plantPositions Int
// Current status
currentCrop String?
plantingDate DateTime?
expectedHarvestDate DateTime?
// Environment targets (JSON)
environmentTargets Json?
// Current readings (JSON)
currentEnvironment Json?
// Status
status ZoneStatus @default(EMPTY)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
farm VerticalFarm @relation(fields: [farmId], references: [id], onDelete: Cascade)
farmId String
cropBatches CropBatch[]
@@index([farmId])
@@index([status])
}
enum GrowingMethod {
NFT
DWC
EBB_FLOW
AEROPONICS
VERTICAL_TOWERS
RACK_SYSTEM
}
enum ZoneStatus {
EMPTY
PREPARING
PLANTED
GROWING
HARVESTING
CLEANING
}
model CropBatch {
id String @id @default(cuid())
// Crop info
cropType String
variety String?
// Growing
plantCount Int
plantingDate DateTime
transplantDate DateTime?
// Progress
currentStage String @default("germinating")
currentDay Int @default(0)
healthScore Float?
// Expected
expectedHarvestDate DateTime
expectedYieldKg Float
// Actual (after harvest)
actualHarvestDate DateTime?
actualYieldKg Float?
qualityGrade String?
// Status
status CropBatchStatus @default(GERMINATING)
// Issues (JSON array)
issues Json?
// Environmental log (JSON array)
environmentLog Json?
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
farm VerticalFarm @relation(fields: [farmId], references: [id])
farmId String
zone GrowingZone @relation(fields: [zoneId], references: [id])
zoneId String
recipe GrowingRecipe? @relation(fields: [recipeId], references: [id])
recipeId String?
seedBatch SeedBatch? @relation(fields: [seedBatchId], references: [id])
seedBatchId String?
plants Plant[]
harvestBatches HarvestBatch[]
@@index([farmId])
@@index([zoneId])
@@index([status])
@@index([cropType])
}
enum CropBatchStatus {
GERMINATING
GROWING
READY
HARVESTING
COMPLETED
FAILED
}
model GrowingRecipe {
id String @id @default(cuid())
name String
cropType String
variety String?
version String @default("1.0")
// Stages (JSON array of GrowthStage)
stages Json
// Expected outcomes
expectedDays Int
expectedYieldGrams Float
expectedYieldPerSqm Float?
// Requirements (JSON)
requirements Json?
// Source
source RecipeSource @default(INTERNAL)
author String?
rating Float?
timesUsed Int @default(0)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
cropBatches CropBatch[]
@@index([cropType])
@@index([source])
}
enum RecipeSource {
INTERNAL
COMMUNITY
COMMERCIAL
}
model ResourceUsage {
id String @id @default(cuid())
// Period
periodStart DateTime
periodEnd DateTime
// Energy
electricityKwh Float
electricityCostUsd Float?
renewablePercent Float?
peakDemandKw Float?
// Water
waterUsageL Float
waterCostUsd Float?
waterRecycledPercent Float?
// CO2
co2UsedKg Float?
co2CostUsd Float?
// Nutrients
nutrientsUsedL Float?
nutrientCostUsd Float?
// Efficiency metrics
kwhPerKgProduce Float?
litersPerKgProduce Float?
costPerKgProduce Float?
// Timestamps
createdAt DateTime @default(now())
// Relations
farm VerticalFarm @relation(fields: [farmId], references: [id])
farmId String
@@index([farmId])
@@index([periodStart, periodEnd])
}
model FarmAnalytics {
id String @id @default(cuid())
// Period
period String
generatedAt DateTime @default(now())
// Production
totalYieldKg Float
yieldPerSqmPerYear Float?
cropCyclesCompleted Int
averageCyclesDays Float?
// Quality
averageQualityScore Float?
gradeAPercent Float?
wastagePercent Float?
// Efficiency
cropSuccessRate Float?
spaceUtilization Float?
laborHoursPerKg Float?
// Financial
revenueUsd Float?
costUsd Float?
profitMarginPercent Float?
revenuePerSqm Float?
// Environmental
carbonFootprintKgPerKg Float?
waterUseLPerKg Float?
energyUseKwhPerKg Float?
// Top crops (JSON arrays)
topCropsByYield Json?
topCropsByRevenue Json?
topCropsByEfficiency Json?
// Timestamps
createdAt DateTime @default(now())
// Relations
farm VerticalFarm @relation(fields: [farmId], references: [id])
farmId String
@@index([farmId])
@@index([period])
}
// ============================================
// DEMAND & MARKET MATCHING
// ============================================
model ConsumerPreference {
id String @id @default(cuid())
// Consumer
consumerId String
consumer User @relation(fields: [consumerId], references: [id])
// Location
latitude Float
longitude Float
maxDeliveryRadiusKm Float @default(50)
city String?
region String?
// Dietary preferences
dietaryType String[]
allergies String[]
dislikes String[]
// Produce preferences (JSON)
preferredCategories String[]
preferredItems Json?
// Quality preferences
certificationPreferences String[]
freshnessImportance Int @default(3)
priceImportance Int @default(3)
sustainabilityImportance Int @default(3)
// Delivery preferences (JSON)
deliveryPreferences Json?
// Household
householdSize Int @default(1)
weeklyBudget Float?
currency String? @default("USD")
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([consumerId])
@@index([latitude, longitude])
}
model DemandSignal {
id String @id @default(cuid())
// Region scope
centerLat Float
centerLon Float
radiusKm Float
regionName String
// Time scope
periodStart DateTime
periodEnd DateTime
seasonalPeriod String // spring, summer, fall, winter
// Aggregated demand (JSON array of DemandItem)
demandItems Json
// Statistics
totalConsumers Int
totalWeeklyDemandKg Float
confidenceLevel Float
// Supply status
currentSupplyKg Float?
supplyGapKg Float?
supplyStatus SupplyStatus @default(BALANCED)
// Timestamps
timestamp DateTime @default(now())
createdAt DateTime @default(now())
// Relations
marketMatches MarketMatch[]
@@index([regionName])
@@index([periodStart, periodEnd])
@@index([supplyStatus])
}
enum SupplyStatus {
SURPLUS
BALANCED
SHORTAGE
CRITICAL
}
model SupplyCommitment {
id String @id @default(cuid())
// Grower
growerId String
grower User @relation(fields: [growerId], references: [id])
// Produce
produceType String
variety String?
// Commitment
committedQuantityKg Float
availableFrom DateTime
availableUntil DateTime
// Pricing
pricePerKg Float
currency String @default("USD")
minimumOrderKg Float @default(0)
bulkDiscountThreshold Float?
bulkDiscountPercent Float?
// Quality
certifications String[]
freshnessGuaranteeHours Int?
// Delivery
deliveryRadiusKm Float
deliveryMethods String[]
// Status
status CommitmentStatus @default(AVAILABLE)
remainingKg Float
// Timestamps
timestamp DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
marketMatches MarketMatch[]
@@index([growerId])
@@index([produceType])
@@index([status])
@@index([availableFrom, availableUntil])
}
enum CommitmentStatus {
AVAILABLE
PARTIALLY_COMMITTED
FULLY_COMMITTED
EXPIRED
}
model MarketMatch {
id String @id @default(cuid())
// Parties
consumerId String
growerId String
// Links
demandSignalId String
demandSignal DemandSignal @relation(fields: [demandSignalId], references: [id])
supplyCommitmentId String
supplyCommitment SupplyCommitment @relation(fields: [supplyCommitmentId], references: [id])
// Match details
produceType String
matchedQuantityKg Float
// Transaction
agreedPricePerKg Float
totalPrice Float
currency String @default("USD")
// Delivery
deliveryDate DateTime
deliveryMethod String
deliveryLatitude Float?
deliveryLongitude Float?
deliveryAddress String?
// Status
status MatchStatus @default(PENDING)
// Ratings
consumerRating Float?
growerRating Float?
feedback String?
// Timestamps
timestamp DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([consumerId])
@@index([growerId])
@@index([status])
@@index([deliveryDate])
}
enum MatchStatus {
PENDING
CONFIRMED
IN_TRANSIT
DELIVERED
COMPLETED
CANCELLED
}
model SeasonalPlan {
id String @id @default(cuid())
// Grower
growerId String
grower User @relation(fields: [growerId], references: [id])
// Season
year Int
season String // spring, summer, fall, winter
// Location context (JSON)
location Json
// Growing capacity (JSON)
growingCapacity Json
// Planned crops (JSON array)
plannedCrops Json
// Expected outcomes
expectedTotalYieldKg Float?
expectedRevenue Float?
expectedCarbonFootprintKg Float?
// Status
status PlanStatus @default(DRAFT)
completionPercentage Float?
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([growerId])
@@index([year, season])
@@index([status])
}
enum PlanStatus {
DRAFT
CONFIRMED
IN_PROGRESS
COMPLETED
}
model DemandForecast {
id String @id @default(cuid())
// Scope
region String
forecastPeriodStart DateTime
forecastPeriodEnd DateTime
// Forecasts (JSON array of ProduceForecast)
forecasts Json
// Model info
modelVersion String
dataPointsUsed Int
lastTrainingDate DateTime?
// Timestamps
generatedAt DateTime @default(now())
createdAt DateTime @default(now())
@@index([region])
@@index([forecastPeriodStart, forecastPeriodEnd])
}
model PlantingRecommendation {
id String @id @default(cuid())
// Grower
growerId String
// Recommendation
produceType String
variety String?
category String
// Quantities
recommendedQuantity Float
quantityUnit String
expectedYieldKg Float
yieldConfidence Float
// Timing
plantByDate DateTime
expectedHarvestStart DateTime
expectedHarvestEnd DateTime
growingDays Int
// Market opportunity
projectedDemandKg Float?
projectedPricePerKg Float?
projectedRevenue Float?
marketConfidence Float?
// Risk assessment (JSON)
riskFactors Json?
overallRisk String @default("medium")
// Reasoning
demandSignalIds String[]
explanation String?
// Timestamps
timestamp DateTime @default(now())
createdAt DateTime @default(now())
@@index([growerId])
@@index([produceType])
@@index([plantByDate])
}
// ============================================
// AUDIT & TRANSPARENCY
// ============================================
model AuditLog {
id String @id @default(cuid())
// Actor
userId String?
user User? @relation(fields: [userId], references: [id])
// Action
action String
entityType String
entityId String?
// Details
previousValue Json?
newValue Json?
metadata Json?
// Source
ipAddress String?
userAgent String?
// Timestamps
timestamp DateTime @default(now())
@@index([userId])
@@index([entityType, entityId])
@@index([action])
@@index([timestamp])
}
model BlockchainBlock {
id String @id @default(cuid())
// Block data
index Int @unique
timestamp DateTime
previousHash String
hash String @unique
nonce Int
// Block content type
blockType String // "plant" or "transport"
// Content reference
plantId String?
transportEventId String?
// Content snapshot (JSON)
content Json
// Timestamps
createdAt DateTime @default(now())
@@index([blockType])
@@index([hash])
}