Files
baya-monorepo/archive/build-chain/working-context/backend/handoff/after-backend-phase-7.md
T
2026-08-02 18:48:32 +03:30

3.3 KiB

Handoff — after backend-phase-7 (Search & matching)

Search is live. Verified nurses are now discoverable through one public endpoint backed by a denormalized, maintained-on-write index. This unblocks frontend f6-b7: search + filters (C1), results list (C2), and the nurse profile (C3) can be built against a real API.

What the frontend can now build (f6-b7)

  • Search + filters (C1)GET api/v1/search/nurses (public, no auth). Query params (snake_case): service_category_id (required), city_id (required), district_id (optional), nurse_gender (male/female, optional), min_price/max_price (IRR long, optional), price_unit (optional), page/page_size (default 1 / 50, max 100).
  • Results list (C2) → the data is a PagedResult<NurseSearchResultDto> (items, total, page, pageSize). Each item: variantId, nurseId, serviceCategoryId, price (IRR digit string), priceUnit, nurseGender, averageRating, totalReviews, totalCompletedBookings, cityId, districtId (null = whole city).
  • Nurse profile (C3) → reuse the b6 public trust badge (GET api/v1/nurses/{id}/trust_badge) and the b5 public variant read (GET api/v1/nurse_variants/get/{id}) already live; b7 adds no new profile route.

Categories/cities/districts for the filter dropdowns come from the b4 geo lookups (geo/*) and b5 catalog (catalog/*) — unchanged.

Rules the UI must respect

  • Only searchable nurses come back. The backend returns a nurse only when verified + not suspended + accepting + variant active. No client-side re-check needed; an empty page is a valid result.
  • districtId = null = whole city. A city-only search returns both whole-city and district rows; a district search returns that district's rows plus whole-city rows. Show whole-city hits as covering the district the user searched.
  • Same-gender filter is first-class. Surface nurse_gender prominently; never default it silently. (Carrying the chosen gender into the booking request — required_caregiver_gender — is b8, not here.)
  • price is an IRR digit string — render with a formatter; never parse to a float. Combine with priceUnit (+ sessionCount from the variant, when booking) for the engagement total.
  • Sort is rating-desc only (MVP). No client sort options beyond what the API returns.

Contracts

Backend notes (not frontend-facing)

  • The index is a read-only projection maintained inline inside each source write's transaction (ISearchIndexMaintainer, wired into the b3/b4/b5/b6 handlers). The read seam is INurseSearch (SQL now; Elasticsearch is a config-selected drop-in later, Search:Backend).
  • Admin POST api/v1/admin_search/rebuild_index (dynamic-permission) does an idempotent full rebuild — the reconciliation path; incremental maintenance and rebuild converge.
  • Deferred to b8: booking_requests.required_caregiver_gender capture (carry the chosen gender into the booking). Deferred: Elasticsearch backend + feeder, availability hard-filter, map/radius discovery, ranking beyond rating.