Appearance
Epic 42 — Match Engine (Swipe-to-Match) — replaces Job Apply
Reworks/Removes: Epic 5 (apply pipeline
BE-JOB-002,applyToJob,FE-JOBS-012apply wizard), Epic 5BE-JOB-003swipe semantics, Epic 6 (Discover), Epic 19↔Shortlist relationship, and Epic 36 (Applications Dashboard → Matches). Decision (user, 2026-06-16): Remove "apply" entirely. Casting becomes a bidirectional swipe: producers swipe talents, talents swipe jobs — Like or Nope only (no Skip). A Match forms when both sides Like in the same job context. Shortlist and Folders are the same thing — remove "shortlist" from jobs; Folders (Epic 19) is the single save concept. When a producer Likes a talent they pick one or more folders to save them; producers can swipe in a job context or "just scouting" (scouting Like = folder-save only, no match). Remember the global rule: talent = Talent + Pet Owner (pet jobs included).**Status (2026-06-17): 🟢 Backend COMPLETE (both axes); frontend CORE done. BE commits:
92528d8,5ed2142,a0dd2ac,e12c313. FE commits:1894a1c(talent like + matches page + remove apply/shortlist),b722a24(producer per-job match management),6d07182(pet-owner likePetJob). 556 FE tests green. FE COMPLETE for every actor (added5c7b167producer pet-matches panel,6680838producer talent-swipe → likeTalent + folder picker,1a80a5apet-owner /pet-matches page + nav,ccf8eb2discover-grid Like/Nope). Only follow-ups left: in-system casting CAPTURE (Epic 43 ships request only), and harmless dead-FE-hook removal. Backend cleanup of jobApplications/updateApplicationStatus is NOT a clean win — those resolvers still conceptually serve Groups/Agency applicants (which create Applications, out of scope); Job.myApplication is still wired into the talent job detail. Leave them as unused-but-retained endpoints until Groups/Agency apply is reworked. Stage 3 done = full PetOwner↔PetJob mirror (PetJobInteraction/PetInteraction/PetMatch + tryFormPetMatch + likePet/nopePet/likePetJob/nopePetJob + myPetMatches/petJobMatches + remove applyToPetJob/myPetJobApplications +migrate-petjob-applications-to-matches.ts). Epic 43 backend lifecycle done (see Epic 43). Stage 4 = the frontend (only remaining piece): producer swipe UI, talent JobsSwipePage, pet-owner swipe, match-management pages (talent/producer/pet), remove apply wizard + ShortlistPage + MyApplicationsPage→MyMatchesPage, i18n, tests. Also still pending: full in-system casting CAPTURE (Epic 43 ships the request only), and removing the now-superseded producer-side apply surfaces (jobApplications/updateApplicationStatus/applicationMatch/Job.myApplication+ pet equivalents) — bundle that cleanup with the FE. Being shipped in tested, coherent sub-stages: (1) ✅ additive backend foundation —Matchmodel +JobInteractionType.LIKE+services/match.tryFormMatch+likeTalent/nopeTalent/likeJob/nopeJob+myMatches/jobMatches+MATCH_CREATED, all ALONGSIDE the still-working apply flow (migrationepic42_match_engine, additive); (2) ✅ removed the talent↔job apply pipeline — deletedapplyToJob/myApplications/jobSwipeShortlisted, rewireddiscoverJobs/jobsForTalentto exclude already-swiped (not applied),inviteTalentsToJobnow LIKE+match,scripts/migrate-applications-to-matches.tsback-fillsApplication→Match(Application table retained; 411 rows migrated locally). NOTE: producer-sidejobApplications/updateApplicationStatus/applicationMatch/Job.myApplicationwere KEPT — they're replaced by the Epic 43 match lifecycle; (3) ⏳ mirror everything for the PetOwner↔PetJob axis (user: both axes this pass); (4) ⏳ frontend swipe UIs + remove apply/shortlist UI.Implementation decisions (locked during build): (a) Non-destructive enum reinterpretation instead of renaming — the producer LIKE/NOPE keep the existing DB enum values
TalentInteraction.SHORTLISTED/SKIPPED(exposed as LIKE/NOPE in the API) to avoid a risky Postgres enum-rename migration; talent LIKE is the new additiveJobInteractionType.LIKE. (b) Full removal + both axes (user, 2026-06-17). (c)Applicationtable is RETAINED for history (never dropped); Groups apply + Agency bulk-apply keep working on it (separate features, out of these epics' scope — flagged as a follow-up). (d)markHired/bounty-release moves fromupdateApplicationStatusonto the Match in Epic 43.
Why: Today a talent gets into a producer's pipeline via applyToJob (the Application model) while producers shortlist via TalentInteraction.SHORTLISTED; there is no mutual "match". The stakeholders want a symmetric, dating-app-style match flow. This epic introduces the Match model and the Like/Nope swipe on both sides, makes the producer Like save into Folders (killing the separate shortlist concept), removes the apply path, and migrates existing applications/shortlists into matches so no data is lost. Match lifecycle (reject/casting/casted/hired/message) and in-system casting live in Epic 43.
Architecture: Reuse the AI matching scores (src/services/ai/matching.ts scoreDiscoverFeed/scoreDiscoverJobs) for ordering both swipe stacks. Redefine the two existing swipe models to LIKE | NOPE (producer→talent TalentInteraction; talent→job JobInteraction, which today lacks a "like"). New Match(jobId, talentId, producerId, source, status, …) row is created idempotently the moment both a producer-Like (for that job) and a talent-Like (of that job) exist; both parties are notified. Scouting = producer Like with jobId = null → writes FolderEntry rows only (no Match). The producer-Like folder pick reuses Folders (ProducerFolder/FolderEntry, SaveToFolderButton). All swipe gating from Epic 40 keeps the talent swipe free.
BE-MATCH-001 — Swipe model overhaul (Like/Nope, both directions)
Files:
- Edit:
castyou-backend/prisma/schema.prisma—InteractionType→LIKE | NOPE(migrateSHORTLISTED→LIKE,SKIPPED/BLOCKED→NOPEwith optionalexpiresAtfor block-style hides);JobInteractionType→LIKE | NOPE(migrateSKIPPED→NOPE, keep hide-expiry semantics). Requiresprisma migrate([[CasTyou Tech Stack]]). - Edit:
castyou-backend/src/graphql/resolvers/job.ts— replaceswipeTalentactions withLIKE/NOPE; replaceswipeJobwithLIKE/NOPE.
Acceptance criteria: Both swipe models accept only LIKE/NOPE; existing interaction rows migrate cleanly; no "skip" path remains.
BE-MATCH-002 — Match model + mutual-match formation
Files:
- Edit:
castyou-backend/prisma/schema.prisma— newMatch { id, jobId, talentId, producerId, source (PRODUCER_FIRST|TALENT_FIRST), status (ACTIVE), createdAt, updatedAt, @@unique([jobId, talentId]) }(+ lifecycle fields added in Epic 43). Requiresprisma migrate. - Create:
castyou-backend/src/services/match/index.ts—tryFormMatch(jobId, talentId)called from both Like mutations: if a producer-Like (this job) and talent-Like (this job) both exist and no Match row exists, create one + notify both (newMATCH_CREATEDnotification type, [[Notifications vs Messages]]).
Acceptance criteria: A producer Like + talent Like on the same job creates exactly one Match and notifies both sides; a one-sided Like creates no Match.
BE-MATCH-003 — Producer swipe surface (job + scouting) with folder-save
Files:
- Edit:
castyou-backend/src/graphql/resolvers/job.ts— keep job-scopeddiscoverFeed; add a scouting feed (jobIdnull) for browsing talents to save. - Edit/Create: producer Like mutation
likeTalent(talentId, jobId?, folderIds: [ID!]!)— requires ≥1 folder; writesFolderEntryfor each chosen folder (reusesrc/services/folders), records theTalentInteraction.LIKE, and (ifjobId) callstryFormMatch.nopeTalent(talentId, jobId?)records NOPE.
Acceptance criteria: Producer Like with no folder selected is rejected; Like saves the talent into every chosen folder; job-context Like attempts a match; scouting Like never creates a Match.
BE-MATCH-004 — Talent swipe-jobs surface (free)
Files:
- Edit:
castyou-backend/src/graphql/resolvers/job.ts—likeJob(jobId)/nopeJob(jobId);likeJobrecordsJobInteraction.LIKEand callstryFormMatch; ordering viadiscoverJobs/scoreDiscoverJobs. This path is exempt from the Epic 40 paywall.
Acceptance criteria: Any talent (free included) can Like/Nope jobs; a Like on a job a producer already Liked them for forms a Match.
BE-MATCH-005 — Remove apply pipeline + fold shortlist into folders (with data migration)
Files:
- Edit:
castyou-backend/src/graphql/resolvers/job.ts— deleteapplyToJob,jobApplications(apply-based),jobSwipeShortlisted, and themyApplicationsSHORTLIST/APPLICATION feed; removeApplicationStatus.SHORTLISTEDusage. ReplacemyApplicationswithmyMatches(talent) and per-job match list (producer) — implemented in Epic 43. - Create:
castyou-backend/scripts/migrateApplicationsToMatches.ts— convert each non-rejectedApplication→ aMatch(source: TALENT_FIRST); convert eachTalentInteraction.SHORTLISTED(job-scoped) → producer-Like (+ optionally aMatchif the talent had applied). Preserve HIRED state. Keep theApplicationtable for history (no destructive drop), but stop writing to it. - Edit:
castyou-backend/prisma/schema.prisma— markApplication/ApplicationStatusas deprecated (comment); do not drop.
Acceptance criteria: No applyToJob mutation remains; the "shortlist" concept is gone from jobs (Folders is the only save); existing applications + shortlists appear as matches after migration; HIRED history survives.
FE-MATCH-001 — Producer swipe UI (job + scouting + folder picker)
Files:
- Create: producer swipe-stack page — Like/Nope (no skip); a job-context vs scouting toggle; on Like, a required folder-picker modal (reuse
components/folders/SaveToFolderButton/ folder list, ≥1 folder). - Edit: nav +
lib/pageTitles.ts(+ i18n en/pt/es).
Acceptance criteria: Producer can swipe in a job or scouting; Like always asks for ≥1 folder; everything is sourced from @castyou/design-system ([[Design System Rule]]).
FE-MATCH-002 — Talent swipe-jobs UI (rename Discover → Jobs swipe)
Files:
- Edit/rename:
castyou-frontend/apps/app/src/pages/discover/DiscoverPage.tsx→ a JobsSwipePage (Like/Nope); this is the free talent jobs entry. - Edit: nav,
lib/pageTitles.ts, i18n.
Acceptance criteria: Talent swipe jobs with Like/Nope; page is reachable on free tier.
FE-MATCH-003 — Remove apply + shortlist UI
Files:
- Delete/repoint: apply wizard (
FE-JOBS-012),pages/jobs/ShortlistPage.tsx, shortlist sections of job applicants; convertMyApplicationsPage→MyMatchesPage(Epic 43). RemoveuseMyApplications/useSwipeTalentSHORTLIST paths.
Acceptance criteria: No "Apply" or "Shortlist" UI remains; talent sees Matches; producer sees per-job matches (Epic 43).
TEST-MATCH-001 — Match engine coverage
Acceptance criteria: Like/Nope on both models, mutual-match formation (and non-formation), required-folder on producer Like, scouting=no-match, the free-swipe exemption, and the applications→matches migration are all tested.