feat: implement cancellation policy, no-show tracking, and waitlist management
- Add implementation notes for cancellation and waitlist features. - Create task documentation outlining goals, current status, and acceptance criteria for cancellation policy and resource utilization reporting. - Establish architecture for domain events and outbox pattern to ensure reliable event publishing. - Define database schema for domain events and necessary queries for resource utilization and plan accuracy reports. - Implement detailed implementation notes covering edge cases, testing strategies, and documentation requirements.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# تسک ۱۴ — رویدادهای دامنه و گزارش بهرهوری منابع
|
||||
|
||||
**فاز:** ۴ (بهینهسازی) · **وابستگی:** ۰۷ · **زمان:** ۸-۱۰ ساعت
|
||||
|
||||
---
|
||||
|
||||
## هدف
|
||||
|
||||
دو چیز از مستند:
|
||||
|
||||
1. **بند ۱۶** — فهرست رویدادهایی که سیستم منتشر میکند تا سیستمهای دیگر (پیامک،
|
||||
حسابداری، گزارش) به آنها گوش بدهند.
|
||||
2. **بند ۱۷، ریسک سوم** — «کلینیک بخشهای نوبت را اشتباه تعریف کند → ظرفیت غلط حساب
|
||||
میشود». راهحل مستند: **گزارش بهرهوری منابع برای پیدا کردن اشکال.**
|
||||
|
||||
گزارش بهرهوری تنها ابزاری است که به کلینیک میگوید تعریف بخشهایش درست است یا نه.
|
||||
بدون آن، تسک ۰۵ یک ابزار قدرتمند بدون بازخورد است.
|
||||
|
||||
## وضعیت فعلی
|
||||
|
||||
- `AppointmentEvent` وجود دارد و تاریخچهٔ تغییر وضعیت نوبت را ثبت میکند
|
||||
- `symfony/messenger` + `symfony/redis-messenger` + `symfony/scheduler` در استک هستند
|
||||
- پیامک از راه `Sms` domain و `messenger:consume async` کار میکند
|
||||
- تسکهای ۰۷ تا ۱۳ هر کدام یک `dispatch` گذاشتهاند بدون یک قرارداد واحد
|
||||
|
||||
## دامنه
|
||||
|
||||
**هست:**
|
||||
- قرارداد واحد رویداد دامنه: نام، payload (فقط uuid)، زمان انتشار (بعد از commit)
|
||||
- ثبت همهٔ رویدادهای بند ۱۶ مستند
|
||||
- `domain_events` — جدول outbox برای تضمین انتشار
|
||||
- گزارش بهرهوری منابع: ساعت آزاد / اشغال / انتظار / کار فعال per منبع per بازه
|
||||
- گزارش «مدت پیشبینیشده در برابر مدت واقعی» برای تشخیص تعریف غلط بخشها
|
||||
|
||||
**نیست:** پیشبینی عدم حضور، پیشنهاد هوشمند وقت (فاز ۴ مستند، خارج از دامنه).
|
||||
|
||||
## Endpoint ها
|
||||
|
||||
| متد | مسیر | توضیح |
|
||||
|---|---|---|
|
||||
| GET | `/api/v1/reports/resource-utilization` | بهرهوری منابع در بازه |
|
||||
| GET | `/api/v1/reports/plan-accuracy` | مقایسهٔ مدت پیشبینی و واقعی per سرویس |
|
||||
| GET | `/api/v1/domain-events` | (ادمین) رویدادهای منتشرشده — عیبیابی |
|
||||
|
||||
## فهرست رویدادها (مستند بند ۱۶)
|
||||
|
||||
```
|
||||
HoldCreated AppointmentBooked
|
||||
AppointmentCancelled AppointmentRescheduled
|
||||
PatientNoShow AppointmentCompleted
|
||||
ResourceBlocked ResourceReleased
|
||||
CourseStarted CourseSessionCompleted
|
||||
CourseCompleted PackagePurchased
|
||||
CreditConsumed CreditRefunded
|
||||
```
|
||||
|
||||
## معیار پذیرش
|
||||
|
||||
- ✅ موفق: ثبت نوبت → یک ردیف در `domain_events` با نام `AppointmentBooked` و
|
||||
payload شامل `appointment_uuid`؛ و `GET /domain-events` آن را نشان میدهد.
|
||||
- ✅ موفق: رویداد **بعد از** commit منتشر میشود. تست: تراکنشی که rollback میشود
|
||||
هیچ رویدادی منتشر نمیکند.
|
||||
- ✅ موفق: گزارش بهرهوری برای اپراتور مریم در یک هفته →
|
||||
`{ available_minutes: 2400, occupied_minutes: 1800, active_minutes: 1200, utilization: 0.75, active_ratio: 0.50 }`.
|
||||
- ✅ موفق (**تشخیص تعریف غلط بخشها**): سرویسی که `total_minutes` پیشبینیاش ۶۰ است ولی
|
||||
میانگین مدت واقعی مراجعاتش ۹۰ دقیقه → `GET /reports/plan-accuracy` آن را با
|
||||
`deviation_percent: +50` و `severity: 'high'` برمیگرداند.
|
||||
- ✅ موفق: منبعی با `active_ratio` زیر ۰.۳ در گزارش با نشان «ظرفیت هدررفته» میآید —
|
||||
یعنی بخشهای `passive` یا انتظار زیادی به آن نسبت داده شده.
|
||||
- ❌ خطا: گزارش با بازهٔ بزرگتر از ۹۰ روز → `422`.
|
||||
- ❌ خطا: منشی روی `GET /domain-events` → `403` (فقط `ROLE_ADMIN`).
|
||||
- ⚠️ مرزی: منبع بدون هیچ تقویم → `available_minutes: 0` و `utilization: null` (نه صفر —
|
||||
تقسیم بر صفر معنایی متفاوت دارد).
|
||||
- ⚠️ مرزی: بخشهای `passive` در `occupied_minutes` میآیند ولی در `active_minutes` نه.
|
||||
- ⚠️ مرزی: `setup/cleanup` در `occupied_minutes` میآید (منبع واقعاً اشغال بوده).
|
||||
- ⚠️ مرزی: رویداد تکراری (پیام دوباره از messenger) → مصرفکننده idempotent، نه رویداد.
|
||||
|
||||
## خروجی
|
||||
|
||||
- `src/Shared/Event/` — قرارداد رویداد + outbox
|
||||
- `src/Report/` — دو گزارش
|
||||
- `assets/admin/pages/ResourceUtilizationPage.tsx` + `PlanAccuracyPage.tsx`
|
||||
- `docs/api/reports.md` + `docs/architecture/domain-events.md`
|
||||
Reference in New Issue
Block a user