Files
clinicpro/graphify-out/cache/ast/v0.8.44/8fac38bd8a0c0f92aebb516d01709532f0bec4ec9bfd2f2b44ae6d72dc15ac44.json
T
hamedandClaude Opus 4.8 51432c7bb9 fix(doctor): strip «دکتر» prefix on IRIMC import + name-fix & purge commands
Root cause of "دکتر دکتر …" (and ellipsis-truncated "…نی") in admin: IRIMC
names already contain the «دکتر» title, while the panel renders «دکتر {name}».
Convention is to store the bare name.

- DoctorImportService: normalize name via PersianText::stripDoctorTitle
  (also fixes ي/ی, ك/ک, half-space)
- PersianText::stripDoctorTitle now strips consecutive «دکتر دکتر …» prefixes
- app:doctors:fix-irimc-names: one-off backfill for existing source='irimc'
  rows (dry-run supported) — fixed 340 rows
- app:doctors:purge: FK-safe full wipe of doctors + all dependent tables +
  orphan surrogate users, for a clean test DB (dry-run default, --force to
  apply, prod-guarded)
- tests: PersianTextTest cases for the title stripping; DoctorImportTest
  asserts stored name has no «دکتر» prefix
- docs/api/doctor-import.md: name convention + the two new commands

Verified: import "دکتر صفورا حجازی نیا" → stored "صفورا حجازی نیا" → panel
shows single «دکتر صفورا حجازی نیا».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 14:07:18 +03:30

1 line
10 KiB
JSON

{"nodes": [{"id": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_api_doctor_import_md", "label": "doctor-import.md", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L1"}, {"id": "api_doctor_import_doctor_import_irimc_api", "label": "Doctor Import (IRIMC) API", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L1"}, {"id": "api_doctor_import_\u0645\u062f\u0644_\u0645\u0627\u0644\u06a9\u06cc\u062a_\u0633\u062a\u0648\u0646_\u0647\u0627\u06cc_\u062c\u062f\u06cc\u062f_doctors", "label": "\u0645\u062f\u0644 \u0645\u0627\u0644\u06a9\u06cc\u062a (\u0633\u062a\u0648\u0646\u200c\u0647\u0627\u06cc \u062c\u062f\u06cc\u062f `doctors`)", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L18"}, {"id": "api_doctor_import_idempotency", "label": "idempotency", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L32"}, {"id": "api_doctor_import_request", "label": "Request", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L45"}, {"id": "api_doctor_import_response", "label": "Response", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L78"}, {"id": "api_doctor_import_201_created_\u0633\u0627\u062e\u062a\u0647_\u0634\u062f", "label": "`201 Created` (\u0633\u0627\u062e\u062a\u0647 \u0634\u062f)", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L80"}, {"id": "api_doctor_import_200_ok_\u0628\u0647_\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06cc_\u0634\u062f", "label": "`200 OK` (\u0628\u0647\u200c\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06cc \u0634\u062f)", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L85"}, {"id": "api_doctor_import_200_ok_\u0631\u062f_\u0628\u0647_\u062f\u0644\u06cc\u0644_\u062a\u0635\u0627\u062d\u0628_\u0634\u062f\u0647", "label": "`200 OK` (\u0631\u062f \u0628\u0647\u200c\u062f\u0644\u06cc\u0644 \u062a\u0635\u0627\u062d\u0628\u200c\u0634\u062f\u0647)", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L90"}, {"id": "api_doctor_import_422_\u0627\u0639\u062a\u0628\u0627\u0631\u0633\u0646\u062c\u06cc", "label": "`422` (\u0627\u0639\u062a\u0628\u0627\u0631\u0633\u0646\u062c\u06cc)", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L95"}, {"id": "api_doctor_import_\u0639\u06a9\u0633_\u067e\u0631\u0648\u0641\u0627\u06cc\u0644", "label": "\u0639\u06a9\u0633 \u067e\u0631\u0648\u0641\u0627\u06cc\u0644", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L102"}, {"id": "api_doctor_import_\u0627\u0646\u062a\u0642\u0627\u0644_\u0645\u0627\u0644\u06a9\u06cc\u062a_\u0628\u0647_\u067e\u0632\u0634\u06a9_\u0648\u0627\u0642\u0639\u06cc", "label": "\u0627\u0646\u062a\u0642\u0627\u0644 \u0645\u0627\u0644\u06a9\u06cc\u062a \u0628\u0647 \u067e\u0632\u0634\u06a9 \u0648\u0627\u0642\u0639\u06cc", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L113"}, {"id": "api_doctor_import_\u06a9\u0627\u0631\u0628\u0631_\u0633\u06cc\u0633\u062a\u0645\u06cc_\u0648_\u0686\u0631\u062e\u0647_\u0639\u0645\u0631", "label": "\u06a9\u0627\u0631\u0628\u0631 \u0633\u06cc\u0633\u062a\u0645\u06cc \u0648 \u0686\u0631\u062e\u0647\u0654 \u0639\u0645\u0631", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L155"}, {"id": "api_doctor_import_\u0644\u0627\u06af\u06cc\u0646_\u0633\u0631\u0648\u06cc\u0633\u06cc_captcha", "label": "\u0644\u0627\u06af\u06cc\u0646 \u0633\u0631\u0648\u06cc\u0633\u06cc (captcha)", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L169"}, {"id": "api_doctor_import_backfill_\u0646\u0642\u0634_\u062c\u0627\u0646\u0634\u06cc\u0646_\u0647\u0627\u06cc_\u0642\u062f\u06cc\u0645\u06cc", "label": "backfill \u0646\u0642\u0634 \u062c\u0627\u0646\u0634\u06cc\u0646\u200c\u0647\u0627\u06cc \u0642\u062f\u06cc\u0645\u06cc", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L183"}, {"id": "api_doctor_import_\u0627\u0635\u0644\u0627\u062d_\u0646\u0627\u0645_\u0631\u06a9\u0648\u0631\u062f\u0647\u0627\u06cc_\u0642\u062f\u06cc\u0645\u06cc_\u062d\u0630\u0641_\u067e\u06cc\u0634\u0648\u0646\u062f_\u062f\u06a9\u062a\u0631", "label": "\u0627\u0635\u0644\u0627\u062d \u0646\u0627\u0645 \u0631\u06a9\u0648\u0631\u062f\u0647\u0627\u06cc \u0642\u062f\u06cc\u0645\u06cc (\u062d\u0630\u0641 \u067e\u06cc\u0634\u0648\u0646\u062f \u00ab\u062f\u06a9\u062a\u0631\u00bb)", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L192"}, {"id": "api_doctor_import_\u067e\u0627\u06a9_\u0633\u0627\u0632\u06cc_\u06a9\u0627\u0645\u0644_\u0628\u0631\u0627\u06cc_\u062f\u06cc\u062a\u0627\u0628\u06cc\u0633_\u062a\u0633\u062a", "label": "\u067e\u0627\u06a9\u200c\u0633\u0627\u0632\u06cc \u06a9\u0627\u0645\u0644 \u0628\u0631\u0627\u06cc \u062f\u06cc\u062a\u0627\u0628\u06cc\u0633 \u062a\u0633\u062a", "file_type": "document", "source_file": "docs/api/doctor-import.md", "source_location": "L201"}], "edges": [{"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_api_doctor_import_md", "target": "api_doctor_import_doctor_import_irimc_api", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L1", "weight": 1.0}, {"source": "api_doctor_import_doctor_import_irimc_api", "target": "api_doctor_import_\u0645\u062f\u0644_\u0645\u0627\u0644\u06a9\u06cc\u062a_\u0633\u062a\u0648\u0646_\u0647\u0627\u06cc_\u062c\u062f\u06cc\u062f_doctors", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L18", "weight": 1.0}, {"source": "api_doctor_import_doctor_import_irimc_api", "target": "api_doctor_import_idempotency", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L32", "weight": 1.0}, {"source": "api_doctor_import_doctor_import_irimc_api", "target": "api_doctor_import_request", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L45", "weight": 1.0}, {"source": "api_doctor_import_doctor_import_irimc_api", "target": "api_doctor_import_response", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L78", "weight": 1.0}, {"source": "api_doctor_import_response", "target": "api_doctor_import_201_created_\u0633\u0627\u062e\u062a\u0647_\u0634\u062f", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L80", "weight": 1.0}, {"source": "api_doctor_import_response", "target": "api_doctor_import_200_ok_\u0628\u0647_\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06cc_\u0634\u062f", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L85", "weight": 1.0}, {"source": "api_doctor_import_response", "target": "api_doctor_import_200_ok_\u0631\u062f_\u0628\u0647_\u062f\u0644\u06cc\u0644_\u062a\u0635\u0627\u062d\u0628_\u0634\u062f\u0647", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L90", "weight": 1.0}, {"source": "api_doctor_import_response", "target": "api_doctor_import_422_\u0627\u0639\u062a\u0628\u0627\u0631\u0633\u0646\u062c\u06cc", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L95", "weight": 1.0}, {"source": "api_doctor_import_doctor_import_irimc_api", "target": "api_doctor_import_\u0639\u06a9\u0633_\u067e\u0631\u0648\u0641\u0627\u06cc\u0644", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L102", "weight": 1.0}, {"source": "api_doctor_import_doctor_import_irimc_api", "target": "api_doctor_import_\u0627\u0646\u062a\u0642\u0627\u0644_\u0645\u0627\u0644\u06a9\u06cc\u062a_\u0628\u0647_\u067e\u0632\u0634\u06a9_\u0648\u0627\u0642\u0639\u06cc", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L113", "weight": 1.0}, {"source": "api_doctor_import_doctor_import_irimc_api", "target": "api_doctor_import_\u06a9\u0627\u0631\u0628\u0631_\u0633\u06cc\u0633\u062a\u0645\u06cc_\u0648_\u0686\u0631\u062e\u0647_\u0639\u0645\u0631", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L155", "weight": 1.0}, {"source": "api_doctor_import_\u06a9\u0627\u0631\u0628\u0631_\u0633\u06cc\u0633\u062a\u0645\u06cc_\u0648_\u0686\u0631\u062e\u0647_\u0639\u0645\u0631", "target": "api_doctor_import_\u0644\u0627\u06af\u06cc\u0646_\u0633\u0631\u0648\u06cc\u0633\u06cc_captcha", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L169", "weight": 1.0}, {"source": "api_doctor_import_\u06a9\u0627\u0631\u0628\u0631_\u0633\u06cc\u0633\u062a\u0645\u06cc_\u0648_\u0686\u0631\u062e\u0647_\u0639\u0645\u0631", "target": "api_doctor_import_backfill_\u0646\u0642\u0634_\u062c\u0627\u0646\u0634\u06cc\u0646_\u0647\u0627\u06cc_\u0642\u062f\u06cc\u0645\u06cc", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L183", "weight": 1.0}, {"source": "api_doctor_import_\u06a9\u0627\u0631\u0628\u0631_\u0633\u06cc\u0633\u062a\u0645\u06cc_\u0648_\u0686\u0631\u062e\u0647_\u0639\u0645\u0631", "target": "api_doctor_import_\u0627\u0635\u0644\u0627\u062d_\u0646\u0627\u0645_\u0631\u06a9\u0648\u0631\u062f\u0647\u0627\u06cc_\u0642\u062f\u06cc\u0645\u06cc_\u062d\u0630\u0641_\u067e\u06cc\u0634\u0648\u0646\u062f_\u062f\u06a9\u062a\u0631", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L192", "weight": 1.0}, {"source": "api_doctor_import_\u06a9\u0627\u0631\u0628\u0631_\u0633\u06cc\u0633\u062a\u0645\u06cc_\u0648_\u0686\u0631\u062e\u0647_\u0639\u0645\u0631", "target": "api_doctor_import_\u067e\u0627\u06a9_\u0633\u0627\u0632\u06cc_\u06a9\u0627\u0645\u0644_\u0628\u0631\u0627\u06cc_\u062f\u06cc\u062a\u0627\u0628\u06cc\u0633_\u062a\u0633\u062a", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/api/doctor-import.md", "source_location": "L201", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}