Refactor code structure for improved readability and maintainability

This commit is contained in:
hamed
2026-07-12 09:54:44 +03:30
parent ca66b86cf9
commit 476d5bb80e
16 changed files with 1617 additions and 907 deletions
@@ -0,0 +1,91 @@
# پروفایل unclaimed پزشک — حذف امتیاز پیش‌فرض جعلی از پاسخ API
## پروژه
`clinicpro` (backend) — **cross-repo**. پرامپت همتای frontend:
`nobat724_front/.claude/prompt/unclaimed-doctor-public-page.md`
این تغییر backend باید **اول** انجام شود؛ سایت عمومی و پنل ادمین و tauri همگی همین پاسخ را مصرف می‌کنند.
## زمینه
پزشکانِ ایمپورت‌شده از نظام پزشکی (IRIMC) با `owner_status = 'unclaimed'` ساخته می‌شوند و هیچ‌گاه فیلد امتیاز ست نمی‌شود؛ پس مقادیر پیش‌فرضِ انتیتی (`doctor_rate = 3.5`, `doctor_rate_percentage = 60`) به‌عنوان امتیاز واقعی در پاسخ عمومی برمی‌گردند. سایت این‌ها را به‌صورت «امتیاز: ۳.۵» و «۶۰٪ رضایت» و در JSON-LD به‌صورت `AggregateRating` نشان می‌دهد — در حالی که تعداد نظرات واقعی صفر است.
## مشکل / هدف
- **بحرانی:** داده‌ی امتیاز جعلی برای پروفایل بدون صاحب. هم گمراه‌کننده، هم نقض دستورالعمل structured data گوگل (ریویوی جعلی) و ریسک جریمه.
- هدف: تا وقتی پروفایل `claimed` نشده، فیلدهای امتیاز در پاسخ عمومی **null** برگردند (نه مقدار پیش‌فرض). بعد از claim، رفتار عادی برگردد (بدون تغییر، چون آن‌موقع `owner_status='claimed'`).
## فایل‌های مرتبط
| فایل | نقش |
|------|-----|
| `src/Doctor/Entity/Doctor.php` | `toDetailArray()` (L530576) و `toListArray()` (L506–528) — سریال‌سازی `satisfaction`/`point`/`owner_status` |
| `src/Doctor/Controller/DoctorController.php` | `show()` L149173 (public `GET /api/v1/doctor/{uuid}``list()` L244260 (public `GET /api/v1/doctors`) — بدون تغییر، فقط مصرف‌کننده |
| `docs/api/doctor.md` | باید به‌روز شود |
## وضعیت فعلی
فیلدهای انتیتی (`src/Doctor/Entity/Doctor.php`):
```php
#[ORM\Column(name: 'doctor_rate', type: 'float')]
private float $doctorRate = 3.5; // L6768
#[ORM\Column(name: 'doctor_rate_percentage', type: 'float')]
private float $doctorRatePercentage = 60.0; // L7071
// owner_status enum: claimed | unclaimed | pending_transfer (L83)
#[ORM\Column(name: 'owner_status', type: 'string', length: 20)]
private string $ownerStatus = 'claimed'; // L8485
```
سریال‌سازی فعلی (هر دو آرایه امتیاز را همیشه برمی‌گردانند):
```php
// toDetailArray() L557559
'satisfaction' => (string) $this->doctorRatePercentage,
'point' => (string) $this->doctorRate,
'owner_status' => $this->ownerStatus,
// toListArray() L521526 — همان دو کلید + owner_status
```
## وظایف
### ۱. helper برای «آیا امتیاز واقعی نمایش داده شود؟»
در `Doctor.php` یک متد کوچک اضافه کن (منبع واحد منطق):
```php
/** امتیاز فقط برای پروفایل claimed معتبر است؛ unclaimed/pending_transfer مقدار پیش‌فرض جعلی دارد. */
public function hasPublicRating(): bool
{
return $this->ownerStatus === 'claimed';
}
```
### ۲. null کردن امتیاز در `toDetailArray()` و `toListArray()`
در هر دو متد، به‌جای مقدار مستقیم:
```php
'satisfaction' => $this->hasPublicRating() ? (string) $this->doctorRatePercentage : null,
'point' => $this->hasPublicRating() ? (string) $this->doctorRate : null,
```
`owner_status` بدون تغییر بماند (frontend به آن نیاز دارد). کلیدها **حذف نشوند**، فقط مقدارشان `null` شود تا شکل پاسخ نشکند.
### ۳. مستندسازی
`docs/api/doctor.md` را به‌روز کن:
- در توضیح فیلدهای پاسخ single (L83118) و list (L196222) ذکر کن: `point` و `satisfaction` برای `owner_status !== 'claimed'` مقدار `null` دارند.
- یک خط در header note اضافه کن که امتیاز پیش‌فرض فقط برای پروفایل claimed منتشر می‌شود.
## نکات مهم
- **پاسخ double-nested است**: `show()` از `$this->success(['data' => array_merge($doctor->toDetailArray($schedule), [...])])` استفاده می‌کند → frontend با `data.data.data` می‌خواند. شکل را تغییر نده، فقط مقدار دو کلید.
- **بعد از claim خودکار درست می‌شود**: `DoctorClaimService::finalize()` وضعیت را به `'claimed'` می‌برد → `hasPublicRating()` صحیح می‌شود → امتیاز واقعی برمی‌گردد. نیازی به منطق اضافه برای «برگشت به حالت عادی» نیست.
- `pending_transfer` هم مثل `unclaimed` امتیاز نداشته باشد (فقط `claimed` امتیاز دارد).
- تست موجود اگر روی `toDetailArray`/`toListArray` هست را چک کن (مقدار `point`/`satisfaction` ممکن است اکنون `null` شود). `ddev exec php bin/phpunit`.
- migration لازم **نیست** (فقط منطق سریال‌سازی، نه تغییر schema).
- بعد از تغییر: `ddev exec php vendor/bin/phpstan analyse` و `graphify update .`.