Appearance
Epic 4 — Pet Owner Profile
BE-PETOWNER-001 — Extend PetOwnerProfile schema + Pet model
- [x] Implemented
Files:
- Edit:
prisma/schema.prisma - Run:
pnpm db:migrate - Edit:
src/graphql/schema/index.ts - Create:
src/graphql/resolvers/petOwner.ts - Edit:
src/graphql/resolvers/index.ts
Schema additions:
prisma
model PetOwnerProfile {
// existing scaffold fields stay
displayName String?
bio String?
location String?
socialLinks Json? // { instagram, tiktok, website }
pets Pet[]
dreamJobs Json? // DreamJobEntry[] — see BE-TALENT-002
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Pet {
id String @id @default(cuid())
ownerId String
owner PetOwnerProfile @relation(fields: [ownerId], references: [id], onDelete: Cascade)
// Identity
name String
species PetSpecies // DOG | CAT | BIRD | HORSE | RABBIT | REPTILE | OTHER
breed String?
gender PetGender? // MALE | FEMALE | UNKNOWN
dateOfBirth DateTime?
estimatedAge String? // fallback when exact DOB unknown: "~3 years"
colorMarkings String?
// Appearance
photos String[] @default([]) // CDN URLs, first is primary
heightCm Float?
weightKg Float?
// Casting-relevant
trainedSkills String[] @default([]) // e.g. ["sit", "roll over", "fetch"]
experienceLevel PetExperience @default(NONE) // NONE | BEGINNER | EXPERIENCED | PROFESSIONAL
hasAgentRep Boolean @default(false)
isAvailable Boolean @default(true)
// Work history
notableWorks Json? // [{ title, role, year, productionType }]
// Health & compliance
vaccinated Boolean @default(false)
insured Boolean @default(false)
certifications String[] @default([])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("pets")
}
enum PetSpecies {
DOG CAT BIRD HORSE RABBIT REPTILE OTHER
}
enum PetGender {
MALE FEMALE UNKNOWN
}
enum PetExperience {
NONE BEGINNER EXPERIENCED PROFESSIONAL
}GraphQL mutations:
graphql
createPet(input: CreatePetInput!): Pet!
updatePet(id: ID!, input: UpdatePetInput!): Pet!
deletePet(id: ID!): Boolean!GraphQL queries:
graphql
myPets: [Pet!]!
pet(id: ID!): PetAcceptance criteria:
- A PetOwner can have unlimited pets
- Only the owning user can mutate their pets (
requireProfile(ctx, 'PET_OWNER')+ ownership check) myPetsreturns all pets for the authenticated PetOwner
BE-PETOWNER-002 — Pet photo upload
- [x] Implemented
Files:
- Edit:
src/graphql/schema/index.ts— adduploadPetPhoto(petId: ID!, file: Upload!): String! - Edit:
src/graphql/resolvers/petOwner.ts - Edit:
src/services/media/index.ts
Description: Upload pet photo to S3 (castyou-media/pet-photos/{petId}/{filename}). Returns CDN URL. Appends URL to Pet.photos. Max 10 photos per pet, 5 MB each. Accepted: jpg, png, webp.
FE-PETOWNER-001 — Pet management page
- [x] Implemented
Files:
- Create:
apps/app/src/pages/petowner/PetOwnerProfilePage.tsx - Create:
apps/app/src/pages/petowner/PetsPage.tsx— list of all pets - Create:
apps/app/src/pages/petowner/PetDetailPage.tsx— view a single pet's full profile - Create:
apps/app/src/pages/petowner/PetEditPage.tsx— create / edit form - Create:
apps/app/src/lib/queries/petOwner.ts—MY_PETS_QUERY,PET_QUERY - Create:
apps/app/src/hooks/usePets.ts - Create:
apps/app/src/hooks/useCreatePet.ts,useUpdatePet.ts,useDeletePet.ts - Edit:
apps/app/src/App.tsx— add routes/pets,/pets/new,/pets/:id,/pets/:id/edit
Description: Pet management hub for PetOwner-profile users.
- Pets list (
/pets): grid of pet cards showing primary photo, name, species badge, breed, experience level badge, and availability indicator. "Add pet" CTA. UsesSkeletonduring load,EmptyStatewhen no pets yet. - Pet detail (
/pets/:id): full view — photo gallery, identity section (species, breed, age, color), casting info (trained skills asChiplist, experience level, availability), notable works, health/compliance badges. "Edit" button. - Pet edit form (
/pets/:id/editand/pets/new): single-page form with sections for identity, appearance, trained skills (MultiSelect), experience, work history, and health.FileUploadfor photos. All DS components.
Acceptance criteria:
- Only visible to users with the
PET_OWNERprofile - Route guard redirects non-PetOwners
- Photo upload wired up (BE-PETOWNER-002)
- Delete pet with confirmation dialog
FE-PETOWNER-002 — Pet card component (Design System)
- [x] Implemented
Files:
- Create:
packages/design-system/src/components/ui/PetCard.tsx - Edit:
packages/design-system/src/index.ts
Description: Reusable card for the pet grid. Shows primary photo, name, species icon, breed, experience badge, and availability dot. Mirrors the TalentCard structure. Props: pet: PetCardData, onClick, className?.