Skip to content

Epic 2 — Talent Profile


BE-TALENT-001 — Extend TalentProfile schema (full spec fields)

  • [x] Implemented

Files:

  • Edit: prisma/schema.prisma — add all missing fields
  • Run: pnpm db:migrate
  • Edit: src/graphql/schema/index.ts — add fields to TalentProfile type and UpdateTalentProfileInput
  • Edit: src/graphql/resolvers/talent.ts

New fields to add to TalentProfile:

prisma
dateOfBirth     DateTime?
nationality     String[]   @default([])
race            String?
tattoos         Boolean    @default(false)
piercings       Boolean    @default(false)
specialPhysicalSkills String[] @default([])
languages       Json?      // [{ language, proficiency, accents }]
talentHierarchy Json?      // { primary, skills[], specialties[] }
experienceEntries Json?    // [{ productionType, subtype, genre, title, year, role }]
notableWorks    Json?      // [{ title, role, year, platform }]
awards          Json?      // [{ name, year, category }]
affiliations    Json?      // { studios[], networks[], productionHouses[] }
willingToRelocate Boolean  @default(false)
relocateConditions String?
availabilityType String    @default("AVAILABLE") // AVAILABLE | UNAVAILABLE | FREELANCE
profileCompleteness Int    @default(0)
headlinePhoto   String?

BE-TALENT-002 — Dream jobs / dream roles (OMDb-backed tags)

  • [x] Implemented

Files:

  • Edit: prisma/schema.prisma — replace dreamGigs String[] on TalentProfile and add equivalent field to PetOwnerProfile
  • Run: pnpm db:migrate
  • Edit: src/graphql/schema/index.ts — add DreamJob type, input, and resolvers
  • Edit: src/graphql/resolvers/talent.ts
  • Create: src/graphql/resolvers/petOwner.ts — same mutations for PetOwnerProfile

Schema change:

Replace dreamGigs String[] on TalentProfile (and add the equivalent field on PetOwnerProfile) with a JSON array of structured entries:

prisma
dreamJobs Json? // DreamJobEntry[] — see type below

Each entry is a JSON object stored inline (no separate table needed at this scale):

ts
type DreamJobEntry = {
  imdbId: string;       // e.g. "tt0944947"
  title: string;        // "Game of Thrones"
  type: 'movie' | 'series' | 'episode';
  year: string;         // "2011–2019"
  posterUrl: string | null;
  role?: string;        // optional: specific character/role name the user wants
}

New GraphQL mutation (both Talent and PetOwner):

graphql
updateDreamJobs(jobs: [DreamJobInput!]!): TalentProfile!   # or PetOwnerProfile!
graphql
input DreamJobInput {
  imdbId:    String!
  title:     String!
  type:      String!
  year:      String!
  posterUrl: String
  role:      String
}

Notes:

  • The OMDb API (https://www.omdbapi.com) is the public interface to IMDb data. It has a free tier (1,000 req/day) and a paid tier. Requires an API key stored as OMDB_API_KEY in the backend .env.
  • Search is done client-side via a direct call to the OMDb API from the frontend (avoids proxying search traffic through the backend). The backend only stores the final selected entries.
  • Guard: max 20 dream jobs per profile.
  • Migration: the existing dreamGigs String[] data should be preserved as-is in a dreamGigsLegacy String[] field until a data migration script converts free-text entries.

BE-TALENT-003 — Profile completeness score calculation

  • [x] Implemented

Files:

  • Create: src/services/talent/completeness.ts
  • Edit: src/services/talent/index.ts — call completeness update after any profile update

Description: After every updateTalentProfile, recalculate and store profileCompleteness (0–100). Scoring weights: headlinePhoto (15), displayName+bio (10), primaryCategory+skills (15), location (5), languages (5), physicalAttributes (10), experienceEntries (15), notableWorks (10), mediaItems/reel (15).


BE-TALENT-003 — Talent profile photo upload

  • [x] Implemented

Files:

  • Edit: src/services/media/index.ts — implement uploadProfilePhoto(userId, file) with S3 put + CDN URL
  • Edit: src/graphql/schema/index.ts — add uploadProfilePhoto(file: Upload!): String!
  • Edit: src/graphql/resolvers/talent.ts

Description: Upload profile photo to S3 (castyou-media/profile-photos/{userId}.{ext}). Return CDN URL. Update TalentProfile.headlinePhoto. Max size 5 MB. Accepted: jpg, png, webp.


FE-TALENT-001 — Talent profile view page

  • [x] Implemented

Files:

  • Create: apps/app/src/pages/talent/TalentProfilePage.tsx
  • Create: apps/app/src/lib/queries/talent.tsGET_TALENT_PROFILE query
  • Create: apps/app/src/hooks/useTalentProfile.ts
  • Edit: apps/app/src/App.tsx — add route /talent/:id

Description: Public view of a talent's full profile (seen by producers). Sections: hero (photo, name, category, location, match score), about/bio, physical attributes, skills hierarchy, languages/accents, experience, notable works, demo reel player, social links. All layout components from @castyou/design-system. Matches the "Detalhes" screens in Figma (Jornada Talento flow).


FE-TALENT-002 — Talent profile editor (multi-step form)

  • [x] Implemented

Files:

  • Create: apps/app/src/pages/profile/TalentEditPage.tsx
  • Create: apps/app/src/pages/profile/steps/BasicInfoStep.tsx
  • Create: apps/app/src/pages/profile/steps/PhysicalStep.tsx
  • Create: apps/app/src/pages/profile/steps/ProfessionalStep.tsx
  • Create: apps/app/src/pages/profile/steps/ExperienceStep.tsx
  • Create: apps/app/src/pages/profile/steps/LocationAvailabilityStep.tsx
  • Create: apps/app/src/pages/profile/steps/MediaStep.tsx
  • Create: apps/app/src/hooks/useUpdateTalentProfile.ts

Description: Multi-step form to edit all talent profile fields. Each step is a separate component. Progress indicator at top (use ProgressRing from DS). Auto-save draft to localStorage between steps. Submit calls updateTalentProfile mutation. All inputs from @castyou/design-system: Input, Textarea, Select, MultiSelect, Chip, FileUpload.


FE-TALENT-003 — My Profile page (authenticated talent view)

  • [x] Implemented

Files:

  • Edit: apps/app/src/pages/profile/ProfilePage.tsx — replace placeholder with real profile display

Description: Replace the "Profile coming soon" placeholder with the real talent's own profile view. Shows ProgressRing with completeness %, sections matching the public view but with "Edit" buttons per section. Shows EmptyState for incomplete sections with prompts to fill in. Shows the "Change Password" modal already in the file.


FE-TALENT-006 — Extend talent profile view & editor for new spec fields

  • [x] Implemented

Files:

  • Edit: apps/app/src/pages/talent/TalentProfilePage.tsx — add new sections: Verbal Proficiency, Location & Availability extended, Equipment
  • Edit: apps/app/src/pages/profile/steps/BasicInfoStep.tsx — add gender, username
  • Edit: apps/app/src/pages/profile/steps/ProfessionalStep.tsx — add yearsOfExperience, trainingEducation
  • Edit: apps/app/src/pages/profile/steps/LocationAvailabilityStep.tsx — add homeCity, preferredProjectTypes, salaryExpectation, passportVisa, backgroundCheck, equipment
  • Create: apps/app/src/pages/profile/steps/VerbalProficiencyStep.tsx — accentDialect picker
  • Edit: apps/app/src/lib/queries/talent.ts — add new fields to GET_TALENT_PROFILE query
  • Edit: apps/app/src/hooks/useUpdateTalentProfile.ts

New profile sections (view page):

  • Verbal Proficiency: accent/dialect chips (e.g. "British RP", "Southern US")
  • Location & Availability (extended): hometown, preferred project types, salary range, passport/visa info, background check badge, owned/preferred equipment chips
  • Username: shown as @handle in profile header

New form steps (editor):

  • BasicInfoStep: add username field (uniqueness validated on blur), gender dropdown
  • ProfessionalStep: add years of experience number input, trainingEducation repeater (institution, type, year)
  • VerbalProficiencyStep (new step): MultiSelect for accent/dialect from a curated list
  • LocationAvailabilityStep: add homeCity input, preferredProjectTypes MultiSelect, salary range inputs (min/max + currency + period), passportVisa MultiSelect, backgroundCheckClear toggle, ownedEquipment/preferredEquipment MultiSelect

BE-TALENT-004 — TalentProfile missing fields (2.2 spec gap)

  • [x] Implemented

Files:

  • Edit: prisma/schema.prisma — add missing columns to TalentProfile and username unique to User
  • Run: pnpm db:migrate
  • Edit: src/graphql/schema/index.ts — expose new fields on TalentProfile type and UpdateTalentProfileInput
  • Edit: src/graphql/resolvers/talent.ts
  • Create: src/__tests__/resolvers/talent-missing-fields.test.ts

Fields to add:

prisma
// On User model
username        String?   @unique

// On TalentProfile model
gender          String?   // e.g. "Male", "Female", "Non-binary", "Prefer not to say"
accentDialect   String[]  @default([])  // e.g. ["British RP", "Southern US"]
yearsOfExperience Int?
trainingEducation Json?   // [{ institution, type, year }] — acting schools, academies, conservatories

GraphQL additions:

graphql
# TalentProfile type
gender: String
accentDialect: [String!]!
yearsOfExperience: Int
trainingEducation: JSON

# User type
username: String

# UpdateTalentProfileInput
gender: String
accentDialect: [String!]
yearsOfExperience: Int
trainingEducation: JSON

Notes:

  • username lives on User (not TalentProfile) so it's platform-unique across all user types.
  • accentDialect covers the entire Verbal Proficiency section from the spec (Accent / Dialect Proficiency).
  • trainingEducation is separate from certifications — it stores formal schooling entries, not licenses.
  • Reviews & Ratings are deferred: they require a separate TalentReview model authored by producers (out of scope for this ticket).

BE-TALENT-005 — TalentProfile Location & Availability extended fields

  • [x] Implemented

Files:

  • Edit: prisma/schema.prisma — add columns to TalentProfile
  • Run: pnpm db:migrate
  • Edit: src/graphql/schema/index.ts — add fields to TalentProfile type and UpdateTalentProfileInput
  • Edit: src/graphql/resolvers/talent.ts
  • Create: src/__tests__/resolvers/talent-location.test.ts

Fields to add:

prisma
homeCity               String?
preferredProjectTypes  Json?     // { productionTypes[], subtypes[], genres[] }
salaryExpectation      Json?     // { min, max, currency, period: "PER_DAY"|"PER_WEEK"|"PER_PROJECT" }
passportVisa           Json?     // { passports: String[], visas: String[], workPermits: String[] }
backgroundCheckClear   Boolean   @default(false)
ownedEquipment         String[]  @default([])
preferredEquipment     String[]  @default([])

Notes:

  • homeCity is distinct from location (current city) — talent may be based in London but living in NYC.
  • salaryExpectation feeds directly into discover-feed matching factor 1 (salary alignment).
  • passportVisa feeds into matching factor 2 (work authorization) — more granular than the existing workAuthorization String[].
  • backgroundCheckClear and equipment fields are needed for commercial, stunt, and technical production roles.