Files
clinicpro/PRD/prd.md
T

436 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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