# غنی‌سازی پاسخ نوبت با تخصص و آدرس مطب پزشک ## پروژه `clinicpro` (Backend — منبع حقیقت). > **Cross-repo:** صفحه‌ی «جزئیات نوبت» در `nobat724_front` (داشبورد → نوبت‌های من → مشاهده جزئیات) این فیلدها را مصرف می‌کند (پرامپت همتا: `nobat724_front/.claude/prompt/appointment-detail-fields-fix.md`). این پرامپت **اول** اجرا شود. ## زمینه `Appointment::toArray()` فقط `doctor:{uuid,name}`, `slot_start/slot_end`, `status`, `note`, `patient_*` را برمی‌گرداند. اما صفحه‌ی جزئیات نوبت در فرانت می‌خواهد **تخصص پزشک، آدرس مطب، تلفن و مختصات نقشه** را هم نشان دهد. چون این داده‌ها در پاسخ نیستند، آن بخش‌ها خالی می‌مانند. `Doctor` این روابط را دارد: `getSpecialties()` (ManyToMany به `Specialty`)، `getAddresses()` (OneToMany به `DoctorAddress`). `DoctorAddress::toArray()` شکل `{address, telephone, map:{latitude,longitude}, name, ...}` می‌دهد. نوبت آدرس مشخصی ذخیره نمی‌کند، پس **اولین آدرس پزشک** به‌عنوان آدرس مطب استفاده می‌شود. ## مشکل / هدف `Appointment::toArray()` گسترش یابد تا `doctor` شامل `specialties` و `address` (اولین آدرس پزشک با `address/telephone/map`) باشد — بدون شکستن مصرف‌کننده‌های فعلی. ## فایل‌های مرتبط | فایل | نقش | |------|-----| | `src/Appointment/Entity/Appointment.php` | `toArray()` — افزودن specialties + address زیر `doctor` | | `src/Doctor/Entity/Doctor.php` | `getSpecialties()`, `getAddresses()` (موجود) | | `src/Doctor/Entity/DoctorAddress.php` | `toArray()` → `{address, telephone, map, ...}` (موجود) | | `src/Specialty/Entity/Specialty.php` | `getUuid()/getName()` (موجود) | ## وضعیت فعلی (کد واقعی) ```php // Appointment::toArray() 'doctor' => [ 'uuid' => $this->doctor->getUuid(), 'name' => $this->doctor->getName(), ], 'slot_start' => $this->slotStart, 'slot_end' => $this->slotEnd, // ... بدون specialties / address ``` `DoctorAddress::toArray()` (مرجع شکل): ```php 'map' => ['latitude' => (string)…, 'longitude' => (string)…], 'address' => $this->address, 'telephone' => $this->telephone, 'name' => $this->name, ``` ## وظایف ### ۱. افزودن specialties و address به `doctor` در `Appointment::toArray()` ```php $doctor = $this->doctor; $firstAddress = $doctor->getAddresses()->first() ?: null; // ... 'doctor' => [ 'uuid' => $doctor->getUuid(), 'name' => $doctor->getName(), 'specialties' => array_map( fn($s) => ['uuid' => $s->getUuid(), 'name' => $s->getName()], $doctor->getSpecialties()->toArray() ), ], 'address' => $firstAddress ? $firstAddress->toArray() : null, ``` - `address` را در سطح بالای آرایه‌ی نوبت بگذار (نه داخل doctor) تا فرانت `appointmentData.address.{address,telephone,map}` را مستقیم بخواند. - `getAddresses()->first()` ممکن است `false` برگرداند (Doctrine Collection) → با `?: null` ایمن کن. - بقیه‌ی کلیدهای موجود (`slot_start`, `status`, ...) بدون تغییر بمانند. ### ۲. مستندسازی `docs/api/appointment.md` شکل جدید `doctor.specialties` و `address` را در response نمونه‌ی `GET /api/v1/appointments/user` (و `GET /api/v1/appointment/{uuid}`) اضافه کن. ## نکات مهم - **بدون شکستن مصرف‌کننده‌ها:** فقط کلید اضافه می‌شود؛ کلیدهای فعلی دست‌نخورده. (پنل ادمین/جاهای دیگری که `toArray` نوبت را می‌خوانند نباید بشکنند.) - تخصص ممکن است خالی باشد (آرایه‌ی خالی) و آدرس ممکن است `null` باشد (پزشک بدون آدرس) — فرانت باید این‌ها را تحمل کند (در پرامپت فرانت لحاظ شده). - نوبت آدرس اختصاصی ذخیره نمی‌کند؛ «اولین آدرس پزشک» یک تقریب منطقی است. اگر بعداً نوبت به آدرس مشخص گره خورد، اینجا باید آن را ترجیح داد. - `slot_start`/`slot_end` Unix‌اند (فرانت تاریخ و ساعت را از `slot_start` می‌سازد). - پاسخ‌ها از `BaseController`؛ migration لازم نیست. - تست: `GET /api/v1/appointments/user` برای کاربری با نوبت → آیتم باید `doctor.specialties[]` و `address.{address,telephone,map}` داشته باشد.