Matching System
What this module does
Matching is the business-critical process of connecting intended parents (IPs) with egg donors, gestational carriers, or sperm donors. The matching system handles everything from preference-based filtering to formal match proposals, including the IP’s review process and match decisions.
Business value
Matching is the core service a fertility agency provides. Getting it right — presenting the right candidates to the right IPs at the right time — is what determines an agency’s success. The matching system must balance the agency’s curation (which profiles to show) with the IP’s autonomy (what they can filter and choose).
Key files
Directoryorchid/
Directorymodels/
- matching.py Favorite, MatchBreakDetails, MatchingPreferences, MatchingQueue
- matchsheet.py MatchSheet, MatchSheetTemplate, MatchSheetHeader, MatchSheetQuestion, CaseMatchSheetAnswer
- agency.py MatchingFilterPreferences (per-agency config)
Directoryapi/
- matching.py 84 KB — matching operations API
- match_sheet.py 29 KB — match sheet API
Directoryviews/
- admin_matching.py 22 KB — admin matching UI
- match_sheet.py 8 KB — match sheet views
How matching works — the four sub-flows
There are four separate matching flows, each with its own logic:
flowchart TD Agency["Agency staff\nmanages matching queue"] Agency --> ED["ED Matching\n(egg donor to IP)"] Agency --> GC["GC Matching\n(carrier to IP)"] Agency --> SD["SD Matching\n(sperm donor to IP)"] Agency --> SDManual["Pre-matching\n(manual ED/SD selection)"]
ED --> Queue["MatchingQueue\n(ordered candidates)"] GC --> Queue SD --> Queue Queue --> Present["Profile shown to IP"] Present --> Decision{"IP Decision"} Decision --> |Interested| Favorite["Favorite added"] Decision --> |Declined| Next["Next candidate shown"] Favorite --> Proposal["Formal match proposal"] Proposal --> Accept["Match accepted\n→ CaseParty created"] Proposal --> Decline["Match declined\n→ MatchBreakDetails"]Data model
erDiagram MatchingQueue { int case_id int candidate_user_id string candidate_type int position string status } Favorite { int case_id int candidate_user_id string candidate_type datetime created_at } MatchBreakDetails { int case_id int candidate_user_id string reason_code text notes } MatchingPreferences { int case_id json preferences } MatchSheetTemplate { int agency_id string name string case_type } MatchSheetQuestion { int template_id string question_text string question_type } CaseMatchSheetAnswer { int case_id int question_id text answer }
MatchingQueue }|--|| Case : "for" Favorite }|--|| Case : "for" MatchBreakDetails }|--|| Case : "for" MatchSheetTemplate ||--o{ MatchSheetQuestion : "has" CaseMatchSheetAnswer }|--|| Case : "for"The matching queue
The MatchingQueue model tracks which candidates are “in queue” to be shown to a specific IP. The agency controls this queue — adding candidates, ordering them, and removing them.
Key concepts:
- Position — the order in which candidates are presented to the IP
- Status — current state of the candidate in this IP’s queue (pending, viewed, declined, favorited, matched)
- The agency can see the full queue; the IP sees only the current candidate being presented
# Get all candidates in an IP's queuequeue = models.MatchingQueue.query.filter_by( case_id=case.id).order_by(models.MatchingQueue.position).all()
# Check if a candidate is favoritedfav = models.Favorite.query.filter_by( case_id=case.id, candidate_user_id=candidate_user_id).first()Match sheets
A match sheet is a structured document comparing both parties in a proposed match. It contains answered questions from both the IP and the donor/carrier, displayed side by side for easy comparison.
Match sheets use a separate template system (MatchSheetTemplate, MatchSheetQuestion) that is different from the main Forms module. Agencies build match sheet templates in the admin settings, and answers are stored as CaseMatchSheetAnswer records.
Agency-level matching configuration
MatchingFilterPreferences (in models/agency.py) controls the matching UI per agency:
- Which filter options appear (age range, ethnicity, education level, etc.)
- Which filters are visible to IPs vs. admin-only
- Default filter values
Match break tracking
When a match proposal is declined or falls apart, a MatchBreakDetails record captures why:
- Reason code (e.g., medical incompatibility, IP changed their mind, candidate withdrew)
- Free-text notes from the admin
This data feeds into agency reporting — understanding why matches fail helps agencies improve their processes.