feat(docs): add API documentation for doctor import from IRIMC
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
# Doctor Import (IRIMC) API
|
||||
|
||||
> **Endpoint:** `POST /api/v1/admin/doctors/import`
|
||||
> **Permission:** `ROLE_ADMIN`
|
||||
> **Controller:** `App\Admin\Controller\AdminApiController::importDoctor`
|
||||
|
||||
وارد کردن یک پزشک از سازمان نظام پزشکی (`membersearch.irimc.org`) **بدون شماره موبایل**.
|
||||
برخلاف `POST /api/v1/admin/doctors` (که موبایل معتبر ایرانی میخواهد)، این اندپوینت برای
|
||||
هر پزشک یک **کاربر جانشینِ غیرفعال** با شناسهٔ مصنوعی میسازد و پروفایل را در وضعیت
|
||||
`unclaimed` ذخیره میکند تا بعداً به پزشک واقعی منتقل شود.
|
||||
|
||||
مصرفکنندهٔ اصلی: خزندهٔ پایتون (`clinicpro-crawler/pipeline.py`) که با کاربر «مالک
|
||||
سیستمی» (`0000000000`) لاگین میکند و هر ~۶۰ ثانیه یک پزشک را میفرستد.
|
||||
|
||||
---
|
||||
|
||||
## مدل مالکیت (ستونهای جدید `doctors`)
|
||||
|
||||
| ستون | مقدار هنگام ایمپورت | توضیح |
|
||||
|---|---|---|
|
||||
| `owner_status` | `unclaimed` | `claimed` \| `unclaimed` \| `pending_transfer` |
|
||||
| `source` | `irimc` | `manual` (پیشفرض رکوردهای قدیمی) \| `irimc` |
|
||||
| `source_ref` | `profile_url` | شناسهٔ رکورد مبدأ برای ممیزی |
|
||||
| `managed_by` | id کاربر ادمینِ فراخوان | کاربری که پروفایل را مدیریت میکند |
|
||||
| `claimed_at` | `null` | زمان انتقال مالکیت (هنگام claim پر میشود) |
|
||||
|
||||
رکوردهای موجود در migration مقدار `manual` + `claimed` میگیرند تا رفتارشان تغییر نکند.
|
||||
|
||||
---
|
||||
|
||||
## idempotency
|
||||
|
||||
کلید یکتای منطقی: `(source, medical_system_code)`.
|
||||
|
||||
- اگر پزشکی با همان `source`+`medical_system_code` وجود نداشته باشد → **ساخته** میشود (`201`).
|
||||
- اگر وجود داشته باشد و `owner_status != claimed` → **بهروزرسانی** میشود (`200`).
|
||||
- اگر وجود داشته باشد و `owner_status == claimed` → **رد** میشود (`200`, `skipped: "claimed"`)
|
||||
تا دادهٔ مالک واقعی بازنویسی نشود.
|
||||
|
||||
---
|
||||
|
||||
## Request
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "دکتر فرخنده حسینی",
|
||||
"medical_system_code": "145657",
|
||||
"source": "irimc",
|
||||
"source_ref": "https://membersearch.irimc.org/member/profile?id=…",
|
||||
"gender": "woman",
|
||||
"degree": "general",
|
||||
"info": "دکترای حرفهای پزشکی",
|
||||
"specialties": [1],
|
||||
"states": [23],
|
||||
"cities": [123]
|
||||
}
|
||||
```
|
||||
|
||||
| فیلد | الزامی | توضیح |
|
||||
|---|:---:|---|
|
||||
| `name` | ✅ | نام کامل پزشک |
|
||||
| `medical_system_code` | ✅ | کد نظام پزشکی (کلید idempotency) |
|
||||
| `source` | — | پیشفرض `irimc` |
|
||||
| `source_ref` | — | `profile_url` یا شناسهٔ مبدأ |
|
||||
| `gender` | — | `man` \| `woman` |
|
||||
| `degree` | — | `general` \| `expert` \| `specialist` \| `subspecialistplus` |
|
||||
| `info` | — | متن تخصص/توضیح |
|
||||
| `specialties` / `states` / `cities` | — | آرایهٔ **شناسههای مرجع** (id) |
|
||||
|
||||
> `gender`/`degree` باید با ثابتهای `Doctor::GENDERS` / `Doctor::DEGREES` سازگار باشند.
|
||||
> `specialties`/`states`/`cities` اگر داده شوند مجموعهٔ فعلی را **جایگزین** میکنند.
|
||||
|
||||
---
|
||||
|
||||
## Response
|
||||
|
||||
### `201 Created` (ساخته شد)
|
||||
```json
|
||||
{ "success": true, "data": { "uuid": "…", "created": true } }
|
||||
```
|
||||
|
||||
### `200 OK` (بهروزرسانی شد)
|
||||
```json
|
||||
{ "success": true, "data": { "uuid": "…", "created": false } }
|
||||
```
|
||||
|
||||
### `200 OK` (رد بهدلیل تصاحبشده)
|
||||
```json
|
||||
{ "success": true, "data": { "uuid": "…", "created": false, "skipped": "claimed" } }
|
||||
```
|
||||
|
||||
### `422` (اعتبارسنجی)
|
||||
```json
|
||||
{ "success": false, "data": null, "errors": [ { "code": "…", "message": "کد نظام پزشکی الزامی است", "field": "medical_system_code" } ] }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## عکس پروفایل
|
||||
|
||||
پس از ایمپورت، عکس با دو مرحله اضافه میشود (همان مسیر پزشکِ عادی):
|
||||
|
||||
1. `POST /file/upload/clinic_pro/doctor/field_image` — بدنه: باینری خام؛ هدر
|
||||
`Content-Disposition: attachment; filename="145657.jpg"`. پاسخ: `{ fid, uuid, url, filename, filemime, filesize }`.
|
||||
2. `PATCH /api/v1/doctor/{uuid}` با بدنهٔ `{ "image_data": <پاسخ مرحلهٔ ۱> }` تا به
|
||||
آرایهٔ `images` پروفایل افزوده شود.
|
||||
|
||||
---
|
||||
|
||||
## کاربر سیستمی و چرخهٔ عمر
|
||||
|
||||
```bash
|
||||
# ساخت/فعالسازی کاربر مالک سیستمی (کرالر با این لاگین میکند)
|
||||
php bin/console app:system-owner 0000000000 --password=<secret> --activate
|
||||
|
||||
# غیرفعالسازی پس از پایان کار (کرالر هم با --deactivate-on-finish این را از طریق API انجام میدهد)
|
||||
php bin/console app:system-owner 0000000000 --deactivate
|
||||
```
|
||||
|
||||
کاربر باید `ROLE_ADMIN` و `status=1` داشته باشد تا لاگینِ رمزی (`POST /api/v1/user/login`)
|
||||
و فراخوانی این اندپوینت ممکن باشد.
|
||||
|
||||
> ⚠️ **captcha:** مسیر `/api/v1/user/login` از `CaptchaGuard` رد میشود و این guard وقتی
|
||||
> `ALTCHA_ENABLED=true` باشد (مقدار فعلی `.env`) یک payloadِ altcha میخواهد. برای اجرای
|
||||
> بدونِمرورگرِ کرالر یکی از اینها لازم است:
|
||||
> ۱) روی همان سرور `ALTCHA_ENABLED=false` در `.env.local` (سادهترین برای dev)، یا
|
||||
> ۲) افزودن یک استثنا در `PasswordAuthenticator` که برای کاربر مالک سیستمی captcha را رد کند،
|
||||
> یا ۳) لاگین سرویس با یک هدر سرّیِ مورد اعتماد. تا وقتی این حل نشود، لاگین کرالر با ۴۲۲
|
||||
> (`ERR_CAPTCHA_001`) رد میشود.
|
||||
Reference in New Issue
Block a user