- 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.
96 lines
4.1 KiB
Markdown
96 lines
4.1 KiB
Markdown
# دیتابیس — تسک ۰۶
|
|
|
|
این تسک **جدول جدیدی نمیسازد** جز کش. مصرفکنندهٔ جدولهای تسک ۰۲/۰۳ و
|
|
`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, 'تعداد کوئری نباید با تعداد روز رشد کند');
|
|
```
|
|
|
|
شرط دوم مهمتر از اولی است: زمان روی ماشینهای مختلف فرق میکند، تعداد کوئری نه.
|