ca-grow-ops-manager/backend/prisma/schema.prisma
fullsizemalt e240ec7911 feat(phase2): Implement Phase 2 - Plant Touch Points & IPM
Added PlantTouchPoint and IPMSchedule models. Implemented touch-points and IPM controllers/routes. Updated frontend with Dashboard feed and IPM widgets.
2025-12-09 21:22:47 -08:00

392 lines
9.1 KiB
Text

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum RoleEnum {
OWNER
MANAGER
GROWER
STAFF
}
enum RoomType {
VEG
FLOWER
DRY
CURE
MOTHER
CLONE
FACILITY
}
enum TaskStatus {
PENDING
IN_PROGRESS
COMPLETED
BLOCKED
}
// Daily Walkthrough Enums
enum WalkthroughStatus {
IN_PROGRESS
COMPLETED
INCOMPLETE
}
enum TankType {
VEG
FLOWER
}
enum TankStatus {
OK
LOW
CRITICAL
}
enum HealthStatus {
GOOD
FAIR
NEEDS_ATTENTION
}
enum AccessStatus {
OK
ISSUES
}
model User {
id String @id @default(uuid())
email String @unique
passwordHash String
name String?
role RoleEnum @default(STAFF) // Kept for legacy/fallback, but relying on roleId usually
roleId String?
userRole Role? @relation(fields: [roleId], references: [id])
rate Decimal? @map("hourly_rate")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tasks Task[]
timeLogs TimeLog[]
walkthroughs DailyWalkthrough[]
touchPoints PlantTouchPoint[]
@@map("users")
}
model Role {
id String @id @default(uuid())
name String @unique
description String?
permissions Json // Store permissions as JSON: { users: { read: true, write: true }, ... }
isSystem Boolean @default(false) // System roles cannot be deleted
users User[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("roles")
}
model Room {
id String @id @default(uuid())
name String
type RoomType
sqft Float?
width Float?
length Float?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
batches Batch[]
tasks Task[]
@@map("rooms")
}
model Batch {
id String @id @default(uuid())
name String // e.g., "B-2023-10-15-GG4"
strain String
startDate DateTime
harvestDate DateTime?
status String @default("ACTIVE") // ACTIVE, HARVESTED, COMPLETED
roomId String?
room Room? @relation(fields: [roomId], references: [id])
tasks Task[]
touchPoints PlantTouchPoint[]
ipmSchedule IPMSchedule?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("batches")
}
model TaskTemplate {
id String @id @default(uuid())
title String
description String? // Instructions/SOP
roomType RoomType?
estimatedMinutes Int?
materials String[] // Array of material names
recurrence Json? // Cron or custom pattern
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tasks Task[]
@@map("task_templates")
}
model Task {
id String @id @default(uuid())
title String
description String?
status TaskStatus @default(PENDING)
priority String @default("MEDIUM")
templateId String?
template TaskTemplate? @relation(fields: [templateId], references: [id])
assignedToId String?
assignedTo User? @relation(fields: [assignedToId], references: [id])
batchId String?
batch Batch? @relation(fields: [batchId], references: [id])
roomId String?
room Room? @relation(fields: [roomId], references: [id])
dueDate DateTime?
completedAt DateTime?
notes String?
photos String[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("tasks")
}
model TimeLog {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id])
startTime DateTime
endTime DateTime?
activityType String? // e.g. "Trimming", "Feeding", "Cleaning"
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("time_logs")
}
// Daily Walkthrough Models
model DailyWalkthrough {
id String @id @default(uuid())
date DateTime @default(now())
completedBy String
user User @relation(fields: [completedBy], references: [id])
startTime DateTime @default(now())
endTime DateTime?
status WalkthroughStatus @default(IN_PROGRESS)
reservoirChecks ReservoirCheck[]
irrigationChecks IrrigationCheck[]
plantHealthChecks PlantHealthCheck[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("daily_walkthroughs")
}
model WalkthroughSettings {
id String @id @default("default")
// Photo Requirements
reservoirPhotos PhotoRequirement @default(OPTIONAL)
irrigationPhotos PhotoRequirement @default(OPTIONAL)
plantHealthPhotos PhotoRequirement @default(REQUIRED)
// Enabled Sections
enableReservoirs Boolean @default(true)
enableIrrigation Boolean @default(true)
enablePlantHealth Boolean @default(true)
updatedAt DateTime @updatedAt
@@map("walkthrough_settings")
}
enum PhotoRequirement {
REQUIRED
OPTIONAL
WEEKLY
ON_DEMAND
}
model ReservoirCheck {
id String @id @default(uuid())
walkthroughId String
walkthrough DailyWalkthrough @relation(fields: [walkthroughId], references: [id], onDelete: Cascade)
tankName String
tankType TankType
levelPercent Int
status TankStatus
photoUrl String?
notes String?
createdAt DateTime @default(now())
@@map("reservoir_checks")
}
model IrrigationCheck {
id String @id @default(uuid())
walkthroughId String
walkthrough DailyWalkthrough @relation(fields: [walkthroughId], references: [id], onDelete: Cascade)
zoneName String // "Veg Upstairs", "Veg Downstairs", "Flower Upstairs", "Flower Downstairs"
drippersTotal Int
drippersWorking Int
drippersFailed String? // JSON array of failed dripper IDs
waterFlow Boolean
nutrientsMixed Boolean
scheduleActive Boolean
photoUrl String? // Photo of working system
issues String?
createdAt DateTime @default(now())
@@map("irrigation_checks")
}
model PlantHealthCheck {
id String @id @default(uuid())
walkthroughId String
walkthrough DailyWalkthrough @relation(fields: [walkthroughId], references: [id], onDelete: Cascade)
zoneName String
healthStatus HealthStatus
pestsObserved Boolean
pestType String?
waterAccess AccessStatus
foodAccess AccessStatus
flaggedForAttention Boolean @default(false)
issuePhotoUrl String?
referencePhotoUrl String? // Photo of healthy system
notes String?
createdAt DateTime @default(now())
@@map("plant_health_checks")
}
// Supply/Shopping List models
model SupplyItem {
id String @id @default(uuid())
name String
category SupplyCategory
quantity Int @default(0)
minThreshold Int @default(0)
unit String // "each", "box", "roll", "gallon", etc.
location String? // "Storage Room", "Bathroom", etc.
vendor String? // "Amazon", "Local", etc.
productUrl String? // Link to reorder
lastOrdered DateTime?
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("supply_items")
}
enum SupplyCategory {
FILTER // Air filters, water filters
CLEANING // Cleaning supplies
PPE // Gloves, masks, suits
OFFICE // Paper, pens, etc.
BATHROOM // Toilet paper, soap, etc.
KITCHEN // Coffee, snacks, etc.
MAINTENANCE // Tools, parts, etc.
OTHER
}
// Plant Touch Points
model PlantTouchPoint {
id String @id @default(uuid())
type TouchType
notes String?
photoUrls String[] // Changed from single photoUrl to array
// Measurements
heightCm Float?
widthCm Float?
// IPM specific
ipmProduct String? // e.g., "Pyganic 5.0"
ipmDosage String? // e.g., "1 oz per gallon"
// Issues
issuesObserved Boolean @default(false)
issueType String?
batchId String
batch Batch @relation(fields: [batchId], references: [id])
createdBy String
user User @relation(fields: [createdBy], references: [id])
createdAt DateTime @default(now())
@@map("plant_touch_points")
}
enum TouchType {
WATER
FEED
PRUNE
TRAIN
INSPECT
IPM
TRANSPLANT
HARVEST
OTHER
}
model IPMSchedule {
id String @id @default(uuid())
batchId String @unique // One schedule per batch
batch Batch @relation(fields: [batchId], references: [id])
product String // "Pyganic 5.0"
intervalDays Int // 10
lastTreatment DateTime?
nextTreatment DateTime? // Calculated
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("ipm_schedules")
}