From 612c0467a1eab858aa2283af18151ef2ebadeefe Mon Sep 17 00:00:00 2001 From: Flea Flicker Date: Fri, 29 May 2026 01:14:56 +0000 Subject: [PATCH] feat(seed): populate extended pet profile fields for UAT regression GRO-1898: Ensure UAT seed data includes clients and pets with extended profile fields (temperamentScore, temperamentFlags, medicalAlerts, preferredCuts, coatType). - Add data pools for extended profile fields in pet batch generation - Populate all 5 extended fields for randomly generated pets - Update UAT test client pets with fully populated extended profiles - Fix type mismatches: medicalAlerts uses MedicalAlert[] with {type, description, severity} shape per @groombook/types Co-Authored-By: Claude Opus 4.7 --- apps/api/src/db/seed.ts | 80 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 7 deletions(-) diff --git a/apps/api/src/db/seed.ts b/apps/api/src/db/seed.ts index 566da17..fc65098 100644 --- a/apps/api/src/db/seed.ts +++ b/apps/api/src/db/seed.ts @@ -20,6 +20,7 @@ import postgres from "postgres"; import { drizzle } from "drizzle-orm/postgres-js"; import { eq, and, sql } from "drizzle-orm"; import * as schema from "./schema.js"; +import type { MedicalAlert, MedicalAlertSeverity } from "./schema.js"; // ── Seed profile configuration ───────────────────────────────────────────── @@ -252,6 +253,38 @@ const appointmentNotes = [ "Client running late, pushed start by 15min", ]; +const temperamentScores = [3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9]; + +const temperamentFlags = [ + [], ["anxious"], ["friendly"], ["nippy"], ["anxious", "sensitive"], + ["friendly", "calm"], ["nippy", "territorial"], ["calm"], ["sensitive"], + ["friendly", "nippy"], ["anxious", "territorial"], +]; + +const medicalAlertsList = [ + [] as MedicalAlert[], + [] as MedicalAlert[], + [{ type: "skin", description: "Sensitive skin — avoid harsh shampoos", severity: "medium" as MedicalAlertSeverity }], + [{ type: "ear", description: "Ear infection prone — dry ears thoroughly", severity: "medium" as MedicalAlertSeverity }], + [{ type: "mobility", description: "Hip dysplasia — handle with care", severity: "high" as MedicalAlertSeverity }], + [{ type: "behavioral", description: "Anxious — needs slow approach", severity: "low" as MedicalAlertSeverity }], + [{ type: "medical", description: "Seizure history — avoid stress triggers", severity: "high" as MedicalAlertSeverity }], + [{ type: "skin", description: "Skin allergies — use hypoallergenic products only", severity: "medium" as MedicalAlertSeverity }], + [{ type: "behavioral", description: "Aggressive when nails trimmed — muzzle required", severity: "high" as MedicalAlertSeverity }], + [{ type: "cardiac", description: "Heart murmur — monitor during grooming", severity: "high" as MedicalAlertSeverity }], + [{ type: "dietary", description: "Diabetic — owner brings treats", severity: "medium" as MedicalAlertSeverity }], +]; + +const preferredCutsList = [ + [], ["Puppy Cut"], ["Teddy Bear Cut"], ["Breed Standard"], + ["Puppy Cut", "Sanitary Trim"], ["Full Groom"], ["Lion Cut"], + ["Kennel Cut", "Face & Feet Trim"], ["Teddy Bear Cut", "Sanitary Trim"], + ["Breed Standard", "Sanitary Trim"], ["Summer Shave"], + ["Puppy Cut", "Face & Feet Trim", "Sanitary Trim"], +]; + +const coatTypes: string[] = ["short", "medium", "long", "curly", "wire", "double", "silky"]; + const visitLogNotes = [ null, null, "Coat in great condition", @@ -872,6 +905,11 @@ async function seed() { cutStyle: pick(cutStyles), shampooPreference: pick(shampoos), specialCareNotes: rand() < 0.1 ? "Vet clearance required before grooming" : null, + coatType: pick(coatTypes), + temperamentScore: pick(temperamentScores), + temperamentFlags: pick(temperamentFlags), + medicalAlerts: pick(medicalAlertsList), + preferredCuts: pick(preferredCutsList), customFields: {}, image: petIndex < 250 ? pick(puggleImages) : pick(demoPetImages), }); @@ -907,6 +945,11 @@ async function seed() { cutStyle: pet.cutStyle, shampooPreference: pet.shampooPreference, specialCareNotes: pet.specialCareNotes, + coatType: pet.coatType, + temperamentScore: pet.temperamentScore, + temperamentFlags: pet.temperamentFlags, + medicalAlerts: pet.medicalAlerts, + preferredCuts: pet.preferredCuts, customFields: pet.customFields, image: pet.image, }, @@ -929,13 +972,18 @@ async function seed() { petId: string; petName: string; petBreed: string; + petCoatType: string; + petTemperamentScore: number; + petTemperamentFlags: string[]; + petMedicalAlerts: MedicalAlert[]; + petPreferredCuts: string[]; } const uatClients: UatClient[] = [ - { id: uuid(), name: "UAT Test Alpha", email: "uat-alpha@groombook.dev", phone: "(555) 100-0001", address: "100 Test Lane, Springfield, CA 90210", petId: uuid(), petName: "TestBuddy", petBreed: "Golden Retriever" }, - { id: uuid(), name: "UAT Test Bravo", email: "uat-bravo@groombook.dev", phone: "(555) 100-0002", address: "200 Test Lane, Springfield, CA 90210", petId: uuid(), petName: "TestMax", petBreed: "Labrador Retriever" }, - { id: uuid(), name: "UAT Test Charlie", email: "uat-charlie@groombook.dev", phone: "(555) 100-0003", address: "300 Test Lane, Springfield, CA 90210", petId: uuid(), petName: "TestCooper", petBreed: "Poodle" }, - { id: uuid(), name: "UAT Test Delta", email: "uat-delta@groombook.dev", phone: "(555) 100-0004", address: "400 Test Lane, Springfield, CA 90210", petId: uuid(), petName: "TestRocky", petBreed: "French Bulldog" }, - { id: uuid(), name: "UAT Test Echo", email: "uat-echo@groombook.dev", phone: "(555) 100-0005", address: "500 Test Lane, Springfield, CA 90210", petId: uuid(), petName: "TestDuke", petBreed: "Beagle" }, + { id: uuid(), name: "UAT Test Alpha", email: "uat-alpha@groombook.dev", phone: "(555) 100-0001", address: "100 Test Lane, Springfield, CA 90210", petId: uuid(), petName: "TestBuddy", petBreed: "Golden Retriever", petCoatType: "double", petTemperamentScore: 7, petTemperamentFlags: ["calm", "friendly"], petMedicalAlerts: [] as MedicalAlert[], petPreferredCuts: ["Breed Standard"] }, + { id: uuid(), name: "UAT Test Bravo", email: "uat-bravo@groombook.dev", phone: "(555) 100-0002", address: "200 Test Lane, Springfield, CA 90210", petId: uuid(), petName: "TestMax", petBreed: "Labrador Retriever", petCoatType: "short", petTemperamentScore: 8, petTemperamentFlags: ["friendly"], petMedicalAlerts: [] as MedicalAlert[], petPreferredCuts: ["Bath & Brush", "Sanitary Trim"] }, + { id: uuid(), name: "UAT Test Charlie", email: "uat-charlie@groombook.dev", phone: "(555) 100-0003", address: "300 Test Lane, Springfield, CA 90210", petId: uuid(), petName: "TestCooper", petBreed: "Poodle", petCoatType: "curly", petTemperamentScore: 9, petTemperamentFlags: ["calm"], petMedicalAlerts: [{ type: "behavioral", description: "Anxious — needs slow approach", severity: "low" as MedicalAlertSeverity }], petPreferredCuts: ["Teddy Bear Cut"] }, + { id: uuid(), name: "UAT Test Delta", email: "uat-delta@groombook.dev", phone: "(555) 100-0004", address: "400 Test Lane, Springfield, CA 90210", petId: uuid(), petName: "TestRocky", petBreed: "French Bulldog", petCoatType: "short", petTemperamentScore: 6, petTemperamentFlags: ["nippy"], petMedicalAlerts: [{ type: "skin", description: "Sensitive skin — avoid harsh shampoos", severity: "medium" as MedicalAlertSeverity }], petPreferredCuts: ["Puppy Cut"] }, + { id: uuid(), name: "UAT Test Echo", email: "uat-echo@groombook.dev", phone: "(555) 100-0005", address: "500 Test Lane, Springfield, CA 90210", petId: uuid(), petName: "TestDuke", petBreed: "Beagle", petCoatType: "short", petTemperamentScore: 7, petTemperamentFlags: ["friendly", "energetic"], petMedicalAlerts: [] as MedicalAlert[], petPreferredCuts: ["Full Groom", "Nail Trim"] }, ]; for (const uc of uatClients) { @@ -943,8 +991,26 @@ async function seed() { .values({ id: uc.id, name: uc.name, email: uc.email, phone: uc.phone, address: uc.address }) .onConflictDoUpdate({ target: schema.clients.id, set: { name: uc.name, email: uc.email, phone: uc.phone, address: uc.address } }); await db.insert(schema.pets) - .values({ id: uc.petId, clientId: uc.id, name: uc.petName, species: "Dog", breed: uc.petBreed, weightKg: "25.00", dateOfBirth: new Date("2021-03-15T00:00:00Z"), image: pick(demoPetImages) }) - .onConflictDoUpdate({ target: schema.pets.id, set: { clientId: uc.id, name: uc.petName, species: "Dog", breed: uc.petBreed, weightKg: "25.00", dateOfBirth: new Date("2021-03-15T00:00:00Z"), image: pick(demoPetImages) } }); + .values({ + id: uc.petId, clientId: uc.id, name: uc.petName, species: "Dog", breed: uc.petBreed, + weightKg: "25.00", dateOfBirth: new Date("2021-03-15T00:00:00Z"), + coatType: uc.petCoatType, + temperamentScore: uc.petTemperamentScore, + temperamentFlags: uc.petTemperamentFlags, + medicalAlerts: uc.petMedicalAlerts, + preferredCuts: uc.petPreferredCuts, + image: pick(demoPetImages), + }) + .onConflictDoUpdate({ target: schema.pets.id, set: { + clientId: uc.id, name: uc.petName, species: "Dog", breed: uc.petBreed, + weightKg: "25.00", dateOfBirth: new Date("2021-03-15T00:00:00Z"), + coatType: uc.petCoatType, + temperamentScore: uc.petTemperamentScore, + temperamentFlags: uc.petTemperamentFlags, + medicalAlerts: uc.petMedicalAlerts, + preferredCuts: uc.petPreferredCuts, + image: pick(demoPetImages), + } }); // Create one completed appointment for this client const apptId = uuid(); const svcIdx = 0;