feat(clinic): enhance clinic listing with additional details and address information

- Updated the clinic API response to include new fields: title, phone, logo, images_clinic, doctors_count, city, state, 24_7, and field_working_days.
- Modified the ClinicController to fetch and include city and state information based on the clinic's address.
- Refactored the toListArray method in the Clinic entity to accept city and state parameters.
- Added a new method in the ClinicRepository to retrieve city and province names for each clinic based on their address.
This commit is contained in:
hamed
2026-06-18 15:03:36 +03:30
parent eb576b7d98
commit 4bb65c7502
5 changed files with 359 additions and 273 deletions
+290 -268
View File
@@ -48,33 +48,33 @@
### Backend
| لایه | تکنولوژی |
|------|----------|
| Framework | Symfony 7.x |
| PHP | ≥ 8.2 |
| ORM | Doctrine ORM |
| Auth | LexikJWT + OTP |
| Queue | Symfony Messenger |
| Cache | Redis |
| Database | MariaDB 11.8 |
| API Docs | NelmioApiDocBundle + swagger-php |
| Rate Limiting | Symfony Rate Limiter |
| لایه | تکنولوژی |
| ------------- | -------------------------------- |
| Framework | Symfony 7.x |
| PHP | ≥ 8.2 |
| ORM | Doctrine ORM |
| Auth | LexikJWT + OTP |
| Queue | Symfony Messenger |
| Cache | Redis |
| Database | MariaDB 11.8 |
| API Docs | NelmioApiDocBundle + swagger-php |
| Rate Limiting | Symfony Rate Limiter |
### Frontend (Admin SPA)
| لایه | تکنولوژی |
|------|----------|
| Framework | React 19 + TypeScript |
| Routing | React Router DOM v7 |
| Server State | TanStack Query v5 |
| Client State | Zustand v5 (persist) |
| Forms | React Hook Form + Zod |
| Charts | Recharts |
| Maps | React Leaflet 5 |
| Icons | Heroicons v2 |
| Notifications | Sonner |
| Date | jalaali-js |
| Build | Webpack Encore 6 |
| لایه | تکنولوژی |
| ------------- | --------------------- |
| Framework | React 19 + TypeScript |
| Routing | React Router DOM v7 |
| Server State | TanStack Query v5 |
| Client State | Zustand v5 (persist) |
| Forms | React Hook Form + Zod |
| Charts | Recharts |
| Maps | React Leaflet 5 |
| Icons | Heroicons v2 |
| Notifications | Sonner |
| Date | jalaali-js |
| Build | Webpack Encore 6 |
---
@@ -131,21 +131,21 @@ ddev exec php bin/console messenger:consume async
## ۴. آدرس‌های مهم
| سرویس | آدرس |
|-------|------|
| **وب‌سایت** | https://clinic-pro.ddev.site |
| **پنل ادمین** | https://clinic-pro.ddev.site/admin |
| **Swagger UI** | https://clinic-pro.ddev.site/api/doc |
| **Health Check** | https://clinic-pro.ddev.site/health |
| سرویس | آدرس |
| ---------------- | ------------------------------------ |
| **وب‌سایت** | https://clinic-pro.ddev.site |
| **پنل ادمین** | https://clinic-pro.ddev.site/admin |
| **Swagger UI** | https://clinic-pro.ddev.site/api/doc |
| **Health Check** | https://clinic-pro.ddev.site/health |
### ورود به Swagger UI
> آدرس: `https://clinic-pro.ddev.site/api/doc`
| فیلد | مقدار |
|------|-------|
| **نام کاربری** | `admin` |
| **رمز عبور** | `clinic123` |
| فیلد | مقدار |
| -------------- | ----------- |
| **نام کاربری** | `admin` |
| **رمز عبور** | `clinic123` |
پس از ورود، برای احراز هویت API درون Swagger ابتدا از `/api/v1/user/login` توکن بگیرید، سپس دکمه **Authorize** را بزنید و `Bearer <token>` وارد کنید.
@@ -201,7 +201,7 @@ SEP_TERMINAL_ID=<شناسه>
# ── Swagger UI ───────────────────────────────────────────────────
API_DOC_USERNAME=admin
API_DOC_PASSWORD=<bcrypt hash> # plain text: clinic123
API_DOC_PASSWORD=<bcrypt hash> # plain text: admin@admin
```
---
@@ -261,25 +261,40 @@ POST /api/v1/user/login
### نقش‌های کاربری
| نقش | توضیح | دسترسی |
|-----|--------|--------|
| `ROLE_USER` | پایه — همه کاربران | نوبت‌گیری، پروفایل |
| `ROLE_ADMIN` | مدیر کل | پنل ادمین کامل |
| `ROLE_CLINIC` | صاحب کلینیک | مدیریت کلینیک خود |
| `ROLE_DOCTOR` | پزشک | مدیریت نوبت‌ها، پروفایل |
| `ROLE_SECRETARY` | منشی | بر اساس permissions دکتر |
| نقش | توضیح | دسترسی |
| ---------------- | ------------------ | ------------------------ |
| `ROLE_USER` | پایه — همه کاربران | نوبت‌گیری، پروفایل |
| `ROLE_ADMIN` | مدیر کل | پنل ادمین کامل |
| `ROLE_CLINIC` | صاحب کلینیک | مدیریت کلینیک خود |
| `ROLE_DOCTOR` | پزشک | مدیریت نوبت‌ها، پروفایل |
| `ROLE_SECRETARY` | منشی | بر اساس permissions دکتر |
### دسترسی‌های منشی (JSON)
```json
{
"version": 1,
"resources": {
"appointments": { "view": true, "create": true, "cancel": false, "update_status": true },
"addresses": { "view": true, "create": false, "update": false, "delete": false },
"clinic_info": { "view": true, "update": false },
"insurances": { "view": true, "create": false, "update": false, "delete": false }
}
"version": 1,
"resources": {
"appointments": {
"view": true,
"create": true,
"cancel": false,
"update_status": true
},
"addresses": {
"view": true,
"create": false,
"update": false,
"delete": false
},
"clinic_info": { "view": true, "update": false },
"insurances": {
"view": true,
"create": false,
"update": false,
"delete": false
}
}
}
```
@@ -292,12 +307,12 @@ POST /api/v1/user/login
### Firewall های security.yaml
| Firewall | Pattern | توضیح |
|----------|---------|--------|
| `api_doc` | `^/api/doc` | HTTP Basic Auth (admin / clinic123) |
| `public_endpoints` | OTP، OAuth، endpoint های عمومی | بدون احراز هویت |
| `payment_callback` | `/api/v1/payment/callback/` | بدون احراز هویت |
| `api` | `^/(api\|oauth\|file/)` | JWT stateless |
| Firewall | Pattern | توضیح |
| ------------------ | ------------------------------ | ----------------------------------- |
| `api_doc` | `^/api/doc` | HTTP Basic Auth (admin / clinic123) |
| `public_endpoints` | OTP، OAuth، endpoint های عمومی | بدون احراز هویت |
| `payment_callback` | `/api/v1/payment/callback/` | بدون احراز هویت |
| `api` | `^/(api\|oauth\|file/)` | JWT stateless |
---
@@ -305,47 +320,47 @@ POST /api/v1/user/login
### جداول اصلی
| جدول | موجودیت | توضیح |
|------|---------|--------|
| `users` | User | uuid، mobile_number (unique)، roles (JSON)، status |
| `doctors` | Doctor | user_id (OneToOne)، degree، doctor_rate، active_doctor_appointment |
| `doctor_addresses` | DoctorAddress | doctor_id، name، latitude، longitude |
| `clinics` | Clinic | user_id (owner)، name، telephone، is_24_7، latitude، longitude، images_clinic (JSON) |
| `clinic_doctor_invitations` | ClinicDoctorInvitation | token (unique 96char hex)، status، expires_at (+72h)، mobile، uuid |
| `appointments` | Appointment | doctor_id، user_id، slot_start، slot_end، status، price |
| `weekly_schedules` | WeeklySchedule | doctor_id (OneToOne)، setting (JSON) |
| `date_overrides` | DateOverride | doctor_id، date، active، setting (JSON) |
| `holidays` | Holiday | doctor_id، start_date، end_date |
| `payments` | Payment | order_id (unique)، amount_rials، status، gateway (mellat\|sep) |
| `settlements` | Settlement | user_id، amount_rials، status، bank_account (JSON) |
| `wallet_transactions` | WalletTransaction | user_id، amount_rials، type (credit\|debit)، balance_after |
| `representations` | Representation | full_name، commission_percent، city_id |
| `doctor_secretaries` | DoctorSecretary | doctor_id، secretary_id، permissions (JSON)، active |
| `rates` | Rate | doctor_id، user_id، overall، diagnosis_accuracy، skill، behavior |
| `comments` | Comment | doctor_id، user_id، body، status (approved\|pending\|rejected) |
| `likes` | Like | comment_id، user_id |
| `blogs` | Blog | author_id، title، slug (unique)، body، status |
| `sms_templates` | SmsTemplate | name، body، provider_code، status |
| `sms_logs` | SmsLog | mobile، message، provider، success |
| `profiles` | UserProfile | blood_type، gender، insurance_id |
| `provinces` | Province | name |
| `cities` | City | name، province_id (FK) |
| `specialties` | Specialty | name، parent_id (nullable برای زیر-تخصص) |
| `doctor_services` | DoctorService | name |
| `insurances` | Insurance | name، type (basic\|supplementary) |
| `tags` | Tag | name |
| جدول | موجودیت | توضیح |
| --------------------------- | ---------------------- | ------------------------------------------------------------------------------------ |
| `users` | User | uuid، mobile_number (unique)، roles (JSON)، status |
| `doctors` | Doctor | user_id (OneToOne)، degree، doctor_rate، active_doctor_appointment |
| `doctor_addresses` | DoctorAddress | doctor_id، name، latitude، longitude |
| `clinics` | Clinic | user_id (owner)، name، telephone، is_24_7، latitude، longitude، images_clinic (JSON) |
| `clinic_doctor_invitations` | ClinicDoctorInvitation | token (unique 96char hex)، status، expires_at (+72h)، mobile، uuid |
| `appointments` | Appointment | doctor_id، user_id، slot_start، slot_end، status، price |
| `weekly_schedules` | WeeklySchedule | doctor_id (OneToOne)، setting (JSON) |
| `date_overrides` | DateOverride | doctor_id، date، active، setting (JSON) |
| `holidays` | Holiday | doctor_id، start_date، end_date |
| `payments` | Payment | order_id (unique)، amount_rials، status، gateway (mellat\|sep) |
| `settlements` | Settlement | user_id، amount_rials، status، bank_account (JSON) |
| `wallet_transactions` | WalletTransaction | user_id، amount_rials، type (credit\|debit)، balance_after |
| `representations` | Representation | full_name، commission_percent، city_id |
| `doctor_secretaries` | DoctorSecretary | doctor_id، secretary_id، permissions (JSON)، active |
| `rates` | Rate | doctor_id، user_id، overall، diagnosis_accuracy، skill، behavior |
| `comments` | Comment | doctor_id، user_id، body، status (approved\|pending\|rejected) |
| `likes` | Like | comment_id، user_id |
| `blogs` | Blog | author_id، title، slug (unique)، body، status |
| `sms_templates` | SmsTemplate | name، body، provider_code، status |
| `sms_logs` | SmsLog | mobile، message، provider، success |
| `profiles` | UserProfile | blood_type، gender، insurance_id |
| `provinces` | Province | name |
| `cities` | City | name، province_id (FK) |
| `specialties` | Specialty | name، parent_id (nullable برای زیر-تخصص) |
| `doctor_services` | DoctorService | name |
| `insurances` | Insurance | name، type (basic\|supplementary) |
| `tags` | Tag | name |
### جداول رابطه‌ای (ManyToMany)
| جدول | رابطه |
|------|-------|
| `clinic_doctors` | Clinic ↔ Doctor |
| `clinic_specialties` | Clinic ↔ Specialty |
| `clinic_services` | Clinic ↔ DoctorService |
| `clinic_insurances` | Clinic ↔ Insurance |
| `doctor_specialties` | Doctor ↔ Specialty |
| `doctor_expertise` | Doctor ↔ Category |
| `doctor_provinces` | Doctor ↔ Province |
| جدول | رابطه |
| -------------------- | ---------------------- |
| `clinic_doctors` | Clinic ↔ Doctor |
| `clinic_specialties` | Clinic ↔ Specialty |
| `clinic_services` | Clinic ↔ DoctorService |
| `clinic_insurances` | Clinic ↔ Insurance |
| `doctor_specialties` | Doctor ↔ Specialty |
| `doctor_expertise` | Doctor ↔ Category |
| `doctor_provinces` | Doctor ↔ Province |
### وابستگی‌های کلیدی
@@ -374,137 +389,137 @@ Clinic ──ManyToOne──► User (owner)
### احراز هویت
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| POST | `/api/v1/user/send-code` | ارسال OTP | عمومی |
| POST | `/api/v1/user/verify-code` | تأیید OTP | عمومی |
| POST | `/api/v1/user/register` | ثبت‌نام | عمومی |
| POST | `/api/v1/user/login` | لاگین با رمز عبور | عمومی |
| POST | `/oauth/token` | دریافت JWT | عمومی |
| POST | `/oauth/token/refresh` | تجدید توکن | عمومی |
| GET | `/oauth/userinfo` | اطلاعات کاربر جاری | احراز هویت |
| POST | `/oauth/logout` | خروج | احراز هویت |
| متد | آدرس | توضیح | دسترسی |
| ---- | -------------------------- | ------------------ | ---------- |
| POST | `/api/v1/user/send-code` | ارسال OTP | عمومی |
| POST | `/api/v1/user/verify-code` | تأیید OTP | عمومی |
| POST | `/api/v1/user/register` | ثبت‌نام | عمومی |
| POST | `/api/v1/user/login` | لاگین با رمز عبور | عمومی |
| POST | `/oauth/token` | دریافت JWT | عمومی |
| POST | `/oauth/token/refresh` | تجدید توکن | عمومی |
| GET | `/oauth/userinfo` | اطلاعات کاربر جاری | احراز هویت |
| POST | `/oauth/logout` | خروج | احراز هویت |
### پزشکان
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| GET | `/api/v1/doctors` | لیست پزشکان | عمومی |
| GET | `/api/v1/doctor/{uuid}` | جزئیات پزشک | عمومی |
| POST | `/api/v1/doctor` | ایجاد پروفایل | احراز هویت |
| PATCH | `/api/v1/doctor/{uuid}` | ویرایش | احراز هویت |
| DELETE | `/api/v1/doctor/{uuid}` | حذف | احراز هویت |
| POST | `/file/upload/clinic_pro/doctor/field_image` | آپلود تصویر | احراز هویت |
| GET | `/api/v1/clinic-pro/doctor-addresses/{doctorId}` | آدرس‌های مطب | عمومی |
| POST | `/api/v1/clinic-pro/doctor-address` | افزودن آدرس | احراز هویت |
| PATCH | `/api/v1/clinic-pro/doctor-address/{id}` | ویرایش آدرس | احراز هویت |
| DELETE | `/api/v1/clinic-pro/doctor-address/{id}` | حذف آدرس | احراز هویت |
| POST | `/api/v1/clinic-pro/doctor-address/from-clinic/{clinicUuid}` | ایجاد از کلینیک | احراز هویت |
| متد | آدرس | توضیح | دسترسی |
| ------ | ------------------------------------------------------------ | --------------- | ---------- |
| GET | `/api/v1/doctors` | لیست پزشکان | عمومی |
| GET | `/api/v1/doctor/{uuid}` | جزئیات پزشک | عمومی |
| POST | `/api/v1/doctor` | ایجاد پروفایل | احراز هویت |
| PATCH | `/api/v1/doctor/{uuid}` | ویرایش | احراز هویت |
| DELETE | `/api/v1/doctor/{uuid}` | حذف | احراز هویت |
| POST | `/file/upload/clinic_pro/doctor/field_image` | آپلود تصویر | احراز هویت |
| GET | `/api/v1/clinic-pro/doctor-addresses/{doctorId}` | آدرس‌های مطب | عمومی |
| POST | `/api/v1/clinic-pro/doctor-address` | افزودن آدرس | احراز هویت |
| PATCH | `/api/v1/clinic-pro/doctor-address/{id}` | ویرایش آدرس | احراز هویت |
| DELETE | `/api/v1/clinic-pro/doctor-address/{id}` | حذف آدرس | احراز هویت |
| POST | `/api/v1/clinic-pro/doctor-address/from-clinic/{clinicUuid}` | ایجاد از کلینیک | احراز هویت |
### کلینیک‌ها
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| GET | `/api/v1/clinics` | لیست کلینیک‌ها | عمومی |
| GET | `/api/v1/clinic/{uuid}` | جزئیات کلینیک | عمومی |
| POST | `/api/v1/clinic` | ایجاد کلینیک | احراز هویت |
| PATCH | `/api/v1/clinic/{uuid}` | ویرایش | احراز هویت |
| GET | `/api/v1/clinic/doctor-list/{clinicUuid}` | پزشکان کلینیک | عمومی |
| POST | `/file/upload/clinic_pro/clinic/field_clinic_logo` | آپلود لوگو | احراز هویت |
| POST | `/file/upload/clinic_pro/clinic/field_image_clinic` | آپلود گالری | احراز هویت |
| متد | آدرس | توضیح | دسترسی |
| ----- | --------------------------------------------------- | -------------- | ---------- |
| GET | `/api/v1/clinics` | لیست کلینیک‌ها | عمومی |
| GET | `/api/v1/clinic/{uuid}` | جزئیات کلینیک | عمومی |
| POST | `/api/v1/clinic` | ایجاد کلینیک | احراز هویت |
| PATCH | `/api/v1/clinic/{uuid}` | ویرایش | احراز هویت |
| GET | `/api/v1/clinic/doctor-list/{clinicUuid}` | پزشکان کلینیک | عمومی |
| POST | `/file/upload/clinic_pro/clinic/field_clinic_logo` | آپلود لوگو | احراز هویت |
| POST | `/file/upload/clinic_pro/clinic/field_image_clinic` | آپلود گالری | احراز هویت |
### دعوتنامه پزشک به کلینیک
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| POST | `/api/v1/admin/clinic/{uuid}/invite-doctor` | ارسال دعوتنامه | ROLE_ADMIN |
| GET | `/api/v1/admin/clinic/{uuid}/invitations` | لیست دعوتنامه‌ها | ROLE_ADMIN |
| POST | `/api/v1/admin/clinic/invitation/{invUuid}/resend` | ارسال مجدد پیامک | ROLE_ADMIN |
| PATCH | `/api/v1/admin/clinic/invitation/{invUuid}/status` | تغییر وضعیت | ROLE_ADMIN |
| DELETE | `/api/v1/admin/clinic/invitation/{invUuid}` | حذف | ROLE_ADMIN |
| GET | `/api/v1/clinic-invitation/{token}` | مشاهده دعوتنامه | عمومی |
| POST | `/api/v1/clinic-invitation/{token}/accept` | پذیرش توسط دکتر | عمومی |
| POST | `/api/v1/clinic-invitation/{token}/reject` | رد کردن توسط دکتر | عمومی |
| متد | آدرس | توضیح | دسترسی |
| ------ | -------------------------------------------------- | ----------------- | ---------- |
| POST | `/api/v1/admin/clinic/{uuid}/invite-doctor` | ارسال دعوتنامه | ROLE_ADMIN |
| GET | `/api/v1/admin/clinic/{uuid}/invitations` | لیست دعوتنامه‌ها | ROLE_ADMIN |
| POST | `/api/v1/admin/clinic/invitation/{invUuid}/resend` | ارسال مجدد پیامک | ROLE_ADMIN |
| PATCH | `/api/v1/admin/clinic/invitation/{invUuid}/status` | تغییر وضعیت | ROLE_ADMIN |
| DELETE | `/api/v1/admin/clinic/invitation/{invUuid}` | حذف | ROLE_ADMIN |
| GET | `/api/v1/clinic-invitation/{token}` | مشاهده دعوتنامه | عمومی |
| POST | `/api/v1/clinic-invitation/{token}/accept` | پذیرش توسط دکتر | عمومی |
| POST | `/api/v1/clinic-invitation/{token}/reject` | رد کردن توسط دکتر | عمومی |
> توکن ۹۶ کاراکتر hex (`bin2hex(random_bytes(48))`) — مدت اعتبار ۷۲ ساعت. پیامک async از طریق Symfony Messenger ارسال می‌شود.
### نوبت‌دهی
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| GET | `/api/v1/appointment-slots` | اسلات‌های خالی | عمومی |
| POST | `/api/v1/appointment` | رزرو نوبت | احراز هویت |
| GET | `/api/v1/appointment/{uuid}` | جزئیات نوبت | احراز هویت |
| PATCH | `/api/v1/appointment/{uuid}/status` | تغییر وضعیت | احراز هویت |
| GET | `/api/v1/appointments/doctor/{doctorUuid}` | نوبت‌های دکتر | احراز هویت |
| GET | `/api/v1/appointments/user` | نوبت‌های کاربر | احراز هویت |
| متد | آدرس | توضیح | دسترسی |
| ----- | ------------------------------------------ | -------------- | ---------- |
| GET | `/api/v1/appointment-slots` | اسلات‌های خالی | عمومی |
| POST | `/api/v1/appointment` | رزرو نوبت | احراز هویت |
| GET | `/api/v1/appointment/{uuid}` | جزئیات نوبت | احراز هویت |
| PATCH | `/api/v1/appointment/{uuid}/status` | تغییر وضعیت | احراز هویت |
| GET | `/api/v1/appointments/doctor/{doctorUuid}` | نوبت‌های دکتر | احراز هویت |
| GET | `/api/v1/appointments/user` | نوبت‌های کاربر | احراز هویت |
### تنظیمات نوبت‌دهی
| متد | آدرس | توضیح |
|-----|------|--------|
| POST/PATCH/GET | `/api/v1/appointment-settings/weekly-schedule` | برنامه هفتگی |
| POST/PATCH/DELETE/GET | `/api/v1/appointment-settings/date-override` | روز استثناء |
| POST/PATCH/DELETE/GET | `/api/v1/appointment-settings/holidays` | تعطیلات |
| متد | آدرس | توضیح |
| --------------------- | ---------------------------------------------- | ------------ |
| POST/PATCH/GET | `/api/v1/appointment-settings/weekly-schedule` | برنامه هفتگی |
| POST/PATCH/DELETE/GET | `/api/v1/appointment-settings/date-override` | روز استثناء |
| POST/PATCH/DELETE/GET | `/api/v1/appointment-settings/holidays` | تعطیلات |
### پرداخت
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| POST | `/api/v1/payment/appointment` | شروع پرداخت نوبت | احراز هویت |
| POST/GET | `/api/v1/payment/callback/{gateway}` | callback (mellat\|sep) | عمومی |
| GET | `/api/v1/payment/{uuid}` | وضعیت پرداخت | احراز هویت |
| POST | `/api/v1/subscription-payment` | پرداخت اشتراک | احراز هویت |
| متد | آدرس | توضیح | دسترسی |
| -------- | ------------------------------------ | ---------------------- | ---------- |
| POST | `/api/v1/payment/appointment` | شروع پرداخت نوبت | احراز هویت |
| POST/GET | `/api/v1/payment/callback/{gateway}` | callback (mellat\|sep) | عمومی |
| GET | `/api/v1/payment/{uuid}` | وضعیت پرداخت | احراز هویت |
| POST | `/api/v1/subscription-payment` | پرداخت اشتراک | احراز هویت |
### کیف پول و تسویه‌حساب
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| GET | `/api/v1/wallet/balance` | موجودی کیف پول | احراز هویت |
| GET | `/api/v1/wallet/transactions` | تاریخچه تراکنش‌ها | احراز هویت |
| POST | `/api/v1/settlement` | درخواست تسویه | احراز هویت |
| GET | `/api/v1/settlement` | لیست تسویه‌های خودم | احراز هویت |
| POST | `/api/v1/settlement/{uuid}/approve` | تأیید | ROLE_ADMIN |
| POST | `/api/v1/settlement/{uuid}/reject` | رد | ROLE_ADMIN |
| متد | آدرس | توضیح | دسترسی |
| ---- | ----------------------------------- | ------------------- | ---------- |
| GET | `/api/v1/wallet/balance` | موجودی کیف پول | احراز هویت |
| GET | `/api/v1/wallet/transactions` | تاریخچه تراکنش‌ها | احراز هویت |
| POST | `/api/v1/settlement` | درخواست تسویه | احراز هویت |
| GET | `/api/v1/settlement` | لیست تسویه‌های خودم | احراز هویت |
| POST | `/api/v1/settlement/{uuid}/approve` | تأیید | ROLE_ADMIN |
| POST | `/api/v1/settlement/{uuid}/reject` | رد | ROLE_ADMIN |
### امتیاز و نظرات
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| POST | `/api/v1/rate` | ثبت امتیاز | احراز هویت |
| GET | `/api/v1/rate/{doctorUuid}` | میانگین امتیاز | عمومی |
| POST | `/api/v1/comment` | ثبت نظر | احراز هویت |
| GET | `/api/v1/comments/{doctorUuid}` | نظرات تأییدشده | عمومی |
| DELETE | `/api/v1/comment/{uuid}` | حذف نظر | احراز هویت |
| POST | `/api/v1/like/{commentUuid}` | لایک | احراز هویت |
| متد | آدرس | توضیح | دسترسی |
| ------ | ------------------------------- | -------------- | ---------- |
| POST | `/api/v1/rate` | ثبت امتیاز | احراز هویت |
| GET | `/api/v1/rate/{doctorUuid}` | میانگین امتیاز | عمومی |
| POST | `/api/v1/comment` | ثبت نظر | احراز هویت |
| GET | `/api/v1/comments/{doctorUuid}` | نظرات تأییدشده | عمومی |
| DELETE | `/api/v1/comment/{uuid}` | حذف نظر | احراز هویت |
| POST | `/api/v1/like/{commentUuid}` | لایک | احراز هویت |
### منشی
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| POST | `/api/v1/secretary` | ایجاد منشی | ROLE_DOCTOR |
| GET | `/api/v1/secretary/{uuid}` | جزئیات | احراز هویت |
| PATCH | `/api/v1/secretary/{uuid}` | ویرایش permissions | ROLE_DOCTOR |
| DELETE | `/api/v1/secretary/{uuid}` | حذف | ROLE_DOCTOR |
| GET | `/api/v1/secretaries/{doctorUuid}` | لیست منشی‌های دکتر | احراز هویت |
| متد | آدرس | توضیح | دسترسی |
| ------ | ---------------------------------- | ------------------ | ----------- |
| POST | `/api/v1/secretary` | ایجاد منشی | ROLE_DOCTOR |
| GET | `/api/v1/secretary/{uuid}` | جزئیات | احراز هویت |
| PATCH | `/api/v1/secretary/{uuid}` | ویرایش permissions | ROLE_DOCTOR |
| DELETE | `/api/v1/secretary/{uuid}` | حذف | ROLE_DOCTOR |
| GET | `/api/v1/secretaries/{doctorUuid}` | لیست منشی‌های دکتر | احراز هویت |
### نمایندگان
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| POST/GET/PATCH/DELETE | `/api/v1/representation/{uuid?}` | مدیریت نماینده | احراز هویت |
| GET | `/api/v1/representation/{uuid}/dashboard/monthly` | آمار ماهانه | احراز هویت |
| GET | `/api/v1/representation/{uuid}/dashboard/yearly` | آمار سالانه | احراز هویت |
| متد | آدرس | توضیح | دسترسی |
| --------------------- | ------------------------------------------------- | -------------- | ---------- |
| POST/GET/PATCH/DELETE | `/api/v1/representation/{uuid?}` | مدیریت نماینده | احراز هویت |
| GET | `/api/v1/representation/{uuid}/dashboard/monthly` | آمار ماهانه | احراز هویت |
| GET | `/api/v1/representation/{uuid}/dashboard/yearly` | آمار سالانه | احراز هویت |
### پیامک
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| POST | `/api/v1/sms/send` | ارسال مستقیم | احراز هویت |
| POST | `/api/v1/sms/send-template` | ارسال با قالب | احراز هویت |
| POST/PATCH/GET/DELETE | `/api/v1/sms/template/{uuid?}` | مدیریت قالب | احراز هویت |
| POST | `/api/v1/sms/template/{uuid}/submit` | ارسال برای تأیید | احراز هویت |
| POST | `/api/v1/admin/sms/template/{uuid}/approve` | تأیید قالب | ROLE_ADMIN |
| متد | آدرس | توضیح | دسترسی |
| --------------------- | ------------------------------------------- | ---------------- | ---------- |
| POST | `/api/v1/sms/send` | ارسال مستقیم | احراز هویت |
| POST | `/api/v1/sms/send-template` | ارسال با قالب | احراز هویت |
| POST/PATCH/GET/DELETE | `/api/v1/sms/template/{uuid?}` | مدیریت قالب | احراز هویت |
| POST | `/api/v1/sms/template/{uuid}/submit` | ارسال برای تأیید | احراز هویت |
| POST | `/api/v1/admin/sms/template/{uuid}/approve` | تأیید قالب | ROLE_ADMIN |
### تخصص، خدمات، بیمه، تگ، موقعیت
@@ -527,42 +542,42 @@ POST/PATCH/DELETE /api/v1/admin/city/{id?} ROLE_ADMIN
### بلاگ
| متد | آدرس | توضیح | دسترسی |
|-----|------|--------|--------|
| GET | `/api/v1/blogs` | لیست بلاگ‌های منتشرشده | عمومی |
| GET | `/api/v1/blog/{slug}` | جزئیات بلاگ | عمومی |
| POST | `/api/v1/blog` | نوشتن بلاگ | احراز هویت |
| PATCH | `/api/v1/blog/{uuid}` | ویرایش | احراز هویت |
| DELETE | `/api/v1/blog/{uuid}` | حذف | احراز هویت |
| POST | `/file/upload/clinic_pro/blog/field_image` | آپلود تصویر | احراز هویت |
| متد | آدرس | توضیح | دسترسی |
| ------ | ------------------------------------------ | ---------------------- | ---------- |
| GET | `/api/v1/blogs` | لیست بلاگ‌های منتشرشده | عمومی |
| GET | `/api/v1/blog/{slug}` | جزئیات بلاگ | عمومی |
| POST | `/api/v1/blog` | نوشتن بلاگ | احراز هویت |
| PATCH | `/api/v1/blog/{uuid}` | ویرایش | احراز هویت |
| DELETE | `/api/v1/blog/{uuid}` | حذف | احراز هویت |
| POST | `/file/upload/clinic_pro/blog/field_image` | آپلود تصویر | احراز هویت |
### پنل ادمین API
> همه endpoint های زیر نیاز به `ROLE_ADMIN` دارند.
| آدرس | توضیح |
|------|--------|
| `GET /api/v1/admin/dashboard/stats` | ۱۲ KPI (کاربران، پزشکان، نوبت، درآمد، ...) |
| `GET /api/v1/admin/dashboard/charts` | نمودار ۳۰ روزه نوبت و درآمد |
| `GET /api/v1/admin/dashboard/recent` | آخرین نوبت‌ها، پرداخت‌ها، کاربران |
| `GET /api/v1/admin/users` | لیست کاربران (paginated) |
| `GET /api/v1/admin/users/{uuid}` | جزئیات کاربر |
| `PUT /api/v1/admin/users/{uuid}/role` | تغییر نقش |
| `POST /api/v1/admin/users/{uuid}/status` | فعال/غیرفعال |
| `DELETE /api/v1/admin/users/{uuid}` | حذف کاربر |
| `GET /api/v1/admin/doctors` | لیست پزشکان |
| `GET /api/v1/admin/clinics` | لیست کلینیک‌ها |
| `PATCH /api/v1/admin/clinic/{uuid}/status` | تغییر وضعیت کلینیک |
| `DELETE /api/v1/admin/clinic/{uuid}` | حذف کلینیک |
| `GET /api/v1/admin/appointments` | لیست نوبت‌ها |
| `GET /api/v1/admin/payments` | لیست پرداخت‌ها |
| `GET /api/v1/admin/settlements` | لیست تسویه‌ها |
| `GET /api/v1/admin/representations` | لیست نمایندگان |
| `GET /api/v1/admin/secretaries` | لیست منشی‌ها |
| `GET /api/v1/admin/rates` | لیست امتیازها |
| `GET /api/v1/admin/comments` | لیست نظرات |
| `GET /api/v1/admin/sms/logs` | لاگ پیامک‌ها |
| `GET /api/v1/admin/sms/templates` | قالب‌های پیامک |
| آدرس | توضیح |
| ------------------------------------------ | ------------------------------------------ |
| `GET /api/v1/admin/dashboard/stats` | ۱۲ KPI (کاربران، پزشکان، نوبت، درآمد، ...) |
| `GET /api/v1/admin/dashboard/charts` | نمودار ۳۰ روزه نوبت و درآمد |
| `GET /api/v1/admin/dashboard/recent` | آخرین نوبت‌ها، پرداخت‌ها، کاربران |
| `GET /api/v1/admin/users` | لیست کاربران (paginated) |
| `GET /api/v1/admin/users/{uuid}` | جزئیات کاربر |
| `PUT /api/v1/admin/users/{uuid}/role` | تغییر نقش |
| `POST /api/v1/admin/users/{uuid}/status` | فعال/غیرفعال |
| `DELETE /api/v1/admin/users/{uuid}` | حذف کاربر |
| `GET /api/v1/admin/doctors` | لیست پزشکان |
| `GET /api/v1/admin/clinics` | لیست کلینیک‌ها |
| `PATCH /api/v1/admin/clinic/{uuid}/status` | تغییر وضعیت کلینیک |
| `DELETE /api/v1/admin/clinic/{uuid}` | حذف کلینیک |
| `GET /api/v1/admin/appointments` | لیست نوبت‌ها |
| `GET /api/v1/admin/payments` | لیست پرداخت‌ها |
| `GET /api/v1/admin/settlements` | لیست تسویه‌ها |
| `GET /api/v1/admin/representations` | لیست نمایندگان |
| `GET /api/v1/admin/secretaries` | لیست منشی‌ها |
| `GET /api/v1/admin/rates` | لیست امتیازها |
| `GET /api/v1/admin/comments` | لیست نظرات |
| `GET /api/v1/admin/sms/logs` | لاگ پیامک‌ها |
| `GET /api/v1/admin/sms/templates` | قالب‌های پیامک |
### فرمت پاسخ‌های API
@@ -586,40 +601,41 @@ POST/PATCH/DELETE /api/v1/admin/city/{id?} ROLE_ADMIN
### Route های پنل
| مسیر | صفحه | توضیح |
|------|------|--------|
| `/admin/login` | LoginPage | ورود با موبایل + رمز |
| `/admin/dashboard` | DashboardPage | آمار KPI، نمودار، فعالیت‌های اخیر |
| `/admin/users` | UsersPage | لیست + جستجو + فیلتر نقش |
| `/admin/users/:uuid` | UserDetailPage | پروفایل + ویرایش نقش |
| `/admin/doctors` | DoctorsPage | لیست پزشکان |
| `/admin/doctors/new` | DoctorFormPage | ایجاد پزشک جدید |
| `/admin/doctors/:uuid` | DoctorDetailPage | پروفایل کامل + تخصص + نوبت‌ها |
| `/admin/clinics` | ClinicsPage | لیست کلینیک‌ها |
| `/admin/clinics/:uuid` | ClinicDetailPage | پروفایل + نقشه + گالری + دعوتنامه‌ها |
| `/admin/appointments` | AppointmentsPage | لیست نوبت‌ها + فیلتر |
| `/admin/appointments/:uuid` | AppointmentDetailPage | جزئیات نوبت |
| `/admin/payments` | PaymentsPage | لیست پرداخت‌ها |
| `/admin/settlements` | SettlementsPage | تسویه‌حساب |
| `/admin/representations` | RepresentationsPage | نمایندگان |
| `/admin/representations/:uuid` | RepresentationDetailPage | جزئیات نماینده |
| `/admin/comments` | CommentsPage | مدیریت نظرات |
| `/admin/ratings` | RatingsPage | امتیازها |
| `/admin/sms` | SmsPage | مدیریت پیامک |
| `/admin/categories` | CategoriesPage | تخصص/خدمات/بیمه/تگ |
| `/admin/blogs` | BlogsPage | لیست بلاگ‌ها |
| `/admin/blogs/new` | BlogFormPage | نوشتن بلاگ جدید |
| `/admin/secretaries` | SecretariesPage | مدیریت منشی‌ها |
| مسیر | صفحه | توضیح |
| ------------------------------ | ------------------------ | ------------------------------------ |
| `/admin/login` | LoginPage | ورود با موبایل + رمز |
| `/admin/dashboard` | DashboardPage | آمار KPI، نمودار، فعالیت‌های اخیر |
| `/admin/users` | UsersPage | لیست + جستجو + فیلتر نقش |
| `/admin/users/:uuid` | UserDetailPage | پروفایل + ویرایش نقش |
| `/admin/doctors` | DoctorsPage | لیست پزشکان |
| `/admin/doctors/new` | DoctorFormPage | ایجاد پزشک جدید |
| `/admin/doctors/:uuid` | DoctorDetailPage | پروفایل کامل + تخصص + نوبت‌ها |
| `/admin/clinics` | ClinicsPage | لیست کلینیک‌ها |
| `/admin/clinics/:uuid` | ClinicDetailPage | پروفایل + نقشه + گالری + دعوتنامه‌ها |
| `/admin/appointments` | AppointmentsPage | لیست نوبت‌ها + فیلتر |
| `/admin/appointments/:uuid` | AppointmentDetailPage | جزئیات نوبت |
| `/admin/payments` | PaymentsPage | لیست پرداخت‌ها |
| `/admin/settlements` | SettlementsPage | تسویه‌حساب |
| `/admin/representations` | RepresentationsPage | نمایندگان |
| `/admin/representations/:uuid` | RepresentationDetailPage | جزئیات نماینده |
| `/admin/comments` | CommentsPage | مدیریت نظرات |
| `/admin/ratings` | RatingsPage | امتیازها |
| `/admin/sms` | SmsPage | مدیریت پیامک |
| `/admin/categories` | CategoriesPage | تخصص/خدمات/بیمه/تگ |
| `/admin/blogs` | BlogsPage | لیست بلاگ‌ها |
| `/admin/blogs/new` | BlogFormPage | نوشتن بلاگ جدید |
| `/admin/secretaries` | SecretariesPage | مدیریت منشی‌ها |
### الگوی دریافت داده
```typescript
// لیست paginated
const { data } = useQuery({
queryKey: ['resource', page, filters],
queryFn: () => api.get<PaginatedResponse<T>>(`/api/v1/admin/...?page=${page}`),
queryKey: ["resource", page, filters],
queryFn: () =>
api.get<PaginatedResponse<T>>(`/api/v1/admin/...?page=${page}`),
});
const items = data?.data ?? []; // آرایه آیتم‌ها
const items = data?.data ?? []; // آرایه آیتم‌ها
const total = data?.meta?.totalRecords ?? 0;
// Single resource (double-nested — برخی endpoint ها)
@@ -654,27 +670,27 @@ ddev exec php bin/console doctrine:migrations:status
### لیست migration های موجود
| فایل | توضیح |
|------|--------|
| Version20260609130407 | جداول پایه: users, doctors, appointments |
| Version20260609131304 | پرداخت، کیف پول |
| Version20260609131553 | امتیاز، نظرات |
| Version20260609132009 | نمایندگان |
| Version20260609132708 | منشی |
| Version20260609133121 | کلینیک |
| Version20260609133334 | پیامک |
| Version20260609133546 | بلاگ |
| Version20260609134112 | تخصص، بیمه، تگ |
| Version20260609134741 | استان، شهر |
| Version20260609135126 | پروفایل، آدرس مطب |
| Version20260609135514 | برنامه هفتگی |
| Version20260609135704 | روز استثناء، تعطیلات |
| Version20260609135923 | ManyToMany: clinic_doctors, clinic_specialties |
| Version20260609140223 | ایندکس‌های اضافی |
| Version20260609140423 | doctor_insurances |
| Version20260610062539 | فیلدهای اضافی clinic |
| Version20260610175105 | فیلد is_active برای clinic |
| **Version20260610183655** | **جدول clinic_doctor_invitations** |
| فایل | توضیح |
| ------------------------- | ---------------------------------------------- |
| Version20260609130407 | جداول پایه: users, doctors, appointments |
| Version20260609131304 | پرداخت، کیف پول |
| Version20260609131553 | امتیاز، نظرات |
| Version20260609132009 | نمایندگان |
| Version20260609132708 | منشی |
| Version20260609133121 | کلینیک |
| Version20260609133334 | پیامک |
| Version20260609133546 | بلاگ |
| Version20260609134112 | تخصص، بیمه، تگ |
| Version20260609134741 | استان، شهر |
| Version20260609135126 | پروفایل، آدرس مطب |
| Version20260609135514 | برنامه هفتگی |
| Version20260609135704 | روز استثناء، تعطیلات |
| Version20260609135923 | ManyToMany: clinic_doctors, clinic_specialties |
| Version20260609140223 | ایندکس‌های اضافی |
| Version20260609140423 | doctor_insurances |
| Version20260610062539 | فیلدهای اضافی clinic |
| Version20260610175105 | فیلد is_active برای clinic |
| **Version20260610183655** | **جدول clinic_doctor_invitations** |
---
@@ -683,14 +699,17 @@ ddev exec php bin/console doctrine:migrations:status
### پیامک
**KaveNegar** (پیش‌فرض)
- API: `https://api.kavenegar.com/v1/{KEY}/sms/send.json`
- پشتیبانی از: send (متن آزاد) + sendTemplate (قالب)
**Rangineh**
- API: `https://rest.payamresan.com/api/v1/send`
- پشتیبانی از: send + sendTemplate
**ارسال async:**
```php
$this->smsService->dispatchAsync($mobile, $message);
// → Symfony Messenger → Redis → SendSmsHandler
@@ -699,13 +718,16 @@ $this->smsService->dispatchAsync($mobile, $message);
### درگاه پرداخت
**بانک ملت (Mellat)**
- SOAP WebService: `https://bpm.shaparak.ir/pgwchannel/services/pgw?wsdl`
- تأیید: ResCode=0 + SettlePayment
**سپ (SEP)**
- REST API با ترمینال ID
### Redis
- صف پیام: `redis://redis:6379/messages`
- Cache: `redis://redis:6379`
- Refresh Token: کلید `refresh_<sha256>`