- Add SendSmsMessage class for encapsulating SMS message data. - Create KavehNegarProvider and RanginehProvider classes implementing SmsProviderInterface for sending SMS. - Implement SmsLogRepository and SmsTemplateRepository for managing SMS logs and templates. - Develop SendSmsHandler for handling SMS sending messages. - Create SmsService to manage SMS dispatching and logging. - Add UserProfileController for managing user profiles with CRUD operations. - Implement UserProfile entity and repository for user profile data management. - Update symfony.lock and bootstrap.php for project dependencies and environment setup.
8.8 KiB
8.8 KiB
تسک ۱۴: ماژول منشی
توضیح
مدیریت منشیهای دکترها که میتوانند نوبتها و پرداختها را مدیریت کنند. هر دکتر بسته به پلن اشتراک میتواند ۱ یا ۳ منشی فعال داشته باشد.
Endpoint ها
| متد | مسیر | توضیح | نیاز به Auth |
|---|---|---|---|
| POST | /api/v1/secretary |
ایجاد منشی | بله (Doctor/Admin) |
| PATCH | /api/v1/secretary/{uuid} |
ویرایش منشی | بله (Doctor/Admin) |
| GET | /api/v1/secretary/{uuid} |
دریافت اطلاعات منشی | بله |
| DELETE | /api/v1/secretary/{uuid} |
حذف منشی | بله (Doctor/Admin) |
| GET | /api/v1/secretaries/{doctorUuid} |
لیست منشیهای دکتر | بله |
پیشنیازها
- تسک ۰۱، ۰۲، ۰۵ (Doctor)
زمان تخمینی
۵ تا ۶ ساعت
سیستم مجوزها — Resource-Based Permissions (مقیاسپذیر)
فیلد permissions در جدول doctor_secretaries یک JSON ساختاریافته با نسخهبندی است.
طراحی به گونهای است که در آینده بتوان منابع (resources) و عملیات (actions) جدید اضافه کرد بدون تغییر در ساختار جدول.
ساختار JSON
{
"version": 1,
"resources": {
"appointments": {
"view": true,
"create": true,
"cancel": false,
"update_status": true
},
"addresses": {
"view": true,
"create": true,
"update": true,
"delete": false
},
"clinic_info": {
"view": true,
"update": false
},
"insurances": {
"view": true,
"create": true,
"update": true,
"delete": false
}
}
}
منابع و عملیات فعلی
| Resource | Actions | توضیح |
|---|---|---|
appointments |
view, create, cancel, update_status |
نوبتها |
addresses |
view, create, update, delete |
آدرسهای مطب/کلینیک |
clinic_info |
view, update |
اطلاعات مطب یا کلینیک |
insurances |
view, create, update, delete |
بیمهها |
مقیاسپذیری — اضافه کردن Resource جدید در آینده
برای اضافه کردن Resource جدید (مثلاً patients یا reports) فقط کافی است:
- کلید جدید به JSON اضافه شود — بدون migration جدید
- کد Permission Checker به صورت خودکار آن را پشتیبانی میکند
- منشیهای موجود که کلید جدید را ندارند، به صورت پیشفرض
falseدارند
پیادهسازی PHP — SecretaryPermissionChecker
// src/Secretary/Security/SecretaryPermissionChecker.php
class SecretaryPermissionChecker
{
/**
* بررسی مجوز منشی برای یک عملیات روی یک منبع
* مثال: $checker->can($secretary, 'appointments', 'create')
*/
public function can(Secretary $secretary, string $resource, string $action): bool
{
if (!$secretary->isActive()) {
return false;
}
$permissions = $secretary->getPermissions();
return (bool) ($permissions['resources'][$resource][$action] ?? false);
}
/**
* بررسی دسترسی کامل به یک منبع (همه actions باید true باشند)
*/
public function canAll(Secretary $secretary, string $resource, array $actions): bool
{
return array_reduce(
$actions,
fn($carry, $action) => $carry && $this->can($secretary, $resource, $action),
true
);
}
}
مثال استفاده در Controller:
// در AppointmentController
if (!$this->permissionChecker->can($secretary, 'appointments', 'create')) {
throw new AccessDeniedHttpException('منشی مجاز به ثبت نوبت نیست');
}
// در InsuranceController
if (!$this->permissionChecker->can($secretary, 'insurances', 'delete')) {
throw new AccessDeniedHttpException('منشی مجاز به حذف بیمه نیست');
}
پیشفرض هنگام ایجاد منشی
{
"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
}
}
}
POST /api/v1/secretary
// Request
{
"mobile_number": "09120671756",
"doctor_uuid": "61be915b-...",
"permissions": {
"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
}
}
}
}
// Response 201
{
"success": true,
"data": {
"uuid": "...",
"user": { "uuid": "...", "realname": "فاطمه رضایی", "mobile": "09120671756" },
"doctor": { "uuid": "...", "name": "دکتر احمدی" },
"active": true,
"permissions": { ... },
"created_at": 1748000000
}
}
// Response 422 — حد مجاز منشی
{
"success": false,
"errors": [{ "code": "ERR_SECRETARY_001", "message": "پلن فعلی اجازه منشی بیشتر را نمیدهد" }]
}
قانون بررسی پلن (سمت سرور):
پلن بیسیک → max 1 منشی فعال
پلن پیشرفته → max 3 منشی فعال
هنگام POST /secretary:
activeCount = COUNT(*) WHERE doctor_id=X AND active=true
if activeCount >= maxAllowed → 422
PATCH /api/v1/secretary/{uuid}
// Request (فقط resources موردنظر — deep merge با پیشفرضها)
{
"active": false,
"permissions": {
"resources": {
"insurances": {
"create": true,
"update": true
}
}
}
}
// نکته: فقط resources/actions ارسالشده تغییر میکنند — بقیه دستنخورده میمانند
// Response 200 { "success": true, "data": { ... } }
---
## GET /api/v1/secretary/{uuid}
```json
{
"success": true,
"data": {
"uuid": "...",
"user": {
"uuid": "...",
"realname": "فاطمه رضایی",
"mobile": "09120671756",
"picture": null
},
"doctor": { "uuid": "...", "name": "دکتر احمدی" },
"active": true,
"permissions": {
"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 }
}
},
"created_at": 1748000000
}
}
GET /api/v1/secretaries/{doctorUuid}
{
"success": true,
"data": [
{
"uuid": "...",
"user": { "uuid": "...", "realname": "فاطمه رضایی", "mobile": "09120671756" },
"active": true,
"permissions": { ... },
"created_at": 1748000000
}
]
}
نکات مهم
- کاربر منشی: هنگام ایجاد منشی با mobile_number، ابتدا بررسی میشود آیا کاربر با این شماره وجود دارد — اگر نه، کاربر جدید ایجاد میشود
- ROLE: کاربر منشی باید role
doctor_s_secretaryداشته باشد - لاگین منشی: منشی میتواند با username/password لاگین کند (تسک ۰۲)
- بررسی پلن: کاملاً سمت سرور انجام میشود، قابل دور زدن نیست
- نوبت آفلاین: نوبتی که منشی ثبت میکند (
appointments.create) کمیسیون نماینده ندارد - PATCH permissions: فقط resources/actions ارسالشده تغییر میکنند (deep merge) — بقیه دستنخورده
- Resource ناشناخته: اگر resource جدیدی در JSON باشد که سرور نمیشناسد، نادیده گرفته میشود (forward compat)
- پیشفرض
false: اگر resource یا action در JSON وجود نداشته باشد →false(deny by default)