Two things ride together because the user noticed the URL bug while
testing the work-in-progress address validation:
1. **Broken Frappe URL pattern.** Three places in the dispatch UI
were generating `/desk/Service Location/<id>` and
`/desk/Dispatch Technician/<id>` links — both return "Page not
found" on Frappe v14+ (= our v16) because the modern desk URL
format is `/app/<slug>/<id>` where slug is lowercase + hyphens.
Fixed in:
• RightPanel.vue (Lieu link in the job details panel)
• DispatchPage.vue (Lieu in the job ctx menu)
• DispatchPage.vue (Ouvrir dans ERPNext in the tech ctx menu)
2. **`POST /address/validate` endpoint** on the hub. Wraps the
existing RQA Supabase search (`address-search.js`) with a
confidence-scored output:
• exact_match (boolean) — score >= 0.7
• best (the top RQA candidate with aq_address_id, lat, lng)
• candidates[] (top 5 ranked)
• confidence (0..1)
• recommendation: validated | review | unmatched
Score combines civic-number exact match, road-name fuzzy overlap,
FSA+full postal-code bonuses, and city-name bonus. The endpoint
is called from ops UI when adding/editing a Service Location to
auto-populate aq_address_id + canonical lat/lng instead of
trusting human typing or Mapbox geocode.
(Custom Fields aq_address_id, address_validation_status,
address_validated_at, linked_address have been added on Service
Location via the Frappe REST API in a separate operation — not in
this commit since they're DB-only.)