From 70739691d1cd647d4f7d79fa3d01d8d9d99b4153 Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Thu, 30 Jul 2026 12:12:45 +0330 Subject: [PATCH] Add checklists for tasks 11 to 14 covering credit ledger, treatment course, cancellation policies, and event utilization - Created checklist for task 11: Package and Credit Ledger - Created checklist for task 12: Treatment Course - Created checklist for task 13: Cancellation Policy, No-Show, and Waitlist - Created checklist for task 14: Domain Events and Utilization Reports --- .../taskes/00-current-state-report.md | 52 ++++-- docs/new_feture/taskes/README.md | 160 +++++++++++++----- .../taskes/task-01-branch-room/checklist.md | 92 ++++++++++ .../task-02-resource-model/checklist.md | 100 +++++++++++ .../task-03-resource-calendar/checklist.md | 113 +++++++++++++ .../task-04-service-catalog-v2/checklist.md | 111 ++++++++++++ .../task-05-appointment-plan/checklist.md | 104 ++++++++++++ .../task-06-availability-engine/checklist.md | 119 +++++++++++++ .../taskes/task-07-hold-and-book/checklist.md | 122 +++++++++++++ .../task-08-pricing-snapshot/checklist.md | 108 ++++++++++++ .../taskes/task-09-policy-engine/checklist.md | 120 +++++++++++++ .../task-10-policy-admin-sandbox/checklist.md | 102 +++++++++++ .../checklist.md | 114 +++++++++++++ .../task-12-treatment-course/checklist.md | 115 +++++++++++++ .../checklist.md | 128 ++++++++++++++ .../task-14-events-utilization/checklist.md | 119 +++++++++++++ 16 files changed, 1726 insertions(+), 53 deletions(-) create mode 100644 docs/new_feture/taskes/task-01-branch-room/checklist.md create mode 100644 docs/new_feture/taskes/task-02-resource-model/checklist.md create mode 100644 docs/new_feture/taskes/task-03-resource-calendar/checklist.md create mode 100644 docs/new_feture/taskes/task-04-service-catalog-v2/checklist.md create mode 100644 docs/new_feture/taskes/task-05-appointment-plan/checklist.md create mode 100644 docs/new_feture/taskes/task-06-availability-engine/checklist.md create mode 100644 docs/new_feture/taskes/task-07-hold-and-book/checklist.md create mode 100644 docs/new_feture/taskes/task-08-pricing-snapshot/checklist.md create mode 100644 docs/new_feture/taskes/task-09-policy-engine/checklist.md create mode 100644 docs/new_feture/taskes/task-10-policy-admin-sandbox/checklist.md create mode 100644 docs/new_feture/taskes/task-11-package-credit-ledger/checklist.md create mode 100644 docs/new_feture/taskes/task-12-treatment-course/checklist.md create mode 100644 docs/new_feture/taskes/task-13-cancellation-waitlist/checklist.md create mode 100644 docs/new_feture/taskes/task-14-events-utilization/checklist.md diff --git a/docs/new_feture/taskes/00-current-state-report.md b/docs/new_feture/taskes/00-current-state-report.md index 1a35f924..add612e7 100644 --- a/docs/new_feture/taskes/00-current-state-report.md +++ b/docs/new_feture/taskes/00-current-state-report.md @@ -128,6 +128,24 @@ JSON هفتگی per `(doctor, clinic)`، هر روز چند `session` با - تنها منبعی که تداخلش بررسی می‌شود پزشک است؛ اگر دو سرویس هم‌زمان به یک پرسنل یا یک دستگاه نیاز داشته باشند، سیستم متوجه نمی‌شود. +### ۲-۵ب حالت سرویسی **نیمه‌کاره** است — پنج شکاف در چرخهٔ عمر نوبت + +مسیر **رزرو** کار می‌کند، ولی بقیهٔ چرخهٔ عمر نه. این‌ها پیش‌نیاز موتور چندمنبعی‌اند و +تسک‌های [۰۰](task-00-service-mode-completion/) و [۰۰ب](task-00b-nobat724-service-mode/) +می‌بندندشان: + +| # | شکاف | محل | +|---|---|---| +| ۱ | `PATCH /appointment/{uuid}` مدت دلخواه می‌پذیرد؛ بافر را نادیده می‌گیرد؛ فقط `service_item_uuid` تکی را به‌روز می‌کند در حالی که `service_items` (ManyToMany) دست‌نخورده می‌ماند | [AppointmentController.php:1077](../../../src/Appointment/Controller/AppointmentController.php) | +| ۲ | `AppointmentEditPage` سه فیلد آزاد `date`/`start`/`end` دارد و هیچ `ServiceSlotPicker` ای ندارد — منشی نوبت ۴۵ دقیقه‌ای را ۲۰ دقیقه می‌کند و سیستم قبول می‌کند | [AppointmentEditPage.tsx:74](../../../assets/admin/pages/AppointmentEditPage.tsx) | +| ۳ | نوبت رزرو (`is_reserve`) صریحاً از حالت سرویسی حذف شده (`serviceMode = mode === 'service' && !isReserve`) و مسیر تبدیل رزرو به نوبت سرویسی وجود ندارد | [NewAppointmentDrawer.tsx:72](../../../assets/admin/components/NewAppointmentDrawer.tsx) | +| ۴ | سایت عمومی چهار رنگ hard-code در مرحلهٔ انتخاب سرویس دارد (`#5559CE`, `#3B3B3B`, `#7A7A7A`, `bg-white`) و در دارک‌مود می‌شکند؛ همچنین مدت را **موازی با بک‌اند** حساب می‌کند | `nobat724_front/components/appointment/service/index.js` | +| ۵ | پنل کاربر سایت نام سرویس و مدت نوبت را نشان نمی‌دهد و مسیر جابه‌جایی سرویس‌آگاه ندارد | `nobat724_front/.../turns/Card.js` · `isTurnsDetails/*` | + +نکتهٔ ۴ دو مشکل در یک فایل است: انحراف از دیزاین‌سیستم، و منبع دوم حقیقت برای مدت. +دومی مهم‌تر است — وقتی تسک ۰۴ فرمول را به «زمان تنها / زمان اضافه» عوض کند، سایت عدد +قدیمی نشان می‌دهد و بیمار مدتی می‌بیند که با مدت واقعی نوبتش نمی‌خواند. + ### ۲-۶ ثبت نوبت و همزمانی [src/Appointment/Entity/Appointment.php](../../../src/Appointment/Entity/Appointment.php): @@ -182,6 +200,7 @@ no_show, following_up, salon` + `AppointmentEvent` برای تاریخچه. تق | بخش مستند | دارد | ندارد | تسک | |---|---|---|---| +| — نوبت‌دهی سرویسی موجود | مسیر رزرو (پنل + سایت) | ویرایش، جابه‌جایی، رزرو، پنل بیمار، دیزاین‌سیستم سایت | **۰۰، ۰۰ب** | | ۴ کلینیک/شعبه/اتاق | tenant دوسطحی | Branch، Room، ساعت کاری شعبه | ۰۱ | | ۵ تعریف خدمات | سرویس، قیمت، مدت، بیمه | گروه آیتم، دو نوع زمان، ناسازگاری، override شعبه | ۰۴ | | ۶ منابع | پرسنل بدون تقویم | نوع منبع، ظرفیت، مهارت، استخر، نیازمندی | ۰۲، ۰۳ | @@ -222,14 +241,27 @@ no_show, following_up, salon` + `AppointmentEvent` برای تاریخچه. تق ## ۵. ترتیب اجرا ``` -۰۱ شعبه/اتاق ─┬─ ۰۲ منابع و مهارت ── ۰۳ تقویم منبع ─┐ - └─ ۰۴ کاتالوگ خدمات v2 ── ۰۵ بخش‌های نوبت ─┴─ ۰۶ جستجوی وقت ── ۰۷ رزرو و ثبت - │ - ۰۸ قیمت‌گذاری و snapshot ────────────────┘ - │ - ۰۹ موتور قوانین ── ۱۰ فرم و sandbox قانون - │ - ۱۱ پکیج و دفتر اعتبار ── ۱۲ دوره درمان ── ۱۳ لغو/عدم‌حضور/لیست انتظار - │ - ۱۴ رویدادها و گزارش بهره‌وری +۰۰ تکمیل سرویسی (clinicpro) ── ۰۰ب سازگارسازی سایت ← فاز ۰، پیش‌نیاز بقیه + │ + ├─ ۰۱ شعبه/اتاق ─┬─ ۰۲ منابع و مهارت ── ۰۳ تقویم منبع ─┐ + │ └─ ۰۴ کاتالوگ v2 ── ۰۵ بخش‌های نوبت ─┴─ ۰۶ جستجوی وقت ── ۰۷ رزرو و ثبت + │ │ + │ ۰۸ قیمت‌گذاری و snapshot ───────────────┘ + │ │ + │ ۰۹ موتور قوانین ── ۱۰ فرم و sandbox قانون + │ │ + │ ۱۱ پکیج و دفتر اعتبار ── ۱۲ دوره درمان ── ۱۳ لغو/عدم‌حضور/انتظار + │ │ + └──────────────────────── ۱۴ رویدادها و گزارش بهره‌وری ``` + +**فاز ۰ اختیاری نیست.** اگر حالت `resource` روی حالت `service` نیمه‌کاره ساخته شود، هر +باگ موجود سرویسی به موتور جدید ارث می‌رسد و تشخیص منبعش غیرممکن می‌شود. + +## ۶. سه قاعدهٔ حاکم بر همهٔ تسک‌ها + +| سند | چه می‌گوید | +|---|---| +| [_shared/red-lines.md](_shared/red-lines.md) | منطق اسلاتی به هیچ عنوان دست‌کاری نمی‌شود · فهرست کامل فایل‌های قفل‌شده · تست `--group=slot-mode-frozen` | +| [_shared/ui-conventions.md](_shared/ui-conventions.md) | هر صفحه یا بخش جدید عیناً با دیزاین‌سیستم موجود — توکن‌ها، کامپوننت‌های `ui/`، پنج قاعدهٔ غیرقابل‌مذاکره | +| [_shared/definition-of-done.md](_shared/definition-of-done.md) | هیچ تسکی بدون تکمیل چک‌لیستش تمام نیست — ✅ 🔄 ⏳ ⚠️ | diff --git a/docs/new_feture/taskes/README.md b/docs/new_feture/taskes/README.md index c6eecb68..413a5ad9 100644 --- a/docs/new_feture/taskes/README.md +++ b/docs/new_feture/taskes/README.md @@ -3,17 +3,34 @@ پیاده‌سازی تدریجی [clinic-pro-mostanad-sade.md](../clinic-pro-mostanad-sade.md) روی کد موجود. گزارش وضعیت فعلی و تحلیل شکاف: [00-current-state-report.md](00-current-state-report.md) -> **پیش‌فرض کلیدی:** بازنویسی نداریم. نوبت‌دهی اسلاتی (`booking_mode=slot`) و نوبت‌دهی -> سرویسیِ فعلی (`booking_mode=service`) تا آخر این مسیر بدون تغییر رفتار کار می‌کنند. -> حالت جدید `booking_mode=resource` کنارشان اضافه می‌شود. +--- + +## ⛔ سه قاعده‌ای که پیش از هر تسکی باید بخوانی + +| سند | چه می‌گوید | +|---|---| +| [_shared/red-lines.md](_shared/red-lines.md) | **منطق اسلاتی به هیچ عنوان دست‌کاری نمی‌شود** · نوبت‌دهی سرویسی در همین فاز کامل می‌شود | +| [_shared/ui-conventions.md](_shared/ui-conventions.md) | **هر صفحه یا بخش جدید عیناً با دیزاین‌سیستم موجود** — هیچ طراحی جدید | +| [_shared/definition-of-done.md](_shared/definition-of-done.md) | **هیچ تسکی بدون تکمیل چک‌لیستش تمام نیست** — ✅ 🔄 ⏳ ⚠️ | + +در تناقض، این سه سند بر متن تسک‌ها برنده‌اند. --- ## لیست تسک‌ها -| تسک | ماژول | Endpoint جدید | وابستگی | زمان | -|-----|-------|--------------|---------|------| -| [۰۱](task-01-branch-room/) | شعبه و اتاق | ۸ | — | ۱۰-۱۲h | +### فاز ۰ — تثبیت وضعیت فعلی (پیش‌نیاز بقیه) + +| تسک | ماژول | پروژه | Endpoint | وابستگی | زمان | +|-----|-------|-------|----------|---------|------| +| [۰۰](task-00-service-mode-completion/) | تکمیل نوبت‌دهی سرویسی | `clinicpro` | ۴ | — | ۱۴-۱۸h | +| [۰۰ب](task-00b-nobat724-service-mode/) | سازگارسازی سایت عمومی | `nobat724_front` | — | ۰۰ | ۱۰-۱۴h | + +### فاز ۱ — هستهٔ چندمنبعی + +| تسک | ماژول | Endpoint | وابستگی | زمان | +|-----|-------|----------|---------|------| +| [۰۱](task-01-branch-room/) | شعبه و اتاق | ۸ | ۰۰ | ۱۰-۱۲h | | [۰۲](task-02-resource-model/) | منبع، نوع منبع، مهارت، استخر | ۱۴ | ۰۱ | ۱۴-۱۸h | | [۰۳](task-03-resource-calendar/) | تقویم منبع، مرخصی، تعطیلات ملی | ۹ | ۰۱، ۰۲ | ۱۲-۱۴h | | [۰۴](task-04-service-catalog-v2/) | کاتالوگ خدمات v2 (گروه آیتم، دو نوع زمان) | ۱۰ | ۰۱ | ۱۴-۱۶h | @@ -21,14 +38,29 @@ | [۰۶](task-06-availability-engine/) | موتور جستجوی وقت چندمنبعی | ۲ | ۰۳، ۰۵ | ۲۰-۲۴h | | [۰۷](task-07-hold-and-book/) | رزرو موقت و ثبت نهایی چندمنبعی | ۴ | ۰۶ | ۱۶-۲۰h | | [۰۸](task-08-pricing-snapshot/) | لیست قیمت بازه‌دار و snapshot فاکتور | ۷ | ۰۴، ۰۷ | ۱۲-۱۴h | + +### فاز ۲ — قوانین + +| تسک | ماژول | Endpoint | وابستگی | زمان | +|-----|-------|----------|---------|------| | [۰۹](task-09-policy-engine/) | موتور قوانین شش‌دسته‌ای | ۶ | ۰۵، ۰۶، ۰۸ | ۲۰-۲۴h | | [۱۰](task-10-policy-admin-sandbox/) | فرم ساخت قانون + محیط آزمایش | ۲ | ۰۹ | ۱۰-۱۲h | + +### فاز ۳ — کسب‌وکار + +| تسک | ماژول | Endpoint | وابستگی | زمان | +|-----|-------|----------|---------|------| | [۱۱](task-11-package-credit-ledger/) | پکیج و دفتر اعتبار جلسات | ۸ | ۰۸ | ۱۰-۱۲h | | [۱۲](task-12-treatment-course/) | دوره درمان | ۹ | ۰۷، ۱۱ | ۱۶-۲۰h | | [۱۳](task-13-cancellation-waitlist/) | سیاست لغو، عدم حضور، لیست انتظار | ۷ | ۰۷ | ۱۰-۱۲h | + +### فاز ۴ — بهینه‌سازی + +| تسک | ماژول | Endpoint | وابستگی | زمان | +|-----|-------|----------|---------|------| | [۱۴](task-14-events-utilization/) | رویدادهای دامنه و گزارش بهره‌وری | ۳ | ۰۷ | ۸-۱۰h | -**مجموع endpoint جدید: ~۹۲ · مجموع زمان: ۱۹۰ تا ۲۲۸ ساعت** +**مجموع endpoint جدید: ~۹۶ · مجموع زمان: ۲۱۴ تا ۲۵۶ ساعت** --- @@ -37,57 +69,99 @@ ``` task-XX-name/ ├── task.md ← شرح، دامنه، endpoint ها، معیار پذیرش، زمان -├── architecture.md ← فایل‌ها، entity ها، سرویس‌ها، لایه‌ها +├── architecture.md ← فایل‌ها، entity ها، سرویس‌ها، لایه‌ها، قواعد UI ├── database.md ← جداول، ستون‌ها، ایندکس‌ها، migration ├── implementation_notes.md ← نکات فنی، edge case، سازگاری عقب‌رو، تست +├── checklist.md ← ☑️ وضعیت هر مورد: ✅ 🔄 ⏳ ⚠️ └── user_flow.md ← (تسک‌های پیچیده) جریان کاربری ``` +`checklist.md` **اجباری** است و ساختار ثابتی دارد: + +``` +۰. خط سرخ‌ها ۱. بک‌اند ۲. دیتابیس ۳. UI ۴. تست ۵. مستندات ۶. بازبینی پایانی +``` + +--- + +## چک‌لیست — قواعد + +| نماد | معنی | اجازهٔ باقی‌ماندن در پایان تسک | +|---|---|---| +| ✅ | انجام‌شده و تأییدشده | بله | +| 🔄 | در حال انجام | **نه** | +| ⏳ | انجام‌نشده | **نه** — مگر با دلیل مکتوب و تسک مقصد | +| ⚠️ | نیازمند بررسی یا تست | **نه** — باید تعیین تکلیف شود | + +**پیش از پایان هر تسک، همهٔ ردیف‌های چک‌لیست بازبینی می‌شوند و وضعیت نهایی می‌گیرند.** +هر تسک بخش «۶. بازبینی پایانی» دارد که تست‌ها، مستندات، UI و دو کلاینت دیگر را می‌سنجد. + --- ## ترتیب پیشنهادی اجرا ``` -۰۱ ─┬─ ۰۲ ── ۰۳ ─┐ - └─ ۰۴ ── ۰۵ ─┴─ ۰۶ ── ۰۷ ─┬─ ۰۸ ─┬─ ۰۹ ── ۱۰ - │ └─ ۱۱ ── ۱۲ - ├─ ۱۳ - └─ ۱۴ +۰۰ ── ۰۰ب + │ + ├─ ۰۱ ─┬─ ۰۲ ── ۰۳ ─┐ + │ └─ ۰۴ ── ۰۵ ─┴─ ۰۶ ── ۰۷ ─┬─ ۰۸ ─┬─ ۰۹ ── ۱۰ + │ │ └─ ۱۱ ── ۱۲ + │ ├─ ۱۳ + │ └─ ۱۴ ``` -فاز اول (هستهٔ قابل عرضه): ۰۱ تا ۰۸ — بعد از آن یک کلینیک زیبایی با اتاق، دستگاه و -اپراتور می‌تواند واقعاً نوبت بگیرد. +**فاز ۰ اختیاری نیست.** اگر حالت `resource` (تسک ۰۶) روی حالت `service` نیمه‌کاره ساخته +شود، هر باگ موجود سرویسی به موتور جدید ارث می‌رسد و تشخیص منبعش غیرممکن می‌شود. + +فاز اول قابل عرضه: ۰۰ تا ۰۸ — بعد از آن یک کلینیک زیبایی با اتاق، دستگاه و اپراتور +می‌تواند واقعاً نوبت بگیرد. + +--- + +## سه حالت نوبت‌دهی + +| حالت | مقدار `WeeklySchedule.meta.booking_mode` | وضعیت | +|---|---|---| +| اسلاتی | `slot` | ⛔ **قفل** — پیش‌فرض، تولیدی، دست‌نخورده | +| سرویسی | `service` | 🔄 موجود ولی نیمه‌کاره → تسک ۰۰ و ۰۰ب کاملش می‌کنند | +| چندمنبعی | `resource` | ⏳ جدید — تسک ۰۶ به بعد | + +`booking_mode` پس از اولین ثبت قفل می‌شود (`WeeklySchedule::getStoredBookingMode()`). +تسک ۰۶ یک استثنای کنترل‌شده اضافه می‌کند: ارتقای **یک‌طرفه** از `slot`/`service` به +`resource`، مشروط بر نبودِ نوبت فعال آینده. بازگشت ممنوع. + +ماتریس کامل «کدام endpoint در کدام حالت» در `docs/architecture/booking-modes.md` +(تسک ۰۰ می‌سازد، تسک ۰۶ حالت سوم را اضافه می‌کند). + +--- + +## اجبار خودکار خط سرخ + +هر تسک باید این را سبز نگه دارد: + +```bash +ddev exec php bin/phpunit --group=slot-mode-frozen +``` + +تسک ۰۰ این تست و سه fixture آن را می‌سازد. fixture ها بعد از آن **read-only** اند: +اگر تستی قرمز شد، **کد باید برگردد، نه fixture**. --- ## قواعد مشترک همهٔ تسک‌ها -قواعد پروژه در [CLAUDE.md](../../../CLAUDE.md) و -[docs/architecture/tenancy.md](../../architecture/tenancy.md) بر همهٔ این تسک‌ها حاکم‌اند. -مواردی که در هر تسک باید رعایت شوند: +از [CLAUDE.md](../../../CLAUDE.md) و [docs/architecture/tenancy.md](../../architecture/tenancy.md). +فهرست کامل در [_shared/definition-of-done.md](_shared/definition-of-done.md): -1. هر entity جدید یا `TenantOwnedTrait` می‌گیرد یا در `GlobalTables` با دلیل ثبت می‌شود؛ - `TenantSchemaCoverageTest` را اجرا کن. -2. `entity_type, entity_id` ستون‌های **اول** هر ایندکس ترکیبی لیست. -3. هر uuid که از request می‌آید باید با `TenantOwnershipChecker` سنجیده شود؛ - `TenantLookupInventoryTest` شمارنده دارد. -4. timestamp ها `int` (Unix)، نه `DateTime`. نمایش شمسی فقط در UI. -5. کنترلر نازک، `extends BaseController`، پاسخ با `success()/paginated()/error()`. -6. هر endpoint جدید یا تغییر یافته → به‌روزرسانی `docs/api/*.md` در همان نشست. -7. تست موفق + خطا + مرزی برای هر تسک، وگرنه تسک تمام نیست. -8. رشته‌های UI فارسی، کد و کامیت انگلیسی. -9. سازگاری عقب‌رو: `nobat724_front` و `clinic-pro-tauri` مصرف‌کنندهٔ همین APIها هستند - و در build خطا نمی‌دهند — هر تغییر قرارداد باید دستی بررسی شود. - ---- - -## سازگاری با نوبت‌دهی فعلی - -| حالت | منبع تنظیم | چه زمانی | -|---|---|---| -| `slot` | `WeeklySchedule.meta.booking_mode` | اسلات ثابت `duration_per_patient` — رفتار پیش‌فرض امروز | -| `service` | همان | طول = جمع مدت سرویس‌ها + buffer — پیاده‌شده، تک‌منبعی | -| `resource` | همان | **جدید** — برنامهٔ چندبخشی + چند منبع (تسک ۰۵ به بعد) | - -`booking_mode` پس از اولین ثبت قفل می‌شود (`WeeklySchedule::getStoredBookingMode()`). -تسک ۰۶ باید مسیر ارتقای داوطلبانهٔ `service → resource` را باز کند، بدون اجبار. +1. entity جدید یا `TenantOwnedTrait` می‌گیرد یا با دلیل در `GlobalTables` ثبت می‌شود +2. `entity_type, entity_id` ستون‌های **اول** هر ایندکس ترکیبیِ لیست +3. هر uuid از request با `TenantOwnershipChecker` سنجیده می‌شود +4. timestamp ها `int` یونیکس؛ نمایش شمسی فقط در UI +5. کنترلر نازک · `BaseController` · `success/paginated/error` +6. API جدید فقط وقتی هیچ endpoint موجودی کافی نباشد — **دلیلش نوشته شود** +7. تست موفق + خطا + مرزی؛ بدون اجرای موفق تست، تسک تمام نیست +8. هر endpoint جدید یا تغییریافته → `docs/api/*` در همان نشست +9. رشته‌های UI فارسی از i18n؛ کد و کامیت و مستندات انگلیسی +10. سازگاری عقب‌رو: `nobat724_front` و `clinic-pro-tauri` در build خطا نمی‌دهند — + بررسی دستی اجباری است (ردیف بازبینی پایانی هر تسک) +11. اول commit، بعد `graphify update .` diff --git a/docs/new_feture/taskes/task-01-branch-room/checklist.md b/docs/new_feture/taskes/task-01-branch-room/checklist.md new file mode 100644 index 00000000..ee9efd87 --- /dev/null +++ b/docs/new_feture/taskes/task-01-branch-room/checklist.md @@ -0,0 +1,92 @@ +# چک‌لیست — تسک ۰۱ (شعبه و اتاق) + +**وضعیت کلی:** ⏳ شروع نشده · **آخرین بازبینی:** — + +قواعد: [_shared/definition-of-done.md](../_shared/definition-of-done.md) · +[red-lines.md](../_shared/red-lines.md) · [ui-conventions.md](../_shared/ui-conventions.md) + +--- + +## ۰. خط سرخ + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۰.۱ | `--group=slot-mode-frozen` سبز | ⏳ | | +| ۰.۲ | `SlotCalculatorService` دست‌نخورده | ⏳ | این تسک به آن کاری ندارد | +| ۰.۳ | `location_id` در JSON برنامهٔ هفتگی دست‌نخورده | ⏳ | شعبه **بالای** آدرس می‌نشیند | +| ۰.۴ | `DoctorAddress` هیچ ستونی حذف/تغییر نداد | ⏳ | فقط `branch_id` تهی‌پذیر اضافه شد | + +## ۱. بک‌اند + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۱.۱ | `Branch` + `BranchWorkingHours` + `Room` entity | ⏳ | | +| ۱.۲ | `BranchService` با گاردهای حذف قابل توسعه (`DeletionGuardInterface`) | ⏳ | تسک ۰۲ و ۰۷ گارد اضافه می‌کنند | +| ۱.۳ | `WorkingHoursService` — اعتبارسنجی و `sequence` سمت سرور | ⏳ | | +| ۱.۴ | ساعت با `start_minute`/`end_minute` عددی، نه رشتهٔ `"09:00"` | ⏳ | | +| ۱.۵ | هشت endpoint ساخته شد | ⏳ | | +| ۱.۶ | پزشک مستقل هم شعبه دارد (مطب = شعبه) | ⏳ | نه فقط `entity_type=clinic` | +| ۱.۷ | `app:branch:backfill` — dry-run پیش‌فرض، idempotent | ⏳ | | +| ۱.۸ | کنترلر نازک · `BaseController` · `success/paginated/error` | ⏳ | | +| ۱.۹ | `TenantOwnershipChecker` روی هر uuid از request | ⏳ | | + +## ۲. دیتابیس + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۲.۱ | `branches` · `branch_working_hours` · `rooms` | ⏳ | | +| ۲.۲ | `entity_type, entity_id` ستون **اول** ایندکس‌های لیست | ⏳ | | +| ۲.۳ | `timezone` روی شعبه از روز اول | ⏳ | افزودن بعدی = backfill زمان‌دار | +| ۲.۴ | `rooms.capacity` — ظرفیت هم‌زمان | ⏳ | اتاق سه‌تخته = یک ردیف با ۳ | +| ۲.۵ | `branch_working_hours` در `GlobalTables::AGGREGATE_CHILDREN` | ⏳ | | +| ۲.۶ | `TenantSchemaCoverageTest` سبز | ⏳ | | + +## ۳. UI + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۳.۱ | `BranchesPage` · `BranchFormPage` · `RoomsPage` | ⏳ | | +| ۳.۲ | `DataTable` با skeleton و empty state فارسی | ⏳ | | +| ۳.۳ | `PageHeader` با `backTo` روی زیرصفحه‌ها | ⏳ | | +| ۳.۴ | شهر/استان با `SearchableSelect` — هیچ `` بومی | ⏳ | | +| ۳.۶ | انتخاب الگو → فرم کوتاه مقدارها (مسیر ۹۰٪ کاربران) | ⏳ | | +| ۳.۷ | ستون «وضعیت فعلی → با این قانون» در گزارش | ⏳ | ⭐ تنها چیزی که کاربر غیرفنی می‌فهمد | +| ۳.۸ | درصد تحت تأثیر + سطح شدت با رنگ توکن‌محور | ⏳ | | +| ۳.۹ | شدت `none` هم هشدار می‌دهد، با متن دو‌حالتی | ⏳ | | +| ۳.۱۰ | شدت `high` → متن «مطمئنید؟» روی دکمهٔ فعال‌سازی | ⏳ | | +| ۳.۱۱ | `ConfirmDialog` موجود برای فعال‌سازی | ⏳ | نه مودال دست‌ساز | +| ۳.۱۲ | `DataTable` برای لیست قوانین با فیلتر دسته/وضعیت در URL | ⏳ | | +| ۳.۱۳ | `backTo`/`BackButton` روی هر سه صفحه | ⏳ | | +| ۳.۱۴ | هیچ رنگ/شعاع hard-code — رنگ‌های شدت هم از توکن وضعیت | ⏳ | `--warning` `--danger` `--success` | +| ۳.۱۵ | دارک‌مود و حالت فشرده | ⏳ | | +| ۳.۱۶ | RTL و موبایل — جدول گزارش اسکرول افقی داخلی | ⏳ | | +| ۳.۱۷ | تاریخ‌ها شمسی | ⏳ | | +| ۳.۱۸ | همهٔ رشته‌ها فارسی | ⏳ | | +| ۳.۱۹ | نمایش تاریخچهٔ نسخه‌ها با diff | ⏳ | | + +## ۴. تست + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۴.۱ | `PolicySimulatorTest` — شمارش ردیف قبل/بعد | ⏳ | ⭐⭐ | +| ۴.۲ | `PolicySimulatorTest` — استثنا در `evaluateIsolated` → rollback + clear | ⏳ | | +| ۴.۳ | `SimulationSamplerTest` — استخراج فیلتر، فقط confirmed/completed، سقف ۵۰ | ⏳ | | +| ۴.۴ | `PolicyActivationGuardTest` — چهار حالت | ⏳ | ⭐ | +| ۴.۵ | `PolicyTemplateTest` — هر الگو قانون معتبر تولید می‌کند (dataProvider) | ⏳ | ⭐ | +| ۴.۶ | `SeverityTest` — چهار آستانه | ⏳ | | +| ۴.۷ | `PolicyFormPage.test.tsx` — فیلد ساختگی از mock schema در UI ظاهر می‌شود | ⏳ | ⭐ | +| ۴.۸ | `PolicyFormPage.test.tsx` — عملگر نامعتبر برای نوع نمایش داده نمی‌شود | ⏳ | | + +## ۵. مستندات + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۵.۱ | `docs/api/policy.md` — `simulate`، `policy-templates`، شرط جدید `activate` | ⏳ | | +| ۵.۲ | `docs/architecture/policy-engine.md` بخش «چرا آزمایش اجباری است» | ⏳ | ارجاع به ریسک دوم مستند | + +## ۶. بازبینی پایانی + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۶.۱ | هیچ 🔄 و ⏳ بی‌دلیل نمانده | ⏳ | | +| ۶.۲ | `bin/phpunit` کامل سبز | ⏳ | | +| ۶.۳ | `--group=slot-mode-frozen` سبز | ⏳ | | +| ۶.۴ | `phpstan` بدون خطای جدید | ⏳ | | +| ۶.۵ | `npx tsc --noEmit` و `yarn test` سبز | ⏳ | | +| ۶.۶ | تست‌های tenant سبز | ⏳ | | +| ۶.۷ | `docs/api/*` به‌روز | ⏳ | | +| ۶.۸ | چک‌لیست UI کامل | ⏳ | | +| ۶.۹ | دو کلاینت دیگر بررسی شدند | ⏳ | این تسک قرارداد عمومی عوض نمی‌کند | +| ۶.۱۰ | commit، سپس `graphify update .` | ⏳ | | +| ۶.۱۱ | موارد به‌تعویق با دلیل و تسک مقصد | ⏳ | | diff --git a/docs/new_feture/taskes/task-11-package-credit-ledger/checklist.md b/docs/new_feture/taskes/task-11-package-credit-ledger/checklist.md new file mode 100644 index 00000000..10c46150 --- /dev/null +++ b/docs/new_feture/taskes/task-11-package-credit-ledger/checklist.md @@ -0,0 +1,114 @@ +# چک‌لیست — تسک ۱۱ (پکیج و دفتر اعتبار جلسات) + +**وضعیت کلی:** ⏳ شروع نشده · **آخرین بازبینی:** — + +قواعد: [_shared/definition-of-done.md](../_shared/definition-of-done.md) · +[red-lines.md](../_shared/red-lines.md) · [ui-conventions.md](../_shared/ui-conventions.md) + +--- + +## ۰. خط سرخ + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۰.۱ | `--group=slot-mode-frozen` سبز | ⏳ | | +| ۰.۲ | **هیچ ستون `remaining`/`used_count`/`balance` در هیچ جدولی** | ⏳ | ⭐⭐ `LedgerSchemaTest` اجبار می‌کند | +| ۰.۳ | دفتر append-only — هیچ `remove`/`update` روی ردیف‌ها | ⏳ | | +| ۰.۴ | `WalletTransaction` و منطق کیف پول دست‌نخورده | ⏳ | مفهوم متفاوت | + +## ۱. بک‌اند + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۱.۱ | `Package` · `PackageService` · `PatientPackage` · `SessionCreditLedger` | ⏳ | | +| ۱.۲ | `CreditLedgerService` — **تنها** نویسندهٔ دفتر | ⏳ | | +| ۱.۳ | `balance()` = `SUM(delta)`، بدون هیچ مقدار ذخیره‌شده | ⏳ | ⭐ | +| ۱.۴ | پنج `kind` تعریف شد | ⏳ | | +| ۱.۵ | `quote` **هرگز** مصرف نمی‌کند؛ فقط `confirm` | ⏳ | ⭐⭐ رفرش صفحه = از دست رفتن جلسه | +| ۱.۶ | `PriceQuote` پرچم `packageWillBeConsumed` دارد | ⏳ | | +| ۱.۷ | مانده صفر → `false`، **نه استثنا** | ⏳ | ⭐ بیمار نقدی بپردازد | +| ۱.۸ | قفل بدبینانه `PESSIMISTIC_WRITE` روی ردیف پکیج | ⏳ | با جدول مقایسه با تسک ۰۷ | +| ۱.۹ | `catch UniqueConstraintViolationException` روی `consume` → idempotent | ⏳ | | +| ۱.۱۰ | FIFO — قدیمی‌ترین پکیج منقضی‌نشده | ⏳ | LIFO یعنی پول بیمار سوخته | +| ۱.۱۱ | `valid_to` هنگام **خرید** محاسبه و ذخیره می‌شود | ⏳ | | +| ۱.۱۲ | لغو → ردیف `refund`، نه حذف `consume` | ⏳ | | +| ۱.۱۳ | `TODO` با ارجاع به تسک ۱۳ برای سیاست بازگشت اعتبار | ⏳ | نه پرچم نیم‌کاره | +| ۱.۱۴ | `adjust` فقط با نقش مدیر و با `reason` اجباری | ⏳ | | +| ۱.۱۵ | `app:package:expire` روزانه — ردیف `expiry` با `delta = -balance` | ⏳ | | +| ۱.۱۶ | قلاب مرحلهٔ ۴ `PricingEngine` وصل شد | ⏳ | | +| ۱.۱۷ | هشت endpoint | ⏳ | | +| ۱.۱۸ | `TenantOwnershipChecker` روی هر uuid از request | ⏳ | | + +## ۲. دیتابیس + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۲.۱ | چهار جدول | ⏳ | | +| ۲.۲ | `price_rials` و `price_paid_rials` از نوع **BIGINT** | ⏳ | پکیج بزرگ | +| ۲.۳ | `UNIQUE(appointment_id, kind)` روی دفتر | ⏳ | ⭐ جلوگیری از مصرف دوباره | +| ۲.۴ | `session_count`/`price_paid_rials` روی `patient_packages` **snapshot** اند | ⏳ | قانون پنجم | +| ۲.۵ | `ON DELETE RESTRICT` روی سرویسِ پکیج فروخته‌شده | ⏳ | | +| ۲.۶ | `package_services` در `AGGREGATE_CHILDREN` | ⏳ | | +| ۲.۷ | دفتر **جفت tenant** دارد (نه `ENTITIES` مثل کیف پول) | ⏳ | ⭐ دلیل مکتوب | +| ۲.۸ | `TenantSchemaCoverageTest` سبز | ⏳ | | + +## ۳. UI + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۳.۱ | `PackagesPage` — تعریف با `PriceInput` و انتخاب سرویس | ⏳ | | +| ۳.۲ | کارت «پکیج‌ها» در `PatientDetailPage` با مانده و انقضا | ⏳ | | +| ۳.۳ | `PatientPackageLedgerPage` — جدول دفتر | ⏳ | | +| ۳.۴ | ستون «مانده تجمعی» **محاسبه‌شده در UI**، نه ستون DB | ⏳ | ⭐ به کاربر ثابت می‌کند عدد از کجاست | +| ۳.۵ | ستون‌های دفتر: تاریخ، نوع، تغییر، مانده تجمعی، دلیل، ثبت‌کننده، نوبت | ⏳ | | +| ۳.۶ | پیام «اعتبار پکیج تمام شده؛ این نوبت نقدی محاسبه می‌شود» | ⏳ | | +| ۳.۷ | `DataTable` با skeleton و empty state | ⏳ | | +| ۳.۸ | سرویس‌ها با `SearchableSelect` | ⏳ | | +| ۳.۹ | `backTo`/`BackButton` روی زیرصفحه‌ها | ⏳ | | +| ۳.۱۰ | هیچ رنگ/شعاع hard-code | ⏳ | | +| ۳.۱۱ | دارک‌مود و حالت فشرده | ⏳ | | +| ۳.۱۲ | RTL و موبایل | ⏳ | | +| ۳.۱۳ | مبالغ با `formatRial` · تاریخ با `formatDate` | ⏳ | | +| ۳.۱۴ | وضعیت لیست در URL با `useUrlState` | ⏳ | | +| ۳.۱۵ | همهٔ رشته‌ها فارسی | ⏳ | | +| ۳.۱۶ | دکمهٔ `adjust` فقط برای نقش مدیر نمایش داده می‌شود | ⏳ | `FeatureGate`/بررسی نقش | + +## ۴. تست + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۴.۱ | `CreditLedgerTest` — `SUM(delta)` در همهٔ سناریوها، append-only | ⏳ | ⭐ | +| ۴.۲ | `LedgerSchemaTest` — هیچ ستون مانده در schema | ⏳ | ⭐⭐ | +| ۴.۳ | `QuoteDoesNotConsumeTest` — ده `quote` → مانده بی‌تغییر | ⏳ | ⭐⭐ | +| ۴.۴ | `ConcurrentConsumeTest` — مانده منفی نمی‌شود | ⏳ | | +| ۴.۵ | `IdempotentConsumeTest` — `confirm` دوبار → یک ردیف | ⏳ | | +| ۴.۶ | `FifoTest` | ⏳ | | +| ۴.۷ | `ExpiryTest` — ردیف `expiry` و حذف از finder | ⏳ | | +| ۴.۸ | `AdjustmentAuthTest` — منشی ۴۰۳، مدیر بی‌دلیل ۴۲۲ | ⏳ | | +| ۴.۹ | `PackageTenantTest` — پکیج محیط دیگر ۴۰۴ | ⏳ | | +| ۴.۱۰ | `PricingIntegrationTest` — ردیف `package` منفی + invariant تسک ۰۸ حفظ شد | ⏳ | ⭐ | + +## ۵. مستندات + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۵.۱ | `docs/api/package.md` | ⏳ | | +| ۵.۲ | جدول مقایسهٔ قفل بدبینانه (این تسک) با سطل زمانی (تسک ۰۷) | ⏳ | ⭐ وگرنه «یکدست‌سازی» می‌شود | +| ۵.۳ | `docs/architecture/tenancy.md` — تفاوت دفتر اعتبار با کیف پول | ⏳ | ⭐ اشتباه گرفتنشان = نشتی مالی | + +## ۶. بازبینی پایانی + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۶.۱ | هیچ 🔄 و ⏳ بی‌دلیل نمانده | ⏳ | | +| ۶.۲ | `bin/phpunit` کامل سبز | ⏳ | | +| ۶.۳ | `--group=slot-mode-frozen` سبز | ⏳ | | +| ۶.۴ | `PatientWalletTenantTest` موجود سبز ماند | ⏳ | | +| ۶.۵ | `phpstan` بدون خطای جدید | ⏳ | | +| ۶.۶ | `npx tsc --noEmit` و `yarn test` سبز | ⏳ | | +| ۶.۷ | تست‌های tenant سبز | ⏳ | | +| ۶.۸ | `docs/api/*` به‌روز | ⏳ | | +| ۶.۹ | چک‌لیست UI کامل | ⏳ | | +| ۶.۱۰ | دو کلاینت دیگر بررسی شدند | ⏳ | مبلغ صفر در رزرو درست نمایش داده می‌شود؟ | +| ۶.۱۱ | commit، سپس `graphify update .` | ⏳ | | +| ۶.۱۲ | موارد به‌تعویق با دلیل و تسک مقصد | ⏳ | سیاست بازگشت اعتبار → تسک ۱۳ | diff --git a/docs/new_feture/taskes/task-12-treatment-course/checklist.md b/docs/new_feture/taskes/task-12-treatment-course/checklist.md new file mode 100644 index 00000000..6246eb8b --- /dev/null +++ b/docs/new_feture/taskes/task-12-treatment-course/checklist.md @@ -0,0 +1,115 @@ +# چک‌لیست — تسک ۱۲ (دوره درمان) + +**وضعیت کلی:** ⏳ شروع نشده · **آخرین بازبینی:** — + +قواعد: [_shared/definition-of-done.md](../_shared/definition-of-done.md) · +[red-lines.md](../_shared/red-lines.md) · [ui-conventions.md](../_shared/ui-conventions.md) + +--- + +## ۰. خط سرخ + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۰.۱ | `--group=slot-mode-frozen` سبز | ⏳ | | +| ۰.۲ | `PatientSession` موجود دست‌نخورده | ⏳ | «مراجعهٔ انجام‌شده» ≠ «جلسهٔ دوره» | +| ۰.۳ | رویدادهای تسک ۰۷ **بعد از** commit منتشر می‌شوند | ⏳ | ⭐ وگرنه در rollback هشت پیامک اشتباه | +| ۰.۴ | `abandon` نوبت‌های `booked` را **لغو نمی‌کند** | ⏳ | عمل برگشت‌ناپذیر روی ظرفیت | + +## ۱. بک‌اند + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۱.۱ | `CourseProtocol` · `CourseProtocolStep` · `TreatmentCourse` · `CourseSession` | ⏳ | | +| ۱.۲ | `CourseStarter` · `CourseScheduler` · `CourseProgressCalculator` · `CourseSessionLinker` | ⏳ | | +| ۱.۳ | چهار فیلد فاصله و `params` **snapshot** می‌شوند | ⏳ | ⭐ قانون پنجم | +| ۱.۴ | `book-all` **همه یا هیچ** در یک تراکنش | ⏳ | ⭐⭐ رزرو نیمه‌کاره بدترین حالت | +| ۱.۵ | لنگر **متحرک** — فاصله از جلسهٔ قبلی، نه از شروع دوره | ⏳ | ⭐ | +| ۱.۶ | `findNearestInRange` — نزدیک‌ترین به **ایده‌آل**، نه اولین موجود | ⏳ | | +| ۱.۷ | لنگر پیشنهاد بعدی = آخرین جلسهٔ **`completed`**، نه `booked` | ⏳ | ⭐ | +| ۱.۸ | سقف ۹۰ روز → جلسات باقی `planned` + **پیام روشن** | ⏳ | ⭐ | +| ۱.۹ | `same_as_previous` ترجیح است نه الزام — fallback به `least_gap` | ⏳ | | +| ۱.۱۰ | `preferredResourceIds` در `PlanRequest` حمل می‌شود | ⏳ | | +| ۱.۱۱ | `SameAsPreviousPicker` تسک ۰۶ ورودی گرفت | ⏳ | | +| ۱.۱۲ | تعامل با `spacing`: `max(min)` و `min(max)`؛ بازهٔ تهی → ۴۲۲ روشن | ⏳ | سخت‌گیرانه‌تر برنده | +| ۱.۱۳ | اعتبار پکیج کمتر از جلسات → **هشدار**، نه خطا | ⏳ | | +| ۱.۱۴ | `active_course_key` با الگوی `active_slot_key` | ⏳ | ⭐ نه UNIQUE روی `status` | +| ۱.۱۵ | `CourseSessionLinker` هر دو سمت رابطه را هم‌زمان ست می‌کند | ⏳ | جای دیگری نه | +| ۱.۱۶ | جلسهٔ آخر `completed` → دوره `completed` خودکار + رویداد | ⏳ | | +| ۱.۱۷ | نُه endpoint | ⏳ | | +| ۱.۱۸ | `TenantOwnershipChecker` روی هر uuid از request | ⏳ | | + +## ۲. دیتابیس + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۲.۱ | چهار جدول | ⏳ | | +| ۲.۲ | `min_days <= ideal_days <= max_days` و `session_count >= 2` | ⏳ | | +| ۲.۳ | `UNIQUE(protocol_id, session_number)` و `UNIQUE(course_id, session_number)` | ⏳ | | +| ۲.۴ | `UNIQUE(appointment_id)` روی `course_sessions` | ⏳ | | +| ۲.۵ | `appointments.course_session_id` تهی‌پذیر (رابطهٔ دوطرفه، عمدی) | ⏳ | | +| ۲.۶ | `course_protocol_steps` در `AGGREGATE_CHILDREN` | ⏳ | | +| ۲.۷ | `TenantSchemaCoverageTest` سبز | ⏳ | | + +## ۳. UI + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۳.۱ | `CourseProtocolsPage` — پروتکل + جدول پارامتر جلسات | ⏳ | | +| ۳.۲ | `TreatmentCoursePage` — نوار پیشرفت، جدول جلسات، دو دکمهٔ رزرو | ⏳ | | +| ۳.۳ | کارت «دوره‌های درمان» در `PatientDetailPage` | ⏳ | | +| ۳.۴ | ستون «فاصله» عدد **واقعی** بین جلسات را نشان می‌دهد، نه ایده‌آل | ⏳ | ⭐ کلینیک نظم بیمار را می‌فهمد | +| ۳.۵ | نوار زرد هشدار عبور از حداکثر فاصله | ⏳ | | +| ۳.۶ | پیشنهاد جلسهٔ بعدی به‌صورت بنر پس از `completed` شدن جلسه | ⏳ | | +| ۳.۷ | نام منبع ترجیحی روی دکمهٔ رزرو («رزرو با اپراتور مریم») | ⏳ | | +| ۳.۸ | پس از لغو جلسهٔ وسط: پیشنهاد «بازچینی جلسات باقی‌مانده» با کلیک صریح | ⏳ | خودکار نه | +| ۳.۹ | `DataTable` برای جدول جلسات | ⏳ | | +| ۳.۱۰ | `StatusBadge` برای وضعیت جلسه و دوره | ⏳ | | +| ۳.۱۱ | تاریخ‌ها شمسی با `PersianDatePicker`/`formatDate` | ⏳ | | +| ۳.۱۲ | `backTo`/`BackButton` روی زیرصفحه‌ها | ⏳ | | +| ۳.۱۳ | هیچ رنگ/شعاع hard-code — نوار پیشرفت هم | ⏳ | | +| ۳.۱۴ | دارک‌مود و حالت فشرده | ⏳ | | +| ۳.۱۵ | RTL و موبایل | ⏳ | | +| ۳.۱۶ | همهٔ رشته‌ها فارسی | ⏳ | | +| ۳.۱۷ | پیام سقف ۹۰ روز در UI نمایش داده می‌شود | ⏳ | ⭐ وگرنه کاربر فکر می‌کند خراب است | + +## ۴. تست + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۴.۱ | `CourseStarterTest` — ۸ جلسه، بدون پروتکل ۴۲۲، دورهٔ دوم ۴۲۲ با `meta` | ⏳ | | +| ۴.۲ | `ProtocolSnapshotTest` | ⏳ | ⭐ | +| ۴.۳ | `CourseSchedulerTest` — لنگر متحرک، نزدیک‌ترین به ایده‌آل | ⏳ | ⭐ | +| ۴.۴ | `CourseSchedulerTest` — شکست جلسهٔ N → rollback ۱..N-1 | ⏳ | ⭐⭐ | +| ۴.۵ | `CourseSchedulerTest` — سقف ۹۰ روز + پیام | ⏳ | | +| ۴.۶ | `NextSuggestionTest` — لنگر `completed`، هشدار عبور از max | ⏳ | | +| ۴.۷ | `CourseProgressTest` | ⏳ | | +| ۴.۸ | `SameResourcePreferenceTest` — fallback بدون خطا | ⏳ | | +| ۴.۹ | `CoursePolicyInteractionTest` — سخت‌گیرانه‌تر برنده، بازهٔ تهی ۴۲۲ | ⏳ | | +| ۴.۱۰ | `CoursePackageTest` — مصرف per جلسه، هشدار نه خطا | ⏳ | | +| ۴.۱۱ | `CourseLifecycleTest` — لغو، `no_show`، تکمیل خودکار، `abandon` | ⏳ | | + +## ۵. مستندات + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۵.۱ | `docs/api/course.md` | ⏳ | | +| ۵.۲ | قاعدهٔ «سخت‌گیرانه‌تر برنده» بین پروتکل و قانون | ⏳ | | +| ۵.۳ | رفتار سقف ۹۰ روز | ⏳ | | +| ۵.۴ | «`abandon` نوبت‌ها را لغو نمی‌کند» صریح | ⏳ | | + +## ۶. بازبینی پایانی + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۶.۱ | هیچ 🔄 و ⏳ بی‌دلیل نمانده | ⏳ | | +| ۶.۲ | `bin/phpunit` کامل سبز | ⏳ | | +| ۶.۳ | `--group=slot-mode-frozen` سبز | ⏳ | | +| ۶.۴ | `phpstan` بدون خطای جدید | ⏳ | | +| ۶.۵ | `npx tsc --noEmit` و `yarn test` سبز | ⏳ | | +| ۶.۶ | تست‌های tenant سبز | ⏳ | | +| ۶.۷ | `docs/api/*` به‌روز | ⏳ | | +| ۶.۸ | چک‌لیست UI کامل | ⏳ | | +| ۶.۹ | دو کلاینت دیگر بررسی شدند | ⏳ | نوبت‌های دوره در پنل بیمار درست دیده می‌شوند؟ | +| ۶.۱۰ | commit، سپس `graphify update .` | ⏳ | | +| ۶.۱۱ | موارد به‌تعویق با دلیل و تسک مقصد | ⏳ | | diff --git a/docs/new_feture/taskes/task-13-cancellation-waitlist/checklist.md b/docs/new_feture/taskes/task-13-cancellation-waitlist/checklist.md new file mode 100644 index 00000000..41b51402 --- /dev/null +++ b/docs/new_feture/taskes/task-13-cancellation-waitlist/checklist.md @@ -0,0 +1,128 @@ +# چک‌لیست — تسک ۱۳ (سیاست لغو، عدم حضور، لیست انتظار) + +**وضعیت کلی:** ⏳ شروع نشده · **آخرین بازبینی:** — + +قواعد: [_shared/definition-of-done.md](../_shared/definition-of-done.md) · +[red-lines.md](../_shared/red-lines.md) · [ui-conventions.md](../_shared/ui-conventions.md) + +--- + +## ۰. خط سرخ + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۰.۱ | `--group=slot-mode-frozen` سبز | ⏳ | | +| ۰.۲ | پیش‌فرض سیاست **بدون جریمه** (`penalty_mode='none'`) | ⏳ | ⭐⭐ وگرنه لحظهٔ deploy همه مشمول جریمه | +| ۰.۳ | بیمار پرریسک **مسدود نمی‌شود** — فقط برچسب | ⏳ | ⭐ مسدودسازی = قانون `eligibility` | +| ۰.۴ | `ReserveAppointmentsPage`/`is_reserve` دست‌نخورده | ⏳ | مفهوم متفاوت از لیست انتظار | +| ۰.۵ | وضعیت‌های لغو موجود (`cancelled_by_*`, `no_show`) دست‌نخورده | ⏳ | | + +## ۱. بک‌اند — لغو و جریمه + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۱.۱ | `CancellationPolicy` · `NoShowRecord` | ⏳ | | +| ۱.۲ | `CancellationPolicyResolver` — سرویس بر محیط اولویت دارد | ⏳ | | +| ۱.۳ | `PenaltyCalculator` — شرط «لغو توسط کلینیک» **اولین خط** | ⏳ | ⭐ | +| ۱.۴ | سقف جریمه = مبلغ پرداختی (`min($penalty, $paid)`) | ⏳ | | +| ۱.۵ | نوبت نقدی → جریمه صفر + `note` | ⏳ | | +| ۱.۶ | `GET /cancellation-preview` پیش از لغو | ⏳ | ⭐ | +| ۱.۷ | `CancellationService` هفت مرحله در یک تراکنش | ⏳ | | +| ۱.۸ | جریمه در `WalletTransaction` با `setRecordedEntity()` | ⏳ | ⭐ وگرنه نشتی بین محیط‌ها | +| ۱.۹ | بازگشت اعتبار پکیج **طبق سیاست** (`credit_refundable`)، نه همیشه | ⏳ | تسک ۱۱ `TODO` را برمی‌دارد | +| ۱.۱۰ | `CourseSessionLinker::releaseSession()` صدا زده می‌شود | ⏳ | تسک ۱۲ | +| ۱.۱۱ | لغو دوباره → idempotent | ⏳ | | +| ۱.۱۲ | لغو نوبت گذشته → ۴۲۲ | ⏳ | | + +## ۲. بک‌اند — عدم حضور + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۲.۱ | `NoShowTracker` با پنجرهٔ **۱۲ ماه** | ⏳ | نه کل تاریخ | +| ۲.۲ | برچسب پرریسک از `TenantTag` موجود، نه ستون بولین جدید | ⏳ | ⭐ | +| ۲.۳ | `UNIQUE(appointment_id)` → یک رکورد per نوبت | ⏳ | | +| ۲.۴ | جدول جدا، نه ستون شمارنده روی بیمار | ⏳ | همان استدلال دفتر اعتبار | + +## ۳. بک‌اند — لیست انتظار + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۳.۱ | `WaitlistEntry` · `WaitlistService` · `WaitlistMatcher` | ⏳ | | +| ۳.۲ | **broadcast** به حداکثر ۱۰ نفر، اولین رزروکننده می‌برد | ⏳ | تصمیم مکتوب | +| ۳.۳ | متن پیامک شامل «اولین نفری که رزرو کند آن را می‌گیرد» | ⏳ | ⭐ اجباری | +| ۳.۴ | `notify_count` سقف دارد (پیشنهاد ۳) | ⏳ | جلوگیری از اسپم | +| ۳.۵ | اطلاع‌رسانی **async** روی رویداد، بیرون تراکنش لغو | ⏳ | ⭐ لغو مستقل از پیامک | +| ۳.۶ | ترتیب: `priority DESC, created_at ASC` | ⏳ | | +| ۳.۷ | `preferred_day_parts` در PHP فیلتر می‌شود | ⏳ | | +| ۳.۸ | بیمار که خودش نوبت گرفت → `converted` خودکار روی رویداد `AppointmentBooked` | ⏳ | ⭐ وگرنه پیامک اضافه می‌گیرد | +| ۳.۹ | `app:waitlist:expire` روزانه | ⏳ | | +| ۳.۱۰ | بازهٔ دلخواه > ۹۰ روز → ۴۲۲ | ⏳ | | +| ۳.۱۱ | هفت endpoint | ⏳ | | + +## ۴. دیتابیس + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۴.۱ | سه جدول | ⏳ | | +| ۴.۲ | `idx_waitlist_match (service_item_id, branch_id, status, desired_from, desired_to)` | ⏳ | | +| ۴.۳ | `idx_no_show_patient (patient_record_id, recorded_at)` | ⏳ | کوئری پنجرهٔ ۱۲ ماه | +| ۴.۴ | `risk_tag_uuid` بدون FK (الگوی `DiscountRule.target_tag_uuid`) | ⏳ | | +| ۴.۵ | `app:cancellation:seed-default-policy` — محافظه‌کار | ⏳ | | +| ۴.۶ | `TenantSchemaCoverageTest` سبز | ⏳ | | + +## ۵. UI + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۵.۱ | `CancellationPolicyPage` — سیاست محیط + جدول override سرویس‌ها | ⏳ | | +| ۵.۲ | `WaitlistPage` — لیست + تب «قابل تطبیق» | ⏳ | | +| ۵.۳ | دکمهٔ لغو → `ConfirmDialog` با محتوای **preview** | ⏳ | ⭐ نه لغو بعد جریمه | +| ۵.۴ | نشان «پرریسک» + شمارش عدم حضور در `PatientDetailPage` | ⏳ | | +| ۵.۵ | `ConfirmDialog` موجود استفاده شد، مودال دست‌ساز نه | ⏳ | | +| ۵.۶ | `DataTable` با فیلتر بازه/سرویس در URL | ⏳ | | +| ۵.۷ | تاریخ‌ها شمسی · مبالغ با `formatRial` | ⏳ | | +| ۵.۸ | `backTo`/`BackButton` روی زیرصفحه‌ها | ⏳ | | +| ۵.۹ | هیچ رنگ/شعاع hard-code — نشان پرریسک از `--danger-bg` | ⏳ | | +| ۵.۱۰ | دارک‌مود و حالت فشرده | ⏳ | | +| ۵.۱۱ | RTL و موبایل | ⏳ | | +| ۵.۱۲ | همهٔ رشته‌ها فارسی | ⏳ | | +| ۵.۱۳ | `ReserveAppointmentsPage` موجود دست‌نخورده ماند | ⏳ | ادغام خارج از دامنه | + +## ۶. تست + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۶.۱ | `PenaltyCalculatorTest` — پنج حالت شامل «کلینیک همیشه صفر» | ⏳ | ⭐ | +| ۶.۲ | `CancellationServiceTest` — آزادسازی، `recorded_entity`، idempotent، گذشته ۴۲۲ | ⏳ | | +| ۶.۳ | `PolicyResolverTest` — اولویت سرویس | ⏳ | | +| ۶.۴ | `NoShowTrackerTest` — سوم برچسب، قدیمی‌تر از ۱۲ ماه نه، دوبار یک رکورد | ⏳ | | +| ۶.۵ | `NoShowTrackerTest` — بیمار پرریسک **رزرو موفق** دارد | ⏳ | ⭐ | +| ۶.۶ | `WaitlistMatcherTest` — سقف ۱۰، ترتیب، فیلتر روزبخش، `notify_count` | ⏳ | | +| ۶.۷ | `WaitlistConversionTest` | ⏳ | | +| ۶.۸ | `WaitlistAsyncTest` — شکست پیامک لغو را rollback نمی‌کند | ⏳ | ⭐ | +| ۶.۹ | `PatientWalletTenantTest` موجود سبز ماند | ⏳ | ⭐ | +| ۶.۱۰ | `CourseLifecycleTest` موجود — سیاست اعتبار اعمال شد | ⏳ | | + +## ۷. مستندات + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۷.۱ | `docs/api/cancellation.md` — preview اجباری، کلینیک بی‌جریمه | ⏳ | | +| ۷.۲ | `docs/api/waitlist.md` — تصمیم broadcast و دلیلش | ⏳ | | + +## ۸. بازبینی پایانی + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۸.۱ | هیچ 🔄 و ⏳ بی‌دلیل نمانده | ⏳ | | +| ۸.۲ | `bin/phpunit` کامل سبز | ⏳ | | +| ۸.۳ | `--group=slot-mode-frozen` سبز | ⏳ | | +| ۸.۴ | `phpstan` بدون خطای جدید | ⏳ | | +| ۸.۵ | `npx tsc --noEmit` و `yarn test` سبز | ⏳ | | +| ۸.۶ | تست‌های tenant سبز | ⏳ | | +| ۸.۷ | `docs/api/*` به‌روز | ⏳ | | +| ۸.۸ | چک‌لیست UI کامل | ⏳ | | +| ۸.۹ | ⚠️ سایت باید preview لغو را نشان دهد → `nobat724_front` بررسی و تسک ثبت شد | ⏳ | ⭐ | +| ۸.۱۰ | `clinic-pro-tauri` بررسی شد | ⏳ | | +| ۸.۱۱ | commit، سپس `graphify update .` | ⏳ | | +| ۸.۱۲ | موارد به‌تعویق با دلیل و تسک مقصد | ⏳ | | diff --git a/docs/new_feture/taskes/task-14-events-utilization/checklist.md b/docs/new_feture/taskes/task-14-events-utilization/checklist.md new file mode 100644 index 00000000..28058be6 --- /dev/null +++ b/docs/new_feture/taskes/task-14-events-utilization/checklist.md @@ -0,0 +1,119 @@ +# چک‌لیست — تسک ۱۴ (رویدادهای دامنه و گزارش بهره‌وری) + +**وضعیت کلی:** ⏳ شروع نشده · **آخرین بازبینی:** — + +قواعد: [_shared/definition-of-done.md](../_shared/definition-of-done.md) · +[red-lines.md](../_shared/red-lines.md) · [ui-conventions.md](../_shared/ui-conventions.md) + +--- + +## ۰. خط سرخ + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۰.۱ | `--group=slot-mode-frozen` سبز | ⏳ | | +| ۰.۲ | `AppointmentEvent` موجود دست‌نخورده | ⏳ | تاریخچهٔ وضعیت ≠ رویداد دامنه | +| ۰.۳ | پیامک‌های موجود (`Sms` domain) نشکستند | ⏳ | | +| ۰.۴ | گزارش با داده حدسی ساخته **نشد** | ⏳ | ⭐ بند ۱.۹ | + +## ۱. بک‌اند — رویدادها + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۱.۱ | `DomainEvent` پایه + `DomainEventPublisher` + `DomainEventLog` | ⏳ | | +| ۱.۲ | payload **فقط uuid و اسکالر** — هیچ entity | ⏳ | ⭐ | +| ۱.۳ | هر رویداد `entityType`/`entityId` دارد | ⏳ | وگرنه پیامک محیط اشتباه | +| ۱.۴ | الگوی **outbox**: `record()` داخل تراکنش کاری، فقط persist | ⏳ | ⭐ | +| ۱.۵ | `PublishDomainEventHandler` + `scheduler` هر ۱۰ ثانیه | ⏳ | | +| ۱.۶ | `attempts < 5`؛ ردیف شکست‌خورده **حذف نمی‌شود** | ⏳ | | +| ۱.۷ | همهٔ `dispatch` های تسک‌های ۰۷ تا ۱۳ به `record()` تغییر کردند | ⏳ | ⭐ | +| ۱.۸ | چهارده رویداد بند ۱۶ مستند ثبت شدند | ⏳ | | +| ۱.۹ | idempotency در **مصرف‌کننده**، با `domain_events.uuid` | ⏳ | at-least-once | +| ۱.۱۰ | worker با loop-wrap برای Coolify | ⏳ | کانتینر خارج نشود | +| ۱.۱۱ | `app:events:prune --older-than=180d` | ⏳ | | +| ۱.۱۲ | `GET /domain-events` فقط `ROLE_ADMIN` | ⏳ | | + +## ۲. بک‌اند — گزارش‌ها + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۲.۱ | `ResourceUtilizationReporter` با چهار عدد | ⏳ | | +| ۲.۲ | `available_minutes` **× `capacity`** منبع | ⏳ | ⭐ اتاق سه‌تخته سه برابر | +| ۲.۳ | `passive` در `occupied` هست، در `active` نه | ⏳ | | +| ۲.۴ | `setup/cleanup` در `occupied` هست | ⏳ | | +| ۲.۵ | `released` شمرده نمی‌شود (`status='booked'` فقط) | ⏳ | | +| ۲.۶ | `available = 0` → `utilization = null`، **نه صفر** | ⏳ | ⭐ معنای متفاوت | +| ۲.۷ | مرز بازه: `start_at >= from AND start_at < to` | ⏳ | نه `end_at <= to` | +| ۲.۸ | کوئری تجمعی با `GROUP BY`، بدون پیمایش | ⏳ | | +| ۲.۹ | **پیش از پیاده‌سازی** `plan-accuracy`: وجود `patient_sessions.started_at/ended_at` تأیید شد | ⏳ | ⭐ اگر نبود → تسک جدا، نه داده حدسی | +| ۲.۱۰ | `PlanAccuracyReporter` با آستانه‌های شدت | ⏳ | | +| ۲.۱۱ | انحراف **منفی** بزرگ هم `high` است | ⏳ | نصف ظرفیت هدر می‌رود | +| ۲.۱۲ | حداقل نمونه ۱۰، وگرنه `insufficient_data` | ⏳ | | +| ۲.۱۳ | بازه > ۹۰ روز → ۴۲۲ | ⏳ | | +| ۲.۱۴ | سه endpoint | ⏳ | | + +## ۳. دیتابیس + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۳.۱ | `domain_events` (BIGINT id) با سه ایندکس | ⏳ | | +| ۳.۲ | `idx_de_pending (published_at, occurred_at)` | ⏳ | کوئری worker | +| ۳.۳ | هیچ جدول دیگری تغییر نکرد | ⏳ | | +| ۳.۴ | `TenantSchemaCoverageTest` سبز | ⏳ | | + +## ۴. UI + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۴.۱ | `ResourceUtilizationPage` — جدول + نمودار `Recharts` | ⏳ | کتابخانهٔ موجود | +| ۴.۲ | `PlanAccuracyPage` — جدول انحراف با شدت | ⏳ | | +| ۴.۳ | ردیف‌های `active_ratio < 0.3` نشان هشدار دارند | ⏳ | | +| ۴.۴ | **tooltip توضیح `active_ratio` در خودِ UI** | ⏳ | ⭐ نه فقط در مستندات | +| ۴.۵ | `utilization = null` → `—` با tooltip «تقویم تعریف نشده» + لینک تنظیم | ⏳ | | +| ۴.۶ | لینک «ویرایش بخش‌های این سرویس» از `PlanAccuracyPage` | ⏳ | ⭐ گزارشی که راه اصلاح ندهد خوانده نمی‌شود | +| ۴.۷ | بازهٔ زمانی با `PersianDatePicker` | ⏳ | | +| ۴.۸ | وضعیت (بازه، فیلتر) در URL با `useUrlState` | ⏳ | | +| ۴.۹ | `DataTable` با skeleton و empty state | ⏳ | | +| ۴.۱۰ | رنگ نمودار از توکن‌های `--stat-*`، نه پالت پیش‌فرض Recharts | ⏳ | ⭐ | +| ۴.۱۱ | هیچ رنگ/شعاع hard-code | ⏳ | | +| ۴.۱۲ | دارک‌مود — نمودار هم در دارک خوانا است | ⏳ | ⭐ محور و legend | +| ۴.۱۳ | حالت فشرده | ⏳ | | +| ۴.۱۴ | RTL و موبایل — جدول و نمودار اسکرول افقی داخلی | ⏳ | | +| ۴.۱۵ | همهٔ رشته‌ها فارسی · اعداد با `formatNumber` | ⏳ | | +| ۴.۱۶ | `backTo` روی صفحات گزارش | ⏳ | | + +## ۵. تست + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۵.۱ | `OutboxTest` — record داخل تراکنش، rollback، انتشار، شکست، سقف تلاش | ⏳ | ⭐ | +| ۵.۲ | `EventPayloadTest` — reflection روی همهٔ زیرکلاس‌ها: فقط اسکالر | ⏳ | | +| ۵.۳ | `ResourceUtilizationTest` — شش سنجهٔ سند | ⏳ | ⭐ شامل `capacity` و `null` | +| ۵.۴ | `PlanAccuracyTest` — انحراف دوطرفه، نمونهٔ کم | ⏳ | | +| ۵.۵ | `ReportAuthTest` — منشی ۴۰۳، بازه ۴۲۲ | ⏳ | | +| ۵.۶ | `ReportQueryCountTest` — تعداد کوئری مستقل از تعداد منبع | ⏳ | | + +## ۶. مستندات + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۶.۱ | `docs/api/reports.md` — معنی هر عدد + جدول `active_ratio` | ⏳ | | +| ۶.۲ | `docs/architecture/domain-events.md` — قرارداد، فهرست، outbox، idempotency | ⏳ | | +| ۶.۳ | جدول تفاوت `AppointmentEvent` با `DomainEventLog` | ⏳ | ⭐ وگرنه یکی حذف می‌شود | + +## ۷. بازبینی پایانی + +| # | مورد | وضعیت | یادداشت | +|---|---|---|---| +| ۷.۱ | هیچ 🔄 و ⏳ بی‌دلیل نمانده | ⏳ | | +| ۷.۲ | `bin/phpunit` کامل سبز | ⏳ | | +| ۷.۳ | `--group=slot-mode-frozen` سبز | ⏳ | | +| ۷.۴ | `phpstan` بدون خطای جدید | ⏳ | | +| ۷.۵ | `npx tsc --noEmit` و `yarn test` سبز | ⏳ | | +| ۷.۶ | تست‌های tenant سبز | ⏳ | | +| ۷.۷ | `docs/api/*` به‌روز | ⏳ | | +| ۷.۸ | چک‌لیست UI کامل | ⏳ | | +| ۷.۹ | پیامک‌های موجود سرتاسر تست شدند (outbox نشکستشان) | ⏳ | ⭐ | +| ۷.۱۰ | دو کلاینت دیگر بررسی شدند | ⏳ | | +| ۷.۱۱ | commit، سپس `graphify update .` | ⏳ | | +| ۷.۱۲ | موارد به‌تعویق با دلیل و تسک مقصد | ⏳ | `plan-accuracy` اگر داده نبود |