v0.11.0 — Plant types: the reusable "kind" record
A rich-but-all-optional reference record per kind of plant (care, sun, water, bloom & harvest windows, toxic-to-pets, edible parts, spacing), distinct from a specific planting or a group. - PlantType model + optional Plant.plantTypeId; migration + idempotent backfill that seeds 247 kinds from the built-in plant library and links plantings by species/common name (wired into the deploy entrypoint) - /api/plant-types CRUD; new "Plant types" section (browse by category, edit a kind, see every spot you've planted it) - New plants auto-link to their type on create; plant detail shows "More about…" - PlantType added to backup/restore; bump APP_VERSION 0.11.0 + changelog Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
-- v0.11.0 — Plant types (the "kind" record)
|
||||
-- A rich-but-all-optional reference record per kind of plant, plus an optional
|
||||
-- link from each planting. Seeded/linked by prisma/scripts/backfill-plant-types.ts.
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PlantType" (
|
||||
"id" TEXT NOT NULL,
|
||||
"commonName" TEXT NOT NULL,
|
||||
"species" TEXT,
|
||||
"category" "PlantCategory" NOT NULL DEFAULT 'OTHER',
|
||||
"careNotes" TEXT,
|
||||
"sun" TEXT,
|
||||
"water" TEXT,
|
||||
"bloomStart" INTEGER,
|
||||
"bloomEnd" INTEGER,
|
||||
"harvestStart" INTEGER,
|
||||
"harvestEnd" INTEGER,
|
||||
"toxicToPets" BOOLEAN,
|
||||
"edibleParts" TEXT,
|
||||
"spacing" TEXT,
|
||||
"imageUrl" TEXT,
|
||||
"notes" TEXT,
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "PlantType_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PlantType_commonName_idx" ON "PlantType"("commonName");
|
||||
CREATE INDEX "PlantType_category_idx" ON "PlantType"("category");
|
||||
CREATE INDEX "PlantType_active_idx" ON "PlantType"("active");
|
||||
|
||||
-- AlterTable: optional link from a planting to its kind
|
||||
ALTER TABLE "Plant" ADD COLUMN "plantTypeId" TEXT;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Plant_plantTypeId_idx" ON "Plant"("plantTypeId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Plant" ADD CONSTRAINT "Plant_plantTypeId_fkey" FOREIGN KEY ("plantTypeId") REFERENCES "PlantType"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -126,6 +126,8 @@ model Plant {
|
||||
zone String? // legacy freeform location — kept during the Location migration (dropped in Release B)
|
||||
locationId String? // shared Location spine
|
||||
location Location? @relation(fields: [locationId], references: [id], onDelete: SetNull)
|
||||
plantTypeId String? // optional link to the "kind" reference record
|
||||
plantType PlantType? @relation(fields: [plantTypeId], references: [id], onDelete: SetNull)
|
||||
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
|
||||
@@ -141,10 +143,42 @@ model Plant {
|
||||
@@index([category])
|
||||
@@index([zone])
|
||||
@@index([locationId])
|
||||
@@index([plantTypeId])
|
||||
@@index([active])
|
||||
@@index([groupId])
|
||||
}
|
||||
|
||||
// PlantType — the "kind" of plant (e.g. "Lily of the valley"), holding general
|
||||
// reusable reference info. Rich but every field optional; seeded from the
|
||||
// built-in plant library (src/lib/garden/plant-db.ts). Individual Plant rows
|
||||
// optionally point at their type.
|
||||
model PlantType {
|
||||
id String @id @default(cuid())
|
||||
commonName String
|
||||
species String? // scientific name
|
||||
category PlantCategory @default(OTHER)
|
||||
careNotes String? // general care: pruning, watering, feeding
|
||||
sun String? // "Full sun", "Part shade", "Shade"
|
||||
water String? // "Low", "Moderate", "High"
|
||||
bloomStart Int? // month 1–12
|
||||
bloomEnd Int? // month 1–12
|
||||
harvestStart Int? // month 1–12
|
||||
harvestEnd Int? // month 1–12
|
||||
toxicToPets Boolean? // null = unknown
|
||||
edibleParts String? // "Fruit, young leaves"
|
||||
spacing String? // "10–15 ft", "18 in"
|
||||
imageUrl String?
|
||||
notes String?
|
||||
active Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
plants Plant[]
|
||||
|
||||
@@index([commonName])
|
||||
@@index([category])
|
||||
@@index([active])
|
||||
}
|
||||
|
||||
enum PlantLogType {
|
||||
OBSERVATION // general note — "looking healthy", "saw first flowers"
|
||||
CARE // watering, mulching, pruning, fertilizing, chop-and-drop
|
||||
|
||||
23
prisma/scripts/backfill-plant-types.ts
Normal file
23
prisma/scripts/backfill-plant-types.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* v0.11.0 Plant-type backfill. Seeds the PlantType library from the built-in
|
||||
* plant DB and links existing plantings to their kind. Idempotent — runs on
|
||||
* deploy (docker-entrypoint.sh) and can be run manually:
|
||||
*
|
||||
* npx tsx prisma/scripts/backfill-plant-types.ts
|
||||
*/
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { syncPlantTypesFromLibrary } from "../../src/lib/garden/plant-types";
|
||||
|
||||
const db = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
const r = await syncPlantTypesFromLibrary(db);
|
||||
console.log(`Plant types: library has ${r.types} kinds; linked ${r.linked} planting(s).`);
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error("Plant-type backfill failed:", e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(() => db.$disconnect());
|
||||
@@ -1,5 +1,6 @@
|
||||
import { PrismaClient, PlantCategory } from "@prisma/client";
|
||||
import { hashSync } from "bcryptjs";
|
||||
import { syncPlantTypesFromLibrary } from "../src/lib/garden/plant-types";
|
||||
|
||||
const db = new PrismaClient();
|
||||
|
||||
@@ -87,6 +88,10 @@ async function main() {
|
||||
});
|
||||
}
|
||||
|
||||
// Seed the PlantType library and link the sample plants to their kind.
|
||||
const pt = await syncPlantTypesFromLibrary(db);
|
||||
console.log(`Seeded ${pt.types} plant types; linked ${pt.linked} plantings.`);
|
||||
|
||||
console.log("Demo seed complete.");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user