185 lines
5.9 KiB
Plaintext
185 lines
5.9 KiB
Plaintext
// Moon Base — property management for the Moon homestead.
|
||
// Tracks the food forest (plants, care logs, harvests), home maintenance,
|
||
// and equipment. v0.1 ships the garden module; home + equipment come next.
|
||
|
||
generator client {
|
||
provider = "prisma-client-js"
|
||
}
|
||
|
||
datasource db {
|
||
provider = "postgresql"
|
||
url = env("DATABASE_URL")
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Auth
|
||
// ---------------------------------------------------------------------------
|
||
|
||
enum UserRole {
|
||
ADMIN // full access — add/edit/delete anything
|
||
MEMBER // can log observations and care, but not delete records
|
||
}
|
||
|
||
model User {
|
||
id String @id @default(cuid())
|
||
email String @unique
|
||
username String? @unique
|
||
name String
|
||
passwordHash String
|
||
role UserRole @default(MEMBER)
|
||
active Boolean @default(true)
|
||
mustChangePassword Boolean @default(false)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Audit log — append-only, every mutation lands here
|
||
// ---------------------------------------------------------------------------
|
||
|
||
model AuditEvent {
|
||
id String @id @default(cuid())
|
||
action String // e.g. "plant.create", "plant.log.add"
|
||
entityId String?
|
||
actorId String?
|
||
payload Json?
|
||
createdAt DateTime @default(now())
|
||
|
||
@@index([entityId])
|
||
@@index([createdAt])
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Garden — food forest plant registry
|
||
// ---------------------------------------------------------------------------
|
||
|
||
enum PlantCategory {
|
||
CANOPY_TREE // apple, pear, cherry, walnut — the tall ones
|
||
UNDERSTORY_TREE // serviceberry, elderberry, pawpaw
|
||
LARGE_SHRUB // hazelnuts, currants, gooseberries
|
||
SHRUB // roses, raspberries, blueberries
|
||
HERB // comfrey, yarrow, mint, chives
|
||
GROUNDCOVER // strawberries, clover, creeping thyme
|
||
VINE // grapes, hops, kiwi
|
||
ANNUAL_VEGETABLE // tomatoes, squash, beans, peppers — seasonal veg
|
||
ANNUAL // legacy, treated as annual vegetable
|
||
ANNUAL_FLOWER // zinnias, marigolds, nasturtiums, cosmos
|
||
PERENNIAL // asparagus, rhubarb, perennial veg
|
||
PERENNIAL_FLOWER // coneflower, bee balm, black-eyed susan
|
||
BULB // garlic, onions, tulips, daffodils
|
||
MUSHROOM // shiitake log, oyster bed, etc.
|
||
OTHER
|
||
}
|
||
|
||
model PlantGroup {
|
||
id String @id @default(cuid())
|
||
name String @unique
|
||
notes String?
|
||
active Boolean @default(true)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
plants Plant[]
|
||
|
||
@@index([active])
|
||
}
|
||
|
||
model Plant {
|
||
id String @id @default(cuid())
|
||
commonName String
|
||
species String? // scientific name (optional)
|
||
variety String? // cultivar / variety name
|
||
category PlantCategory
|
||
zone String? // location on the property, freeform ("Back fence guild", "Front yard")
|
||
plantedAt DateTime? // when it went in the ground
|
||
source String? // where it came from ("Jung's Nursery", "from seed", "division from Mom's")
|
||
notes String? // general notes about this plant
|
||
groupId String? // optional: belongs to a PlantGroup (e.g. "Irises")
|
||
group PlantGroup? @relation(fields: [groupId], references: [id])
|
||
imageUrl String? // thumbnail fetched from Wikipedia on add/edit
|
||
active Boolean @default(true)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
logs PlantLog[]
|
||
tasks Task[]
|
||
|
||
@@index([category])
|
||
@@index([zone])
|
||
@@index([active])
|
||
@@index([groupId])
|
||
}
|
||
|
||
enum PlantLogType {
|
||
OBSERVATION // general note — "looking healthy", "saw first flowers"
|
||
CARE // watering, mulching, pruning, fertilizing, chop-and-drop
|
||
HARVEST // picked fruit, veg, herb, flower
|
||
TREATMENT // pest or disease treatment
|
||
TRANSPLANT // moved to a different spot
|
||
DIED // plant died or was removed
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Tasks / reminders
|
||
// ---------------------------------------------------------------------------
|
||
|
||
enum TaskCategory {
|
||
GARDEN
|
||
HOME
|
||
EQUIPMENT
|
||
OTHER
|
||
}
|
||
|
||
enum RecurrenceType {
|
||
ONCE // one-time task, no repeat
|
||
CUSTOM // every N days (intervalDays)
|
||
MONTHLY // same day every month (uses nextDue day-of-month)
|
||
YEARLY // same month every year (month field)
|
||
}
|
||
|
||
model Task {
|
||
id String @id @default(cuid())
|
||
title String
|
||
notes String?
|
||
category TaskCategory @default(GARDEN)
|
||
plantId String?
|
||
plant Plant? @relation(fields: [plantId], references: [id])
|
||
recurrence RecurrenceType @default(YEARLY)
|
||
intervalDays Int? // for CUSTOM: every N days
|
||
month Int? // 1–12: for YEARLY, which month
|
||
nextDue DateTime
|
||
lastDone DateTime?
|
||
active Boolean @default(true)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
completions TaskCompletion[]
|
||
|
||
@@index([nextDue])
|
||
@@index([plantId])
|
||
@@index([active])
|
||
}
|
||
|
||
model TaskCompletion {
|
||
id String @id @default(cuid())
|
||
taskId String
|
||
task Task @relation(fields: [taskId], references: [id])
|
||
doneAt DateTime @default(now())
|
||
notes String?
|
||
actorId String?
|
||
|
||
@@index([taskId])
|
||
}
|
||
|
||
model PlantLog {
|
||
id String @id @default(cuid())
|
||
plantId String
|
||
plant Plant @relation(fields: [plantId], references: [id])
|
||
type PlantLogType
|
||
date DateTime @default(now())
|
||
notes String?
|
||
quantity String? // freeform for harvests: "2 lbs", "1 gallon", "a big handful"
|
||
actorId String?
|
||
createdAt DateTime @default(now())
|
||
|
||
@@index([plantId])
|
||
@@index([date])
|
||
}
|