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,95 @@
|
||||
# دیتابیس — تسک ۰۶
|
||||
|
||||
این تسک **جدول جدیدی نمیسازد** جز کش. مصرفکنندهٔ جدولهای تسک ۰۲/۰۳ و
|
||||
`resource_occupancy` تسک ۰۷ است.
|
||||
|
||||
⚠️ **وابستگی معکوس:** موتور جستجو به `resource_occupancy` نیاز دارد ولی آن جدول در تسک ۰۷
|
||||
ساخته میشود. راهحل: **مهاجرت جدول `resource_occupancy` در همین تسک انجام شود** و تسک ۰۷
|
||||
فقط منطق نوشتن در آن را اضافه کند. تعریف کامل جدول در
|
||||
[task-07/database.md](../task-07-hold-and-book/database.md) است؛ اینجا فقط ایندکسهای
|
||||
لازم برای خواندن ذکر میشوند.
|
||||
|
||||
## ایندکسهای حیاتی خواندن
|
||||
|
||||
```sql
|
||||
-- کوئری داغ: اشغالهای این منابع در این بازه
|
||||
KEY idx_occupancy_resource_range (resource_id, start_at, end_at, status)
|
||||
```
|
||||
|
||||
پرسوجو:
|
||||
|
||||
```sql
|
||||
SELECT resource_id, start_at, end_at, units
|
||||
FROM resource_occupancy
|
||||
WHERE resource_id IN (?, ?, …)
|
||||
AND start_at < :to AND end_at > :from
|
||||
AND status IN ('hold', 'booked')
|
||||
```
|
||||
|
||||
`resource_id` ستون اول است چون `IN` روی آن، محدودکنندهترین شرط است. اضافه کردن
|
||||
`entity_type` به ابتدای این ایندکس **اشتباه** است: اینجا فیلتر tenant از راه منابع
|
||||
(که خودشان محیط دارند) اعمال شده و ستون tenant-پیشرو فقط ایندکس را بیاثر میکند.
|
||||
یک ایندکس دوم tenant-پیشرو برای لیستهای پنل جدا تعریف میشود (تسک ۰۷).
|
||||
|
||||
## تنظیمات جدید روی `weekly_schedules.setting.meta`
|
||||
|
||||
بدون تغییر schema (ستون JSON موجود):
|
||||
|
||||
```json
|
||||
{
|
||||
"meta": {
|
||||
"booking_mode": "resource",
|
||||
"slot_granularity": 15,
|
||||
"picker_strategy": "least_gap",
|
||||
"buffer_minutes": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`setMeta()` باید کلیدهای جدید را با اعتبارسنجی بپذیرد:
|
||||
- `slot_granularity` ∈ {5, 10, 15, 20, 30, 60}
|
||||
- `picker_strategy` ∈ کلیدهای ثبتشدهٔ `ResourcePickerInterface`
|
||||
|
||||
مقدار نامعتبر → مقدار فعلی حفظ میشود (همان الگوی موجود `setMeta`).
|
||||
|
||||
## کش
|
||||
|
||||
Redis، بدون جدول. کلیدها:
|
||||
|
||||
```
|
||||
cp:avail:res:{resourceId}:win:{Y-m-d} → JSON بازههای آزاد TTL تا پایان روز
|
||||
cp:avail:month:{branchId}:{serviceId}:{Y-m} → JSON بولین per روز TTL 300s
|
||||
```
|
||||
|
||||
ابطال:
|
||||
|
||||
| رویداد | کلیدهای باطل |
|
||||
|---|---|
|
||||
| تغییر `resource_calendars` | همهٔ `win` آن منبع |
|
||||
| ثبت/حذف `resource_exceptions` | `win` آن منبع در بازهٔ استثنا |
|
||||
| تغییر `branch_working_hours` | `win` همهٔ منابع آن شعبه |
|
||||
| تغییر `tenant_holiday_overrides` | `win` همهٔ منابع آن محیط در آن روز |
|
||||
| ثبت/لغو نوبت | فقط `month` — **`win` هرگز** (اشغال کش نمیشود) |
|
||||
|
||||
آخرین سطر مهمترین است: اگر کسی وسوسه شد اشغال را هم کش کند، نتیجهاش نمایش وقتِ
|
||||
گرفتهشده و شکست رزرو در مرحلهٔ آخر است.
|
||||
|
||||
## تست کارایی — داده مصنوعی
|
||||
|
||||
```bash
|
||||
ddev exec php bin/console app:dev:seed-availability-benchmark --force
|
||||
```
|
||||
|
||||
میسازد:
|
||||
- ۱ شعبه · ۳ اتاق (ظرفیت ۱) · ۲ اپراتور · ۳ دستگاه در یک استخر
|
||||
- ۱ سرویس با ۴ بخش (سناریوی مستند)
|
||||
- ۵۰۰ نوبت پراکنده در ۳۰ روز آینده
|
||||
|
||||
`AvailabilityPerformanceTest` روی همین داده اجرا میشود و **دو** چیز را میسنجد:
|
||||
|
||||
```php
|
||||
self::assertLessThan(500, $elapsedMs, 'جستجوی ۳۰ روزه باید زیر نیم ثانیه باشد');
|
||||
self::assertLessThanOrEqual(5, $queryCount, 'تعداد کوئری نباید با تعداد روز رشد کند');
|
||||
```
|
||||
|
||||
شرط دوم مهمتر از اولی است: زمان روی ماشینهای مختلف فرق میکند، تعداد کوئری نه.
|
||||
Reference in New Issue
Block a user