feat: add social media links field to Doctor entity and update API documentation
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
# افزودن فیلد شبکههای اجتماعی به Doctor
|
||||
|
||||
## پروژه
|
||||
|
||||
`clinicpro` (Backend) — این تغییر پیشنیاز پرامپت همتا در frontend است: `nobat724_front/.claude/prompt/doctor-seo-schema-knowledge-panel.md`. آن پرامپت برای Knowledge Panel گوگل به `sameAs` در JSON-LD نیاز دارد که باید از همین فیلد جدید پر شود.
|
||||
|
||||
## زمینه
|
||||
|
||||
برای فعالسازی Knowledge Panel گوگل برای صفحهی هر پزشک (هدف نهایی در `nobat724_front`)، schema.org نیاز به آرایهی `sameAs` دارد که لینک پروفایلهای شبکههای اجتماعی پزشک (اینستاگرام، تلگرام، آپارات، یوتیوب، لینکدین) را به گوگل معرفی میکند. بررسی `src/Doctor/Entity/Doctor.php` و `docs/api/doctor.md` نشان داد این داده هیچجا در API موجود نیست — نه در پاسخ `GET /api/v1/doctor/{uuid}` و نه در فرم ادمین (`assets/admin/pages/DoctorFormPage.tsx`).
|
||||
|
||||
نکتهی مهم: برخلاف انتظار اولیه، `DoctorAddress` (`src/Doctor/Entity/DoctorAddress.php`) از قبل `latitude`/`longitude` دارد و در `toArray()` بهصورت `map: { latitude, longitude }` برمیگرداند — یعنی GeoCoordinates برای LocalBusiness schema نیازی به تغییر backend ندارد. فقط شبکههای اجتماعی پزشک باقی میماند.
|
||||
|
||||
## مشکل / هدف
|
||||
|
||||
به `Doctor` entity یک فیلد JSON برای ذخیرهی لینک شبکههای اجتماعی (اینستاگرام، تلگرام، آپارات، یوتیوب، لینکدین، توییتر/X) اضافه شود، در پاسخ API برگردانده شود، و در فرم ادمین برای ویرایش در دسترس باشد.
|
||||
|
||||
## فایلهای مرتبط
|
||||
|
||||
| فایل | نقش |
|
||||
|------|-----|
|
||||
| `src/Doctor/Entity/Doctor.php` | باید فیلد `socialMedia` (JSON nullable) اضافه شود |
|
||||
| `src/Doctor/Controller/DoctorController.php` | پاسخ `GET /api/v1/doctor/{uuid}` باید `social_media` را برگرداند؛ متد update باید آن را بپذیرد |
|
||||
| `migrations/` | migration جدید برای ستون `social_media` روی جدول `doctors` |
|
||||
| `assets/admin/pages/DoctorFormPage.tsx` | فیلدهای ورودی لینکهای اجتماعی به فرم اضافه شود |
|
||||
| `assets/admin/types/index.ts` | type پزشک باید `socialMedia` را شامل شود |
|
||||
| `docs/api/doctor.md` | باید فیلد جدید مستند شود |
|
||||
|
||||
## وضعیت فعلی
|
||||
|
||||
`src/Doctor/Entity/Doctor.php` فیلدهای پایه دارد (نام، تخصص، آدرسها) اما هیچ فیلد JSON برای دادهی نیمهساختیافته ندارد. الگوی مشابه را میتوان از `DoctorAddress::toArray()` که `map` را بهصورت nested object برمیگرداند الگو گرفت:
|
||||
|
||||
```php
|
||||
// src/Doctor/Entity/DoctorAddress.php — الگوی موجود برای nested object در toArray()
|
||||
'map' => [
|
||||
'latitude' => $this->latitude !== null ? (string) $this->latitude : null,
|
||||
'longitude' => $this->longitude !== null ? (string) $this->longitude : null,
|
||||
],
|
||||
```
|
||||
|
||||
## وظایف
|
||||
|
||||
### ۱. افزودن فیلد `socialMedia` به `Doctor` entity
|
||||
|
||||
```php
|
||||
// src/Doctor/Entity/Doctor.php
|
||||
#[ORM\Column(name: 'social_media', type: 'json', nullable: true)]
|
||||
private ?array $socialMedia = null;
|
||||
|
||||
public function getSocialMedia(): ?array { return $this->socialMedia; }
|
||||
public function setSocialMedia(?array $v): self { $this->socialMedia = $v; $this->touch(); return $this; }
|
||||
```
|
||||
|
||||
ساختار JSON ذخیرهشده:
|
||||
|
||||
```json
|
||||
{
|
||||
"instagram": "https://instagram.com/dr.example",
|
||||
"telegram": "https://t.me/dr_example",
|
||||
"aparat": "https://aparat.com/dr.example",
|
||||
"youtube": "https://youtube.com/@dr.example",
|
||||
"linkedin": "https://linkedin.com/in/dr-example"
|
||||
}
|
||||
```
|
||||
|
||||
هر کلید nullable است — پزشک ممکن است فقط بعضی شبکهها را داشته باشد. کلیدهای خالی/null باید در پاسخ API هم `null` بمانند (نه حذف شوند) تا frontend بهسادگی چک کند.
|
||||
|
||||
### ۲. Migration
|
||||
|
||||
```bash
|
||||
ddev exec php bin/console doctrine:migrations:diff --no-interaction
|
||||
ddev exec php bin/console doctrine:migrations:migrate --no-interaction
|
||||
```
|
||||
|
||||
### ۳. بازگرداندن فیلد در پاسخ API
|
||||
|
||||
در `src/Doctor/Controller/DoctorController.php`، هرجا `toArray()`-مانند برای پزشک ساخته میشود (GET تکی، GET لیست)، کلید `social_media` اضافه شود:
|
||||
|
||||
```php
|
||||
'social_media' => $doctor->getSocialMedia(),
|
||||
```
|
||||
|
||||
و در متد update، فیلد جدید از request body خوانده و validate شود (فقط باید URL معتبر یا null باشد برای هر کلید — از `InputValidator` یا یک Assert ساده استفاده کن، الگوی موجود validation در همان کنترلر را دنبال کن).
|
||||
|
||||
### ۴. فرم ادمین
|
||||
|
||||
در `assets/admin/pages/DoctorFormPage.tsx`، یک بخش جدید «شبکههای اجتماعی» با ۵ فیلد متنی (اینستاگرام، تلگرام، آپارات، یوتیوب، لینکدین) اضافه شود. الگوی `Field()` موجود در همین فایل (خط ۵۲) را برای ساخت input استفاده کن. مقدار اولیه از `doctor.socialMedia` پر شود، در submit به همان شکل JSON ارسال شود.
|
||||
|
||||
در `assets/admin/types/index.ts`، interface پزشک باید شامل شود:
|
||||
|
||||
```ts
|
||||
socialMedia?: {
|
||||
instagram?: string | null;
|
||||
telegram?: string | null;
|
||||
aparat?: string | null;
|
||||
youtube?: string | null;
|
||||
linkedin?: string | null;
|
||||
} | null;
|
||||
```
|
||||
|
||||
## نکات مهم
|
||||
|
||||
- این فیلد باید **nullable** کامل باشد — پزشکانی که شبکه اجتماعی ندارند نباید خطا بگیرند.
|
||||
- مقادیر باید URL کامل (با `https://`) ذخیره شوند، نه فقط username — frontend مستقیماً این مقدار را در `sameAs` آرایهی JSON-LD قرار میدهد بدون پردازش اضافی.
|
||||
- بعد از این تغییر، `docs/api/doctor.md` را طبق قانون پروژه (بهروزرسانی مستندات همزمان با تغییر API) ویرایش کن — هم در نمونهی JSON پاسخ `GET /api/v1/doctor/{uuid}` و هم در بخش فیلدهای قابل ویرایش.
|
||||
- migration را قبل از merge باید روی دیتابیس dev واقعی تست کنی (`ddev exec php bin/console doctrine:migrations:migrate --no-interaction`).
|
||||
Reference in New Issue
Block a user