From a72a6da6215aac9711c412ead759d7fe9b2f055b Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Sun, 14 Jun 2026 21:02:18 +0330 Subject: [PATCH] feat: create phase 2 task documentation for staff management, subscription, secretary completion, clinic services, SMS panel, patient records, and smart dashboard --- .claude/prompt/create-phase2-tasks.md | 575 ++++++++++++++++++++++++++ 1 file changed, 575 insertions(+) create mode 100644 .claude/prompt/create-phase2-tasks.md diff --git a/.claude/prompt/create-phase2-tasks.md b/.claude/prompt/create-phase2-tasks.md new file mode 100644 index 00000000..ef307c05 --- /dev/null +++ b/.claude/prompt/create-phase2-tasks.md @@ -0,0 +1,575 @@ +# ساخت تسک‌های فاز ۲ — ClinicPro + +## زمینه + +PRD فاز ۲ در `docs/PRD/prd.md` تعریف شده و شامل ۷ اپیک است. باید برای هر اپیک یک پوشه تسک در `docs/tasks/` با فایل‌های `task.md`، `architecture.md`، `database.md` و `user_flow.md` ایجاد شود — دقیقاً مطابق ساختار `docs/tasks/task-09-appointment-settings/`. + +## وضعیت فعلی + +### ساختار نمونه (task-09): +``` +docs/tasks/task-09-appointment-settings/ + task.md ← endpoints، نمونه request/response، پیش‌نیازها، زمان تخمینی + architecture.md ← ساختار فایل‌های src/، نمونه entity با Doctrine annotations + database.md ← جداول، ستون‌ها با نوع دقیق، ایندکس‌ها، ساختار JSON ها + user_flow.md ← جریان کاربری با pseudocode و diagram ASCII +``` + +### مسیر نهایی تسک‌های جدید: +``` +docs/phase2_taskes/task-10-staff/ +docs/phase2_taskes/task-11-subscription/ +docs/phase2_taskes/task-12-secretary-completion/ +docs/phase2_taskes/task-13-clinic-services/ +docs/phase2_taskes/task-14-sms-panel/ +docs/phase2_taskes/task-15-patient-records/ +docs/phase2_taskes/task-16-smart-dashboard/ +``` + +### API های موجود (نیازی به پیاده‌سازی ندارند): +- `/api/v1/secretary*` — SecretaryController موجود است +- `/api/v1/subscription-payment` و `/api/v1/subscription-payment/callback/{gateway}` — موجود است +- `/api/v1/sms/send`, `/api/v1/sms/template*` — موجود است +- `/api/v1/wallet/*` — WalletTransaction موجود است (برای SMS wallet الگو می‌گیریم) + +### Entities موجود مرتبط: +- `src/Secretary/Entity/DoctorSecretary.php` — DEFAULT_PERMISSIONS ساختار permissions +- `src/Settlement/Entity/WalletTransaction.php` — الگوی wallet برای SmsWallet +- `src/Payment/Entity/Payment.php` — `TYPE_SUBSCRIPTION` const موجود است +- `src/Sms/Entity/SmsLog.php`, `SmsTemplate.php` — زیرساخت SMS موجود + +## قوانین کلی ساختار فایل + +### قوانین entity در architecture.md: +```php +// همه entity های جدید از این الگو پیروی می‌کنند: +#[ORM\Entity] +#[ORM\Table(name: 'table_name')] +class EntityName +{ + #[ORM\Id, ORM\GeneratedValue, ORM\Column(type: 'integer')] + private ?int $id = null; + + #[ORM\Column(type: 'string', length: 36, unique: true)] + private string $uuid; + + // polymorphic pattern: + #[ORM\Column(type: 'string', length: 10)] + private string $entityType; // 'doctor' | 'clinic' + + #[ORM\Column(type: 'integer')] + private int $entityId; + + #[ORM\Column(type: 'integer')] + private int $createdAt; + + #[ORM\Column(type: 'integer')] + private int $updatedAt; +} +``` + +### قوانین controller: +```php +// همه controller ها از BaseController ارث می‌برند +class XxxController extends BaseController +{ + // پاسخ موفق: $this->success($data) + // لیست paginated: $this->paginated($items, $total, $page, $limit) + // خطا: $this->error(ErrorCodes::ERR_XXX, 'پیام', Response::HTTP_XXX) + // خطای validation: $this->validationError($violations) +} +``` + +### قوانین database.md: +- تاریخ‌ها همه `INT NOT NULL` (Unix timestamp) هستند — هیچ‌گاه DATETIME نه +- `uuid` همیشه `CHAR(36) UNIQUE NOT NULL` +- `entity_type` همیشه `VARCHAR(10)` با مقادیر `'doctor'` یا `'clinic'` +- `entity_id` همیشه `INT NOT NULL` (FK به doctors.id یا clinics.id بسته به entity_type) + +--- + +## وظایف + +### ۱. ساخت `docs/tasks/task-10-staff/` + +**پیش‌نیاز اپیک ۴ و ۶ — باید اول پیاده‌سازی شود.** + +#### `task.md`: +- عنوان: «تسک ۱۰: مدیریت پرسنل (Staff)» +- پیش‌نیازها: تسک ۰۲ (Auth)، تسک ۰۵ (Doctor)، تسک ۰۶ (Clinic) +- زمان تخمینی: ۶ تا ۸ ساعت +- Endpoints: + +| متد | مسیر | توضیح | نیاز به Auth | +|-----|------|-------|-------------| +| GET | `/api/v1/staff` | لیست پرسنل context جاری | بله (Doctor/Clinic) | +| POST | `/api/v1/staff` | ایجاد پرسنل جدید | بله | +| PATCH | `/api/v1/staff/{uuid}` | ویرایش اطلاعات | بله (مالک) | +| PATCH | `/api/v1/staff/{uuid}/toggle` | فعال/غیرفعال | بله (مالک) | + +نمونه Request و Response واقعی با json کامل. + +#### `architecture.md`: +``` +src/Staff/ +├── Controller/StaffController.php +├── Entity/ClinicStaff.php +├── Repository/ClinicStaffRepository.php +└── Service/StaffService.php +``` +Entity `ClinicStaff` با تمام فیلدها با Doctrine annotations دقیق. + +#### `database.md`: +جدول `clinic_staff`: +- id INT UNSIGNED AUTO_INCREMENT PK +- uuid CHAR(36) UNIQUE NOT NULL +- entity_type VARCHAR(10) NOT NULL (`'doctor'` | `'clinic'`) +- entity_id INT NOT NULL +- full_name VARCHAR(200) NOT NULL +- phone VARCHAR(20) NULL +- job_title VARCHAR(100) NULL +- address TEXT NULL +- national_code CHAR(10) NULL +- active TINYINT(1) NOT NULL DEFAULT 1 +- created_at INT NOT NULL +- updated_at INT NOT NULL + +ایندکس: `idx_clinic_staff_entity ON clinic_staff(entity_type, entity_id, active)` + +#### `user_flow.md`: +جریان ایجاد پرسنل + جریان غیرفعال‌سازی (چرا حذف ممنوع است: تاریخچه سرویس‌ها حفظ می‌شود). + +--- + +### ۲. ساخت `docs/tasks/task-11-subscription/` + +**پیش‌نیاز همه gate check ها — باید دوم پیاده‌سازی شود.** + +#### `task.md`: +- عنوان: «تسک ۱۱: پنل اشتراکی (Subscription Tiers)» +- پیش‌نیازها: تسک ۰۲، تسک ۱۵ (Payment موجود) +- زمان تخمینی: ۱۴ تا ۱۶ ساعت +- Endpoints (جدید — هیچ‌کدام موجود نیستند به جز `/api/v1/subscription-payment` که payment callback را handle می‌کند): + +| متد | مسیر | Permission | توضیح | +|-----|------|-----------|-------| +| GET | `/api/v1/subscription/plans` | public | لیست پنل‌ها + دوره‌ها + قیمت‌ها | +| GET | `/api/v1/subscription/my` | doctor/clinic | اشتراک فعال + `used_trial` flag | +| POST | `/api/v1/subscription/trial` | doctor/clinic | فعال‌سازی تریال Basic (یک‌بار) | +| GET | `/api/v1/admin/subscription/plans` | ROLE_ADMIN | لیست پنل‌ها | +| POST | `/api/v1/admin/subscription/plan` | ROLE_ADMIN | ایجاد پنل | +| PATCH | `/api/v1/admin/subscription/plan/{uuid}` | ROLE_ADMIN | ویرایش پنل | +| POST | `/api/v1/admin/subscription/period` | ROLE_ADMIN | افزودن دوره | +| PATCH | `/api/v1/admin/subscription/period/{uuid}` | ROLE_ADMIN | ویرایش دوره | +| DELETE | `/api/v1/admin/subscription/period/{uuid}` | ROLE_ADMIN | غیرفعال‌سازی | +| GET | `/api/v1/admin/subscription/report` | ROLE_ADMIN | گزارش فروش | + +نکته: `/api/v1/subscription-payment` قبلاً در `PaymentController` موجود است — callback آن هم موجود است. فقط باید بعد از callback موفق، `ClinicSubscription` ساخته شود (این وابستگی باید توضیح داده شود). + +نمونه Response برای `GET /api/v1/subscription/my`: +```json +{ + "success": true, + "data": { + "plan": { "name": "basic", "level": 1, "features": {"patient_records": true, "services": true} }, + "period": { "label": "۶ ماهه", "duration_months": 6 }, + "is_trial": false, + "starts_at": 1718000000, + "expires_at": 1733360000, + "used_trial": true + } +} +``` + +#### `architecture.md`: +``` +src/Subscription/ +├── Controller/SubscriptionController.php +├── Entity/ +│ ├── SubscriptionPlan.php +│ ├── SubscriptionPeriod.php +│ └── ClinicSubscription.php +├── Repository/ +│ ├── SubscriptionPlanRepository.php +│ ├── SubscriptionPeriodRepository.php +│ └── ClinicSubscriptionRepository.php +└── Service/ + └── SubscriptionService.php ← hasFeature() gate method +``` + +`SubscriptionService::hasFeature(string $feature): bool`: +```php +public function hasFeature(string $feature): bool +{ + // 1. entity_type + entity_id از authStore JWT claim + // 2. آخرین ClinicSubscription فعال: expires_at > time() OR expires_at IS NULL + // 3. plan->features[$feature] === true + // برگشتی false → caller باید $this->error(ErrorCodes::ERR_SUBSCRIPTION_REQUIRED, ..., 403) بزند +} +``` + +Entity‌ها با Doctrine annotations دقیق (نوع `json` برای features در SubscriptionPlan). + +#### `database.md`: +سه جدول کامل: + +**subscription_plans:** +- id, uuid, name VARCHAR(30) ('free'|'basic'|'professional'), level TINYINT, max_secretaries TINYINT +- features JSON (e.g. `{"patient_records": true, "services": true, "sms_panel": false}`) +- active TINYINT(1), created_at INT, updated_at INT + +**subscription_periods:** +- id, uuid, plan_id INT FK→subscription_plans.id +- label VARCHAR(50), duration_months TINYINT, price_rials INT +- is_trial TINYINT(1) DEFAULT 0, active TINYINT(1), sort_order TINYINT +- created_at INT, updated_at INT + +**clinic_subscriptions:** +- id, uuid, entity_type VARCHAR(10), entity_id INT +- plan_id INT FK→subscription_plans.id, period_id INT FK→subscription_periods.id +- payment_id INT NULL FK→payments.id (NULL برای تریال) +- is_trial TINYINT(1), starts_at INT, expires_at INT NULL (NULL = Free بی‌نهایت) +- created_at INT + +ایندکس‌ها: +```sql +INDEX idx_clinic_subscriptions_entity ON clinic_subscriptions(entity_type, entity_id, expires_at); +UNIQUE idx_subscription_trial_once ON clinic_subscriptions(entity_type, entity_id, is_trial) -- جلوگیری از تریال مکرر +``` + +**Seed data اولیه** (باید در migration یا fixture باشد): +```sql +INSERT INTO subscription_plans (uuid, name, level, max_secretaries, features, active) VALUES + (UUID(), 'free', 0, 1, '{"patient_records":false,"services":false,"sms_panel":false}', 1), + (UUID(), 'basic', 1, 2, '{"patient_records":true,"services":true,"sms_panel":false}', 1), + (UUID(), 'professional', 2, 5, '{"patient_records":true,"services":true,"sms_panel":true}', 1); +``` + +#### `user_flow.md`: +- جریان خرید اشتراک (انتخاب پنل + دوره → payment → callback → ClinicSubscription) +- جریان تریال (check used_trial → POST /trial → ClinicSubscription بدون payment_id) +- جریان تمدید (expires_at قبلی + duration_months × 30 × 86400) +- gate check flow: هر endpoint protected → `hasFeature()` → 403 اگر false + +--- + +### ۳. ساخت `docs/tasks/task-12-secretary-completion/` + +#### `task.md`: +- عنوان: «تسک ۱۲: تکمیل منشی — محدودیت پنل + UI Permissions» +- پیش‌نیازها: تسک ۱۴ (Secretary — موجود)، **تسک ۱۱** (Subscription) +- زمان تخمینی: ۴ تا ۵ ساعت +- **هیچ endpoint جدیدی نیست** — فقط تغییر در کد موجود: + - Backend: `src/Secretary/Controller/SecretaryController.php::create()` — اضافه کردن gate check + - Frontend: `assets/admin/pages/SecretariesPage.tsx` — Modal ویرایش permissions + +نمونه کد Backend تغییر (قبل/بعد): +```php +// قبل: +public function create(Request $request): JsonResponse +{ + // validate و ذخیره مستقیم + +// بعد — باید اضافه شود: +public function create(Request $request): JsonResponse +{ + $limit = $this->subscriptionService->getSecretaryLimit(); // 1 یا 2 یا 5 + $current = $this->secretaryRepo->countActive($doctorId); + if ($current >= $limit) { + return $this->error(ErrorCodes::ERR_SECRETARY_LIMIT_REACHED, 'سقف منشی پنل رسیده است', 403); + } +``` + +نمونه کد Frontend permissions checkbox: +```tsx +// در SecretariesPage.tsx — Modal ویرایش +// DoctorSecretary::DEFAULT_PERMISSIONS ساختار را نشان می‌دهد: +// resources: { appointments: { view, create, cancel, update_status }, addresses: {...}, ... } +// باید یک checkbox matrix رندر شود +``` + +#### `architecture.md`: +فایل‌هایی که تغییر می‌کنند (نه فایل جدید): +- `src/Secretary/Controller/SecretaryController.php` — inject `SubscriptionService` +- `assets/admin/pages/SecretariesPage.tsx` — Modal با checkbox matrix + +#### `database.md`: +- هیچ migration لازم نیست +- توضیح ستون `permissions` در جدول `doctor_secretaries` (JSON) + +#### `user_flow.md`: +- جریان تلاش برای افزودن منشی جدید وقتی سقف پنل رسیده +- جریان ویرایش permissions منشی موجود + +--- + +### ۴. ساخت `docs/tasks/task-13-clinic-services/` + +#### `task.md`: +- عنوان: «تسک ۱۳: سرویس‌های کلینیک (Clinic Services)» +- پیش‌نیازها: **تسک ۱۰** (Staff)، **تسک ۱۱** (Subscription — gate check) +- زمان تخمینی: ۸ تا ۱۰ ساعت +- gate: همه write endpoints نیاز به `hasFeature('services')` دارند (Basic+ فقط) +- Endpoints: + +| متد | مسیر | توضیح | +|-----|------|-------| +| GET | `/api/v1/service-sections` | لیست بخش‌ها | +| POST | `/api/v1/service-section` | ایجاد بخش (Basic+) | +| PATCH | `/api/v1/service-section/{uuid}` | ویرایش | +| DELETE | `/api/v1/service-section/{uuid}` | حذف | +| GET | `/api/v1/service-items/{sectionUuid}` | لیست زیربخش‌های یک بخش | +| POST | `/api/v1/service-item` | ایجاد زیربخش (Basic+) | +| PATCH | `/api/v1/service-item/{uuid}` | ویرایش | +| DELETE | `/api/v1/service-item/{uuid}` | حذف | + +#### `architecture.md`: +``` +src/ClinicService/ +├── Controller/ClinicServiceController.php +├── Entity/ +│ ├── ServiceSection.php +│ └── ServiceItem.php +└── Repository/ + ├── ServiceSectionRepository.php + └── ServiceItemRepository.php +``` + +#### `database.md`: + +**service_sections:** +- id, uuid, entity_type VARCHAR(10), entity_id INT, name VARCHAR(200), active TINYINT(1) DEFAULT 1 +- created_at INT, updated_at INT +- INDEX: `idx_service_sections_entity ON service_sections(entity_type, entity_id)` + +**service_items:** +- id, uuid, section_id INT FK→service_sections.id ON DELETE CASCADE +- staff_id INT NULL FK→clinic_staff.id ON DELETE SET NULL +- name VARCHAR(200), price_rials INT NOT NULL DEFAULT 0, active TINYINT(1) DEFAULT 1 +- created_at INT, updated_at INT + +#### `user_flow.md`: +- جریان ایجاد ساختار دو سطحی (بخش → زیربخش) +- جریان انتخاب پرسنل انجام‌دهنده +- gate check — کاربر Free تلاش می‌کند سرویس بسازد → 403 + +--- + +### ۵. ساخت `docs/tasks/task-14-sms-panel/` + +#### `task.md`: +- عنوان: «تسک ۱۴: پنل پیامکی — کیف پول + تنظیمات» +- پیش‌نیازها: تسک ۱۷ (SMS infrastructure موجود)، تسک ۱۵ (Payment موجود) +- زمان تخمینی: ۱۰ تا ۱۲ ساعت +- نکته: `src/Sms/` و `src/Settlement/` موجودند — کد جدید در `src/Sms/` اضافه می‌شود +- Endpoints جدید: + +| متد | مسیر | Permission | توضیح | +|-----|------|-----------|-------| +| GET | `/api/v1/sms/wallet/balance` | doctor/clinic | موجودی | +| POST | `/api/v1/sms/wallet/charge` | doctor/clinic | شارژ — `{ gateway, amount_rials }` | +| GET | `/api/v1/sms/wallet/logs` | doctor/clinic | تاریخچه کسر/شارژ | +| GET | `/api/v1/sms/settings` | doctor/clinic | تنظیمات | +| PATCH | `/api/v1/sms/settings` | doctor/clinic | ذخیره تنظیمات | +| GET | `/api/v1/admin/sms/wallet-report` | ROLE_ADMIN | گزارش مصرف | + +#### `architecture.md`: +Entity های جدید در `src/Sms/Entity/`: +```php +// SmsWallet.php — الگو از WalletTransaction.php در src/Settlement/Entity/ +// SmsSettings.php — key-value per entity +``` + +Controller جدید: `src/Sms/Controller/SmsWalletController.php` +شارژ کیف پول: redirect به gateway موجود با `Payment.type = 'sms_wallet'` (const جدید در Payment entity) + +#### `database.md`: + +**sms_wallets:** +- id, entity_type VARCHAR(10), entity_id INT (UNIQUE PAIR) +- balance_rials INT NOT NULL DEFAULT 0, created_at INT, updated_at INT +- UNIQUE INDEX: `idx_sms_wallets_entity ON sms_wallets(entity_type, entity_id)` + +**sms_wallet_transactions:** +- id, uuid, sms_wallet_id INT FK→sms_wallets.id +- type VARCHAR(10) ('credit'|'debit'), amount_rials INT, description VARCHAR(255) NULL +- payment_id INT NULL FK→payments.id, created_at INT + +**sms_settings:** +- id, entity_type VARCHAR(10), entity_id INT (UNIQUE PAIR) +- reminder_enabled TINYINT(1) DEFAULT 0, reminder_hours_before TINYINT DEFAULT 2 +- post_visit_enabled TINYINT(1) DEFAULT 0, post_visit_text TEXT NULL, updated_at INT +- UNIQUE INDEX: `idx_sms_settings_entity ON sms_settings(entity_type, entity_id)` + +SiteConfig key جدید: `sms_price_rials` (ادمین مقدار می‌دهد) + +#### `user_flow.md`: +- جریان شارژ کیف پول (مثل payment اما `type='sms_wallet'`) +- جریان کسر خودکار هنگام ارسال پیامک (hook در SmsService) +- جریان تنظیم یادآوری خودکار + +--- + +### ۶. ساخت `docs/tasks/task-15-patient-records/` + +#### `task.md`: +- عنوان: «تسک ۱۵: پرونده بیمار (Patient Records)» +- پیش‌نیازها: **تسک ۱۰** (Staff)، **تسک ۱۱** (Subscription)، **تسک ۱۳** (Services) +- زمان تخمینی: ۱۶ تا ۲۰ ساعت +- gate: همه endpoints نیاز به `hasFeature('patient_records')` (Basic+ فقط) +- Endpoints: + +| متد | مسیر | توضیح | +|-----|------|-------| +| GET | `/api/v1/patients` | لیست بیماران — query: `?search=` | +| POST | `/api/v1/patient` | ایجاد پرونده دستی | +| GET | `/api/v1/patient/{uuid}` | جزئیات پرونده + خلاصه | +| GET | `/api/v1/patient/{uuid}/sessions` | لیست مراجعات | +| POST | `/api/v1/patient/{uuid}/session` | ثبت مراجعه جدید | +| PATCH | `/api/v1/session/{uuid}` | ویرایش مراجعه | + +نمونه Request ثبت سشن: +```json +{ + "appointment_uuid": "optional-uuid", + "insurance_base_uuid": "category-uuid", + "insurance_supplementary_uuid": null, + "visit_price_rials": 500000, + "base_insurance_discount_percent": 30, + "supplementary_discount_percent": 0, + "payment_method": "cash", + "notes": "...", + "services": [ + { "service_item_uuid": "...", "staff_uuid": "..." } + ] +} +``` + +نمونه Response (final_price محاسبه‌شده): +```json +{ + "success": true, + "data": { + "uuid": "...", + "visit_price_rials": 500000, + "base_insurance_discount_percent": 30, + "supplementary_discount_percent": 0, + "services_total_rials": 150000, + "final_price_rials": 500000, + "payment_method": "cash" + } +} +``` + +فرمول محاسبه: +``` +after_base = visit_price × (1 - base_discount/100) +after_supp = after_base × (1 - supp_discount/100) +final = round(after_supp) + sum(service_item.price_rials) +``` + +#### `architecture.md`: +``` +src/Patient/ +├── Controller/PatientController.php +├── Entity/ +│ ├── PatientRecord.php +│ ├── PatientSession.php +│ └── SessionService.php +├── Repository/ +│ ├── PatientRecordRepository.php +│ └── PatientSessionRepository.php +└── Service/ + └── PatientService.php ← calculateFinalPrice(), autoCreateOnAppointmentConfirm() +``` + +نکته در architecture.md: `autoCreateOnAppointmentConfirm()` باید از `AppointmentController::updateStatus()` صدا شود — وقتی status به `'confirmed'` تغییر می‌کند، PatientRecord چک/ایجاد می‌شود. + +#### `database.md`: + +**patient_records:** +- id, uuid, entity_type VARCHAR(10), entity_id INT +- user_id INT FK→users.id ON DELETE RESTRICT +- created_by_type VARCHAR(15) ('doctor'|'secretary'|'system'), created_by_id INT +- created_at INT +- UNIQUE: `idx_patient_record_unique ON patient_records(entity_type, entity_id, user_id)` + +**patient_sessions:** +- id, uuid, record_id INT FK→patient_records.id ON DELETE CASCADE +- appointment_id INT NULL FK→appointments.id ON DELETE SET NULL +- insurance_base_id INT NULL FK→categories.id, insurance_supplementary_id INT NULL FK→categories.id +- visit_price_rials INT NOT NULL DEFAULT 0 +- base_insurance_discount_percent DECIMAL(5,2) DEFAULT 0 +- supplementary_discount_percent DECIMAL(5,2) DEFAULT 0 +- services_total_rials INT NOT NULL DEFAULT 0 +- final_price_rials INT NOT NULL +- payment_method VARCHAR(15) ('cash'|'card'|'insurance'|'pending') +- notes TEXT NULL, created_at INT, updated_at INT + +**session_services:** +- id, uuid, session_id INT FK→patient_sessions.id ON DELETE CASCADE +- service_item_id INT FK→service_items.id ON DELETE RESTRICT +- staff_id INT NULL FK→clinic_staff.id ON DELETE SET NULL +- price_rials INT NOT NULL ← کپی از service_item.price_rials در زمان ثبت +- created_at INT + +ایندکس‌ها: +```sql +INDEX idx_patient_records_entity ON patient_records(entity_type, entity_id); +INDEX idx_patient_sessions_record ON patient_sessions(record_id, created_at); +``` + +#### `user_flow.md`: +- جریان خودکار: تأیید نوبت → چک PatientRecord → ایجاد اگر نبود → ایجاد PatientSession +- جریان دستی: منشی/دکتر → جستجو بیمار → ایجاد پرونده → ثبت مراجعه + سرویس‌ها +- محاسبه final_price با step by step مثال عددی +- جریان جستجو بیمار (search در patients API) + +--- + +### ۷. ساخت `docs/tasks/task-16-smart-dashboard/` + +#### `task.md`: +- عنوان: «تسک ۱۶: داشبورد هوشمند — چارت + فیلتر زمانی» +- پیش‌نیازها: همه تسک‌های قبل — نیاز به داده واقعی دارد +- زمان تخمینی: ۸ تا ۱۰ ساعت +- **هیچ endpoint جدیدی نیست** — فقط پارامتر `from` و `to` به endpoint های موجود اضافه می‌شود: + - `GET /api/v1/admin/dashboard/charts?from=UNIX&to=UNIX` + - `GET /api/v1/dashboard/clinic?from=UNIX&to=UNIX` + - `GET /api/v1/dashboard/doctor?from=UNIX&to=UNIX` + +فیلدهای جدید در response داشبورد کلینیک/دکتر: +```json +{ + "sms_wallet_balance": 150000, + "unique_patients_count": 45, + "revenue_current_month": 12500000 +} +``` + +#### `architecture.md`: +فایل‌هایی که تغییر می‌کنند: +- `src/Dashboard/Controller/DashboardController.php` — اضافه کردن `from`/`to` به query +- `assets/admin/pages/DashboardPage.tsx` — date range selector + نمودار (Recharts) + +نکته: Recharts پیشنهادی است (سبک، tree-shakeable). نصب با `yarn add recharts`. + +#### `database.md`: +- هیچ migration لازم نیست +- query های DQL که باید به `from`/`to` محدود شوند + +#### `user_flow.md`: +- کاربر date range انتخاب می‌کند → charts refresh می‌شوند +- preset ها: «این هفته» / «این ماه» / «۳ ماه» / «سفارشی» +- تبدیل تاریخ شمسی به Unix timestamp برای ارسال به API + +--- + +## نکات مهم + +- **ترتیب پیاده‌سازی اجباری است**: task-10 → task-11 → task-12 → task-13 → task-14 → task-15 → task-16 +- **حذف سخت ممنوع** در ClinicStaff — فقط `active=false` +- **UNIQUE constraint در تریال**: یک entity نمی‌تواند دو بار از تریال استفاده کند — index روی `(entity_type, entity_id, is_trial)` در `clinic_subscriptions` +- **price_rials در session_services کپی می‌شود** — تغییر قیمت سرویس در آینده تأثیری روی سشن‌های قبلی ندارد +- **patient_records UNIQUE per entity+user** — یک بیمار یک پرونده در هر کلینیک/مطب دارد (مراجعات چندگانه = سشن‌های جداگانه در همان پرونده) +- **فایل doc** برای هر اپیک بعد از پیاده‌سازی باید ایجاد شود (`docs/api/staff.md`، `docs/api/subscription.md`، `docs/api/clinic-services.md`، `docs/api/patient.md`)