import mongoose from "mongoose"; import { DEFAULT_PRODUCE_ICON, PRODUCE_ICON_IDS, } from "../../constants/produceIcons.js"; const SUNLIGHT_VALUES = ["fullSun", "partialShade", "fullShade"]; const WATER_NEEDS_VALUES = ["low", "medium", "high"]; const patchSchema = new mongoose.Schema( { deviceId: { type: mongoose.Schema.Types.ObjectId, ref: "Device", required: true, index: true, }, patchId: { type: String, required: true }, name: { type: String, default: "" }, description: { type: String, default: "" }, /** Produce icon id (basename under client assets/svg/produce). */ icon: { type: String, enum: PRODUCE_ICON_IDS, default: DEFAULT_PRODUCE_ICON, }, /** Plant grid rows on the bed visualisation. */ rows: { type: Number, default: 3, min: 1 }, /** Plant grid columns on the bed visualisation. */ columns: { type: Number, default: 8, min: 1 }, /** Growth stage passed to the plant Lottie (derived from lifecycle + time; not user-edited). */ currentGrowingPosition: { type: Number, default: 0 }, /** Withering tint 0–100 for plant Lottie (derived from lifecycle + time; not user-edited). */ currentWithering: { type: Number, default: 0 }, /** Visible leaf count 0–6 for plant Lottie (derived from lifecycle + time; not user-edited). */ currentLeaves: { type: Number, default: 0, min: 0, max: 6 }, /** Visible flower count 0–3 for plant Lottie (derived from lifecycle + time; not user-edited). */ currentFlowers: { type: Number, default: 0, min: 0, max: 3 }, /** Fruit development 0–100 for plant Lottie (derived from lifecycle + time; not user-edited). */ currentFruiting: { type: Number, default: 0, min: 0, max: 100 }, /** Active lifecycle phase name/index from last server-side recalculation. */ currentGrowingPhase: { type: new mongoose.Schema( { name: { type: String, default: "" }, index: { type: Number, default: 0 }, }, { _id: false }, ), default: null, }, soilHumidity: { type: Number, default: 0 }, soilTemperature: { type: Number, default: 21 }, sunlight: { type: String, enum: SUNLIGHT_VALUES, default: "fullSun", }, soilPhMin: { type: Number, default: 5.5, min: 0, max: 14 }, soilPhMax: { type: Number, default: 6.5, min: 0, max: 14 }, waterNeeds: { type: String, enum: WATER_NEEDS_VALUES, default: "medium", }, /** Biennial: sow/plant date anchor for offset-based lifecycle (ISO date in API). */ plantedAt: { type: Date, default: null }, /** * Biennial: { type, durationWeeks, phases[{ name, startOffsetWeeks, endOffsetWeeks, growingPosition 0–100, withering 0–100, leaves 0–6, flowers 0–3, fruiting 0–100 }] } * Perennial: { type, recurring, phases[{ name, startWeek, endWeek, growingPosition 0–100, withering 0–100, leaves 0–6, flowers 0–3, fruiting 0–100 }] } */ lifecycle: { type: mongoose.Schema.Types.Mixed, default: undefined }, /** Ordered gallery image references (see `Image` model). */ images: { type: [{ type: mongoose.Schema.Types.ObjectId, ref: "Image" }], default: [], }, }, { timestamps: true }, ); patchSchema.index({ deviceId: 1, patchId: 1 }, { unique: true }); export const Patch = mongoose.model("Patch", patchSchema);