Files
clinicpro/docs/new_feture/taskes/task-14-events-utilization/task.md
T
hamed 021d0eb6b2 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.
2026-07-30 11:43:58 +03:30

84 lines
4.9 KiB
Markdown

# تسک ۱۴ — رویدادهای دامنه و گزارش بهره‌وری منابع
**فاز:** ۴ (بهینه‌سازی) · **وابستگی:** ۰۷ · **زمان:** ۸-۱۰ ساعت
---
## هدف
دو چیز از مستند:
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`