feat(seed): populate extended pet profile fields for UAT verification #99
@@ -50,4 +50,5 @@ CMD ["pnpm", "--filter", "@groombook/db", "seed"]
|
||||
|
||||
# Reset stage — drops all tables, re-runs migrations, and re-seeds
|
||||
FROM builder AS reset
|
||||
RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
|
||||
CMD ["pnpm", "--filter", "@groombook/db", "reset"]
|
||||
|
||||
+114
-2
@@ -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 } from "@groombook/types";
|
||||
|
||||
// ── Seed profile configuration ─────────────────────────────────────────────
|
||||
|
||||
@@ -243,6 +244,55 @@ const groomingNotes = [
|
||||
"Previous clipper burn — be gentle on belly",
|
||||
];
|
||||
|
||||
// ── Extended pet profile pools ─────────────────────────────────────────────────
|
||||
|
||||
const temperamentFlagPool: string[] = [
|
||||
"friendly",
|
||||
"anxious-with-strangers",
|
||||
"good-with-kids",
|
||||
"leash-reactive",
|
||||
"vocal",
|
||||
"high-energy",
|
||||
"calm-on-table",
|
||||
"treat-motivated",
|
||||
];
|
||||
|
||||
const medicalAlertPool: MedicalAlert[] = [
|
||||
{ id: "", type: "allergies", description: "Seasonal allergies — monitor skin", severity: "low" },
|
||||
{ id: "", type: "allergies", description: "Chicken allergy — avoid poultry-based treats", severity: "high" },
|
||||
{ id: "", type: "joint", description: "Hip dysplasia — handle with care", severity: "medium" },
|
||||
{ id: "", type: "joint", description: "Arthritis — anti-inflammatory medication on file", severity: "medium" },
|
||||
{ id: "", type: "dental", description: "Dental disease — extractions in history", severity: "medium" },
|
||||
{ id: "", type: "dental", description: "Baby teeth retained — vet monitor", severity: "low" },
|
||||
{ id: "", type: "heart", description: "Heart murmur grade II — avoid stress", severity: "high" },
|
||||
{ id: "", type: "heart", description: "Murmur cleared by vet last year", severity: "low" },
|
||||
{ id: "", type: "other", description: "Eye ulcer history — be careful around face", severity: "medium" },
|
||||
{ id: "", type: "other", description: "Seizure history — avoid flashing lights", severity: "high" },
|
||||
{ id: "", type: "other", description: "Luxating patella — short walks only", severity: "medium" },
|
||||
{ id: "", type: "other", description: "Ear infections — dry thoroughly after bath", severity: "low" },
|
||||
];
|
||||
|
||||
const preferredCutPool: string[] = [
|
||||
"Puppy Cut",
|
||||
"Teddy Bear Cut",
|
||||
"Lion Cut",
|
||||
"Breed Standard",
|
||||
"Summer Shave",
|
||||
"Kennel Cut",
|
||||
"Lamb Cut",
|
||||
"Continental Clip",
|
||||
"Sporting Clip",
|
||||
"Sanitary Trim",
|
||||
"Face & Feet Trim",
|
||||
"Full Groom",
|
||||
];
|
||||
|
||||
type CoatType = schema.coatTypeEnum.enumValues[number];
|
||||
type PetSizeCategory = schema.petSizeCategoryEnum.enumValues[number];
|
||||
|
||||
const coatTypePool: CoatType[] = ["short", "medium", "long", "double", "wire", "silky", "curly", "hairless"];
|
||||
const petSizeCategoryPool: PetSizeCategory[] = ["small", "medium", "large", "extra_large"];
|
||||
|
||||
const appointmentNotes = [
|
||||
null, null, null, null,
|
||||
"Client requested extra brushing",
|
||||
@@ -853,6 +903,18 @@ async function seed() {
|
||||
specialCareNotes: rand() < 0.1 ? "Vet clearance required before grooming" : null,
|
||||
customFields: {},
|
||||
image: petIndex < 250 ? pick(puggleImages) : pick(demoPetImages),
|
||||
temperamentScore: randInt(1, 5),
|
||||
temperamentFlags: pickN(temperamentFlagPool, randInt(1, 3)),
|
||||
medicalAlerts: (() => {
|
||||
if (rand() < 0.3) {
|
||||
const count = rand() < 0.7 ? 1 : 2;
|
||||
return pickN(medicalAlertPool, count).map((a) => ({ ...a, id: uuid() }));
|
||||
}
|
||||
return [];
|
||||
})(),
|
||||
preferredCuts: pickN(preferredCutPool, randInt(1, 2)),
|
||||
coatType: pick(coatTypePool),
|
||||
petSizeCategory: pick(petSizeCategoryPool),
|
||||
});
|
||||
|
||||
petRecords.push({ id: petId, clientId });
|
||||
@@ -888,6 +950,12 @@ async function seed() {
|
||||
specialCareNotes: pet.specialCareNotes,
|
||||
customFields: pet.customFields,
|
||||
image: pet.image,
|
||||
temperamentScore: pet.temperamentScore,
|
||||
temperamentFlags: pet.temperamentFlags,
|
||||
medicalAlerts: pet.medicalAlerts,
|
||||
preferredCuts: pet.preferredCuts,
|
||||
coatType: pet.coatType,
|
||||
petSizeCategory: pet.petSizeCategory,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -922,8 +990,52 @@ 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"),
|
||||
image: pick(demoPetImages),
|
||||
temperamentScore: randInt(1, 5),
|
||||
temperamentFlags: pickN(temperamentFlagPool, randInt(1, 3)),
|
||||
medicalAlerts: (() => {
|
||||
if (rand() < 0.3) {
|
||||
const count = rand() < 0.7 ? 1 : 2;
|
||||
return pickN(medicalAlertPool, count).map((a) => ({ ...a, id: uuid() }));
|
||||
}
|
||||
return [];
|
||||
})(),
|
||||
preferredCuts: pickN(preferredCutPool, randInt(1, 2)),
|
||||
coatType: pick(coatTypePool),
|
||||
petSizeCategory: pick(petSizeCategoryPool),
|
||||
})
|
||||
.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),
|
||||
temperamentScore: randInt(1, 5),
|
||||
temperamentFlags: pickN(temperamentFlagPool, randInt(1, 3)),
|
||||
medicalAlerts: (() => {
|
||||
if (rand() < 0.3) {
|
||||
const count = rand() < 0.7 ? 1 : 2;
|
||||
return pickN(medicalAlertPool, count).map((a) => ({ ...a, id: uuid() }));
|
||||
}
|
||||
return [];
|
||||
})(),
|
||||
preferredCuts: pickN(preferredCutPool, randInt(1, 2)),
|
||||
coatType: pick(coatTypePool),
|
||||
petSizeCategory: pick(petSizeCategoryPool),
|
||||
},
|
||||
});
|
||||
// Create one completed appointment for this client
|
||||
const apptId = uuid();
|
||||
const svcIdx = 0;
|
||||
|
||||
Reference in New Issue
Block a user