Phone fix: shifts/jobs showed Facility.Phone, but unnamed ads all share one
placeholder facility, so every such listing displayed the same stale number
while the ad's real phone sat unused in the description. ContactMethod is now
attachable to a Shift/JobOpening (not just talent); ingestion stores the ad's
own number(s) on each listing and the detail pages render them (new
_ContactList partial), falling back to the facility phone only when the ad had
none. Migration ShiftJobContacts (nullable owner FKs) — auto-applies on deploy.
Stale applicants: skip «آماده به کار» posts older than 7 days at ingest, by the
source's real timestamp (Telegram <time>, Bale date) or a Persian time-ago
phrase in the text (Divar «۲ هفته پیش»). Recorded as Discarded; shifts/jobs
are not aged out.
Admin: Review page now shows a «مشاهده آگهی در منبع» link (RawListing.SourceUrl)
so the source post can be checked before publishing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The detail pages showed a 'map coming later' placeholder. Add a read-only Neshan web map (Leaflet SDK) showing the facility marker when NeshanMapKey is set, plus a 'مسیریابی در نشان' directions link; falls back to coordinates when no key. New _NeshanMap shared partial loads the SDK and inits #facmap. Shift/Job Details models now expose MapKey via SettingsService. Coordinates are emitted with InvariantCulture so the decimal point/digits don't break JS. The facility registration picker already used Neshan; this reuses the same key.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>