# PRD — ClinicPro Phase 2 **تاریخ:** ۲۴ خرداد ۱۴۰۵ **نسخه:** 1.0 **وضعیت:** Draft --- ## خلاصه اجرایی این سند نیازمندی‌های فاز ۲ پلتفرم **ClinicPro** را پوشش می‌دهد. هدف: تبدیل پلتفرم از یک سیستم نوبت‌دهی ساده به یک سیستم مدیریت کلینیک کامل با پنل‌های اشتراکی، پرونده بیمار، مدیریت پرسنل و پنل پیامکی. --- ## وضعیت فعلی پروژه | ماژول | وضعیت | |--------|--------| | Auth (OTP + JWT) | ✅ کامل | | Doctor profile | ✅ کامل | | Clinic management | ✅ کامل | | Appointment booking | ✅ کامل | | Secretary entity (DoctorSecretary) | ✅ موجود — نیاز به UI و permissions بیشتر | | Payment gateway (Mellat, SEP) | ✅ کامل — برای نوبت + subscription | | SMS (SmsLog, SmsTemplate) | ✅ زیرساخت موجود — نیاز به پنل کلینیک | | Wallet / Settlement | ✅ کامل | | Site config (SiteConfig key-value) | ✅ موجود | | **Staff (پرسنل)** | ❌ موجود نیست | | **Panel subscription tiers** | ❌ موجود نیست | | **Patient records (پرونده بیمار)** | ❌ موجود نیست | | **Clinic services (خدمات)** | ❌ موجود نیست | | **SMS panel per clinic** | ❌ UI نیاز دارد | --- ## اپیک‌ها و قابلیت‌ها --- ### اپیک ۱ — پرسنل (Staff) #### توضیح مدیر کلینیک یا دکتر مستقل می‌تواند پرسنلی که نیازی به لاگین ندارند را ثبت کند. این پرسنل در سرویس‌دهی، سشن‌ها و گزارشات استفاده می‌شوند. #### نیازمندی‌های کارکردی - **F1.1** — ایجاد / ویرایش / غیرفعال‌سازی پرسنل (حذف نرم — soft delete) - **F1.2** — فیلدهای پرسنل: - نام و نام خانوادگی (اجباری) - شماره تماس - عنوان شغل (مثال: پرستار، منشی، تکنسین) - آدرس - کد ملی - فعال / غیرفعال - **F1.3** — پرسنل به کلینیک یا مطب دکتر وابسته است (FK به clinic_id یا doctor_id) - **F1.4** — لیست پرسنل فقط در scope کلینیک/مطب فعال نمایش داده می‌شود - **F1.5** — در ایجاد سرویس، از لیست پرسنل انتخاب می‌شود #### موجودیت‌های جدید مورد نیاز ``` ClinicStaff: - id, uuid - clinic_id (FK → clinics) OR doctor_id (FK → doctors) [یکی از دو] - full_name, phone, job_title, address, national_code - active (bool, default: true) - created_at, updated_at (Unix timestamp) ``` #### API endpoints | Method | Path | Permission | |--------|------|-----------| | `GET` | `/api/v1/staff` | clinic/doctor | | `POST` | `/api/v1/staff` | clinic/doctor | | `PATCH` | `/api/v1/staff/{uuid}` | clinic/doctor | | `PATCH` | `/api/v1/staff/{uuid}/toggle` | clinic/doctor | #### Frontend - صفحه: `StaffPage.tsx` — لیست با DataTable + Modal ایجاد/ویرایش - در Sidebar زیر بخش «تنظیمات» --- ### اپیک ۲ — پنل اشتراکی (Subscription Tiers) #### توضیح سه سطح پنل وجود دارد. برای هر پنل، ادمین می‌تواند چند **دوره زمانی** با قیمت‌های مختلف تعریف کند (مثلاً ۱ ماهه، ۶ ماهه، ۱۲ ماهه). کلینیک/دکتر دوره و پنل مورد نظر را انتخاب و پرداخت می‌کند. #### پنل‌ها | سطح | نام | قابلیت‌ها | |-----|-----|----------| | 0 | Free | نوبت‌دهی + ۱ منشی — رایگان، بدون زمان انقضا | | 1 | Basic | ۲ منشی + پرونده بیمار + مدیریت سرویس‌ها | | 2 | Professional | ۵ منشی + پرونده بیمار + مدیریت سرویس‌ها | #### دوره‌های اشتراک (مثال) | دوره | مدت (ماه) | قیمت Basic | قیمت Professional | |------|-----------|-----------|------------------| | ۱ ماهه | 1 | ادمین تعیین می‌کند | ادمین تعیین می‌کند | | ۳ ماهه | 3 | ادمین تعیین می‌کند | ادمین تعیین می‌کند | | ۶ ماهه | 6 | ادمین تعیین می‌کند | ادمین تعیین می‌کند | | ۱۲ ماهه | 12 | ادمین تعیین می‌کند | ادمین تعیین می‌کند | > ادمین می‌تواند دوره‌های دلخواه اضافه، ویرایش یا غیرفعال کند. #### نیازمندی‌های کارکردی - **F2.1** — ادمین برای هر ترکیب (پنل × دوره) یک قیمت تعریف می‌کند - **F2.2** — ادمین می‌تواند دوره‌های جدید اضافه کند (مثلاً ۲ ماهه) یا دوره‌ای را غیرفعال کند - **F2.3** — کلینیک/دکتر پنل + دوره را انتخاب و از طریق gateway موجود (Mellat/SEP) پرداخت می‌کند - **F2.4** — پس از پرداخت موفق، اشتراک فعال می‌شود: `starts_at = now`, `expires_at = now + duration_months * 30 * 86400` - **F2.5** — تمدید: اگر اشتراک فعال باشد، `starts_at` از تاریخ انقضای قبلی محاسبه می‌شود (نه از now) - **F2.6** — gate: `hasFeature('patient_records')` — بررسی اشتراک فعال و expired نبودن - **F2.7** — گزارش فروش پنل‌ها در داشبورد ادمین (تعداد، درآمد، بر اساس دوره و سطح) - **F2.8** — نمایش تاریخ انقضا و هشدار ۷ روز قبل به کلینیک/دکتر #### موجودیت‌های جدید مورد نیاز ``` SubscriptionPlan: - id, uuid - name: 'free' | 'basic' | 'professional' - level: int (0/1/2) - max_secretaries: int (1/2/5) - features: json { patient_records: bool, services: bool, sms_panel: bool } - active: bool - created_at, updated_at SubscriptionPeriod: - id, uuid - plan_id (FK → subscription_plans) - label: string (مثال: "۶ ماهه", "سالانه") - duration_months: int (1, 3, 6, 12, ...) - price_rials: int (قیمت این دوره برای این پنل) - active: bool - sort_order: int (ترتیب نمایش) - created_at, updated_at ClinicSubscription: - id, uuid - entity_type: 'doctor' | 'clinic' - entity_id: int - plan_id (FK → subscription_plans) - period_id (FK → subscription_periods) - payment_id (FK → payments, nullable) - starts_at: int (Unix timestamp) - expires_at: int (Unix timestamp — null = بی‌نهایت برای Free) - created_at ``` #### وابستگی به Payment موجود - `Payment.type = 'subscription'` ✅ (از قبل موجود) - Callback در `PaymentController::subscriptionCallback()`: ایجاد `ClinicSubscription` پس از تأیید #### API endpoints | Method | Path | Permission | |--------|------|-----------| | `GET` | `/api/v1/subscription/plans` | public — لیست پنل‌ها با دوره‌ها و قیمت‌ها | | `GET` | `/api/v1/subscription/my` | clinic/doctor — اشتراک فعال + تاریخ انقضا | | `POST` | `/api/v1/subscription-payment` | clinic/doctor — `{ period_uuid }` | | `GET` | `/api/v1/admin/subscription/plans` | admin — مدیریت پنل‌ها | | `POST` | `/api/v1/admin/subscription/plan` | admin | | `PATCH` | `/api/v1/admin/subscription/plan/{uuid}` | admin | | `POST` | `/api/v1/admin/subscription/period` | admin — افزودن دوره جدید | | `PATCH` | `/api/v1/admin/subscription/period/{uuid}` | admin — ویرایش قیمت/مدت | | `DELETE` | `/api/v1/admin/subscription/period/{uuid}` | admin — غیرفعال‌سازی | | `GET` | `/api/v1/admin/subscription/report` | admin — گزارش فروش | #### Frontend - صفحه کلینیک/دکتر: `SubscriptionPage.tsx` - نمایش پنل فعال + تاریخ انقضا (شمسی) - جدول مقایسه پنل‌ها با انتخاب دوره (مثل toggle ماهانه/سالانه) - دکمه خرید → redirect به gateway - صفحه ادمین: `AdminSubscriptionPage.tsx` - تب «پنل‌ها»: ویرایش قیمت دوره‌ها (DataTable با inline edit) - تب «گزارش»: فروش بر اساس بازه زمانی، سطح، دوره --- ### اپیک ۳ — منشی (Secretary) — تکمیل #### توضیح جدول `doctor_secretaries` و entity `DoctorSecretary` موجود است. نیاز به: - محدودیت تعداد منشی بر اساس پنل - صفحه فرانت‌اند کامل برای مدیریت منشیان و تنظیم دسترسی‌ها #### نیازمندی‌های کارکردی - **F3.1** — بررسی سقف تعداد منشی قبل از ایجاد (free→1, basic→2, pro→5) - **F3.2** — UI کامل: لیست منشیان + اضافه کردن + ویرایش دسترسی + غیرفعال‌سازی - **F3.3** — پنل دسترسی: checkbox matrix برای هر منشی (permissions JSON موجود) - نوبت‌ها: view, create, cancel, update_status - آدرس‌ها: view, create, update, delete - اطلاعات کلینیک: view, update - بیمه‌ها: view, create, update, delete - **F3.4** — منشی هرگز حذف نمی‌شود (soft delete با `active: false`) #### وضعیت فعلی ```php // DoctorSecretary.DEFAULT_PERMISSIONS — موجود // API موجود: GET /api/v1/secretaries/{doctorUuid}, POST /api/v1/secretary, PATCH, DELETE // صفحه SecretariesPage.tsx موجود — نیاز به بررسی کامل بودن ``` #### تغییرات مورد نیاز - Backend: اضافه کردن بررسی سقف پنل در `SecretaryController::create()` - Frontend: ویرایشگر گرافیکی permissions (checkbox matrix در Modal) --- ### اپیک ۴ — سرویس‌های کلینیک (Clinic Services) #### توضیح دسترسی فقط در پنل Basic و بالاتر. سرویس‌ها در دو سطح تعریف می‌شوند: بخش و زیر بخش. #### ساختار سرویس ``` ServiceSection (بخش — مثال: تزریقات، پانسمان) └── ServiceItem (زیر بخش — مثال: سرم) - section_id (FK) - staff_id (FK → clinic_staff) — پرسنل انجام‌دهنده - price (ریال) - active ``` #### نیازمندی‌های کارکردی - **F4.1** — CRUD بخش‌ها (ServiceSection) - **F4.2** — CRUD زیر بخش‌ها (ServiceItem) با انتخاب بخش و پرسنل - **F4.3** — قیمت هر زیر بخش قابل ویرایش - **F4.4** — gate: `hasFeature('services')` — بدون Basic+ → 403 #### موجودیت‌های جدید مورد نیاز ``` ServiceSection: - id, uuid - entity_type: 'doctor' | 'clinic', entity_id - name - active, created_at, updated_at ServiceItem: - id, uuid - section_id (FK → service_sections) - staff_id (FK → clinic_staff, nullable) - name, price_rials - active, created_at, updated_at ``` #### API endpoints | Method | Path | Permission | |--------|------|-----------| | `GET` | `/api/v1/service-sections` | clinic/doctor | | `POST` | `/api/v1/service-section` | clinic/doctor (basic+) | | `PATCH` | `/api/v1/service-section/{uuid}` | clinic/doctor | | `DELETE` | `/api/v1/service-section/{uuid}` | clinic/doctor | | `GET` | `/api/v1/service-items/{sectionUuid}` | clinic/doctor | | `POST` | `/api/v1/service-item` | clinic/doctor (basic+) | | `PATCH` | `/api/v1/service-item/{uuid}` | clinic/doctor | | `DELETE` | `/api/v1/service-item/{uuid}` | clinic/doctor | #### Frontend - صفحه: `ServicesPage.tsx` با دو سطح accordion: بخش‌ها و زیر بخش‌ها --- ### اپیک ۵ — پنل پیامکی (SMS Panel) #### توضیح زیرساخت SMS (SmsLog, SmsTemplate, SmsProvider) موجود است. باید پنل شارژی برای هر کلینیک/دکتر اضافه شود. #### نیازمندی‌های کارکردی - **F5.1** — کیف پول پیامک جداگانه از کیف پول مالی (یا همان wallet با type مجزا) - **F5.2** — شارژ کردن پنل پیامک از طریق gateway موجود - **F5.3** — ادمین تعرفه هر پیامک را در SiteConfig تعیین می‌کند (`sms_price_rials`) - **F5.4** — کسر خودکار هزینه از پنل پس از هر ارسال موفق - **F5.5** — تنظیمات ارسال پیامک (در صفحه تنظیمات کلینیک): - یادآوری نوبت: فعال/غیرفعال + چند ساعت قبل - پیام بعد از ویزیت: فعال/غیرفعال + متن قابل تنظیم - **F5.6** — گزارش لاگ پیامک‌های هر کلینیک/دکتر - **F5.7** — گزارش ادمین: درآمد پیامکی، مصرف هر کلینیک #### موجودیت‌های جدید/تغییر یافته ``` SmsWallet (یا افزودن فیلد به Doctor/Clinic): - entity_type, entity_id - balance_rials (موجودی) - created_at, updated_at SmsSettings: - entity_type, entity_id - reminder_enabled (bool) - reminder_hours_before (int) - post_visit_enabled (bool) - post_visit_text (text) - updated_at ``` #### API endpoints | Method | Path | Permission | |--------|------|-----------| | `GET` | `/api/v1/sms/wallet/balance` | clinic/doctor | | `POST` | `/api/v1/sms/wallet/charge` | clinic/doctor | | `GET` | `/api/v1/sms/wallet/logs` | clinic/doctor | | `GET` | `/api/v1/sms/settings` | clinic/doctor | | `PATCH` | `/api/v1/sms/settings` | clinic/doctor | | `GET` | `/api/v1/admin/sms/wallet-report` | admin | #### Frontend - تب «پیامک» در صفحه تنظیمات کلینیک/دکتر - نمایش موجودی + دکمه شارژ + لاگ --- ### اپیک ۶ — پرونده بیمار (Patient Records) #### توضیح دسترسی در پنل Basic+. پرونده بیمار به صورت خودکار پس از تأیید نوبت ایجاد می‌شود یا دستی توسط منشی/دکتر. #### ساختار پرونده ``` PatientRecord (پرونده بیمار): - entity_type, entity_id (کلینیک/مطب که پرونده به آن تعلق دارد) - user_id (FK → users — بیمار) - created_by (منشی/دکتر که ایجاد کرده) - created_at PatientSession (مراجعه/ویزیت): - record_id (FK → patient_records) - appointment_id (FK → appointments, nullable — اگر از نوبت) - insurance_base_id (FK → categories, bundle='insurance_type') - insurance_supplementary_id (FK → categories) - visit_price_rials (مبلغ کل ویزیت) - base_insurance_discount_percent (کسر بیمه پایه) - supplementary_discount_percent (کسر بیمه مکمل) - final_price_rials (مبلغ نهایی پس از کسورات) - payment_method: 'cash' | 'card' | 'insurance' | 'pending' - notes (text) - created_at, updated_at SessionService (سرویس انجام‌شده در یک مراجعه): - session_id (FK → patient_sessions) - service_item_id (FK → service_items) - staff_id (FK → clinic_staff — پرسنل انجام‌دهنده) - price_rials (قیمت در زمان ارائه) - created_at ``` #### نیازمندی‌های کارکردی - **F6.1** — ایجاد خودکار PatientRecord پس از تأیید appointment (اگر وجود ندارد) - **F6.2** — ایجاد دستی توسط منشی یا دکتر - **F6.3** — ثبت سشن جدید با: - انتخاب بیمه پایه و تکمیلی (از categories) - تعیین مبلغ ویزیت (از پیش تعیین‌شده یا قابل ویرایش) - محاسبه خودکار مبلغ نهایی - ثبت سرویس‌های انجام شده (از ServiceItems) - تعیین پرسنل انجام‌دهنده - **F6.4** — gate: `hasFeature('patient_records')` — بدون Basic+ → 403 - **F6.5** — تاریخچه مراجعات یک بیمار قابل نمایش #### API endpoints | Method | Path | Permission | |--------|------|-----------| | `GET` | `/api/v1/patients` | clinic/doctor (basic+) | | `POST` | `/api/v1/patient` | clinic/doctor (basic+) | | `GET` | `/api/v1/patient/{uuid}` | clinic/doctor | | `GET` | `/api/v1/patient/{uuid}/sessions` | clinic/doctor | | `POST` | `/api/v1/patient/{uuid}/session` | clinic/doctor | | `PATCH` | `/api/v1/session/{uuid}` | clinic/doctor | #### Frontend - صفحه `PatientsPage.tsx` — لیست بیماران با جستجو - صفحه `PatientDetailPage.tsx` — پرونده کامل + تاریخچه مراجعات - Modal ثبت سشن جدید --- ### اپیک ۷ — داشبورد هوشمند (Smart Dashboard) #### توضیح هر داشبورد (ادمین، کلینیک، مطب، منشی) باید چارت‌های مناسب با فیلترهای role-based داشته باشد. #### نیازمندی‌های کارکردی - **F7.1** — داشبورد ادمین: - چارت: درآمد پلتفرم (ماهانه، هفتگی) - چارت: نوبت‌های ثبت‌شده در بازه زمانی - آمار: تعداد کلینیک‌ها، دکترها، کاربران فعال - گزارش پنل‌های فروخته‌شده - **F7.2** — داشبورد کلینیک/مطب: - نوبت‌های امروز (موجود) - درآمد ماه جاری - تعداد بیماران منحصربه‌فرد - موجودی پیامک - **F7.3** — فیلتر بازه زمانی در همه چارت‌ها (این هفته / این ماه / ۳ ماه / سفارشی) - **F7.4** — فیلتر بر اساس نقش (منشی فقط نوبت‌ها را می‌بیند) --- ## اولویت‌بندی پیاده‌سازی | اولویت | اپیک | دلیل | |--------|------|-------| | 1 | اپیک ۱ (Staff) | پیش‌نیاز اپیک ۴ و ۶ | | 2 | اپیک ۲ (Subscription) | پیش‌نیاز gate checks | | 3 | اپیک ۳ (Secretary - تکمیل) | وابسته به پنل | | 4 | اپیک ۴ (Services) | پیش‌نیاز اپیک ۶ | | 5 | اپیک ۵ (SMS Panel) | مستقل از بقیه | | 6 | اپیک ۶ (Patient Records) | بیشترین وابستگی | | 7 | اپیک ۷ (Dashboard) | آخر — نیاز به داده واقعی | --- ## وابستگی‌های فنی ### وضعیت زیرساخت موجود و قابل استفاده | زیرساخت | فایل | نحوه استفاده در فاز ۲ | |---------|------|----------------------| | Payment gateway | `src/Payment/` | پرداخت پنل اشتراکی و شارژ SMS | | Wallet | `src/Settlement/Entity/WalletTransaction.php` | بررسی مدل برای SMS wallet | | SiteConfig | `src/Config/Entity/SiteConfig.php` | ذخیره قیمت پنل‌ها + تعرفه SMS | | Categories (insurance) | `bundle='insurance_type'` | انتخاب بیمه در سشن | | DoctorSecretary | `src/Secretary/Entity/DoctorSecretary.php` | افزودن بررسی سقف پنل | | SmsLog/SmsTemplate | `src/Sms/Entity/` | زیرساخت ارسال موجود | ### نکات معماری - همه entity‌های جدید از الگوی Unix timestamp استفاده می‌کنند - همه controller‌های جدید از `BaseController` ارث می‌برند - gate check برای features با یک helper در `BaseController` یا `SubscriptionService` پیاده‌سازی شود - `entity_type` + `entity_id` pattern (polymorphic) برای Staff، Services، SmsSettings، Patient Records --- ## معیارهای پذیرش (Definition of Done) برای هر اپیک: - [ ] Entity + Migration ایجاد شده - [ ] Controller + Repository + Service نوشته شده - [ ] API endpoints تست‌پذیر در Swagger (`/api/doc`) - [ ] Frontend page کامل با CRUD - [ ] مستندات `docs/api/` به‌روزرسانی شده - [ ] بررسی gate/permission برای plan-gated features