Files
clinicpro/docs/new_feture/taskes/task-07-hold-and-book/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

82 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# تسک ۰۷ — رزرو موقت و ثبت نهایی چندمنبعی
**فاز:** ۱ (هسته) · **وابستگی:** ۰۶ · **زمان:** ۱۶-۲۰ ساعت
---
## هدف
مستند بند ۱۱ و قانون سوم جمع‌بندی: «جلوگیری از رزرو تکراری کار دیتابیس است، نه کار کد».
سه مرحلهٔ `جستجو → رزرو موقت → ثبت نهایی` روی **چند منبع** پیاده شود، با تضمین یکتایی
در سطح دیتابیس.
## وضعیت فعلی — نقطهٔ قوت پروژه
```php
// src/Appointment/Entity/Appointment.php
public const PAYMENT_TTL = 900;
#[ORM\Column(name: 'active_slot_key', length: 64, nullable: true, unique: true)]
private ?string $activeSlotKey = null; // "{doctorId}:{slotStart}" یا NULL
private function refreshActiveSlotKey(): void {
$this->activeSlotKey = !$this->isReserve && in_array($this->status, self::SLOT_OCCUPYING_STATUSES, true)
? sprintf('%d:%d', $this->doctor->getId(), $this->slotStart)
: null;
}
```
سه مرحله و تضمین دیتابیسی **از قبل درست پیاده شده‌اند**. محدودیت: کلید فقط
`doctor + slot_start` است و هیچ منبع دیگری را نمی‌پوشاند، و مدل «یک ردیف = یک بازهٔ پیوسته»
است.
## دامنه
**هست:**
- `resource_occupancy` — تنها مرجع حقیقت اشغال منابع
- `appointment_segments` — بخش‌های نوبت ثبت‌شده
- `HoldService` — رزرو موقت چندمنبعی با TTL
- `BookingService` — ثبت نهایی اتمی
- تضمین یکتایی در MariaDB (بدون `EXCLUDE` — راه‌حل «سطل زمانی»)
- انقضای خودکار hold ها (توسعهٔ `ExpireAppointmentsHandler` موجود)
- وضعیت `rescheduled` و رویداد جابه‌جایی
**نیست:** قیمت‌گذاری تفکیک‌شده (تسک ۰۸)، سیاست لغو و جریمه (تسک ۱۳).
## Endpoint ها
| متد | مسیر | توضیح |
|---|---|---|
| POST | `/api/v1/appointment-hold` | رزرو موقت یک زمان + منابعش |
| DELETE | `/api/v1/appointment-hold/{uuid}` | آزادسازی زودهنگام |
| POST | `/api/v1/appointment-confirm` | ثبت نهایی از یک hold معتبر |
| POST | `/api/v1/appointment/{uuid}/reschedule` | جابه‌جایی (hold جدید + آزادسازی قدیم، اتمی) |
## معیار پذیرش
- ✅ موفق: `POST /appointment-hold` با زمان و `assignment` معتبر → `201` با
`hold_uuid` و `expires_at`؛ ردیف‌های `resource_occupancy` با `status='hold'` برای
**هر بخش × هر منبع** ثبت می‌شوند.
- ✅ موفق: بلافاصله بعد از hold، `POST /appointment-availability` همان زمان را **برنمی‌گرداند**.
- ✅ موفق: `POST /appointment-confirm``200`، وضعیت `confirmed`، همهٔ ردیف‌های اشغال
`status='booked'` و `expires_at = NULL`.
- ✅ موفق (**تست همزمانی — اصلی‌ترین**): دو درخواست hold هم‌زمان روی همان منبع و بازه →
دقیقاً **یکی** `201` و دیگری `409` با `ERR_SLOT_TAKEN`. تست باید با تراکنش واقعی
موازی اجرا شود، نه mock.
- ✅ موفق: hold منقضی‌شده → `POST /appointment-confirm` با `409 ERR_HOLD_EXPIRED` و آن
زمان دوباره در جستجو ظاهر می‌شود.
- ✅ موفق: آزادسازی ظرفیت حفظ می‌شود — اپراتور در بخش انتظار ردیف اشغال **ندارد**.
- ❌ خطا: `confirm` با hold متعلق به کاربر دیگر → `404`.
- ❌ خطا: hold با منبعی که در `assignment` نیست ولی نیازمندی دارد → `422`.
- ⚠️ مرزی: منبع با `capacity=3` → سه hold هم‌زمان موفق، چهارمی `409`.
- ⚠️ مرزی: لغو نوبت → همهٔ ردیف‌های اشغالش آزاد (`status='released'`)، نه حذف فیزیکی.
- ⚠️ مرزی: `reschedule` که hold جدیدش شکست بخورد → نوبت قدیمی **دست‌نخورده** بماند.
- ⚠️ مرزی: نوبت‌های حالت `slot`/`service``active_slot_key` قدیمی همچنان کار می‌کند و
ردیف اشغال هم برایشان ساخته می‌شود (تور ایمنی دوگانه).
## خروجی
- `src/Appointment/Booking/`
- توسعهٔ `Appointment` entity با `segments` و رابطهٔ اشغال
- `docs/api/appointment-booking.md` + به‌روزرسانی `docs/api/appointment.md`
- تست همزمانی واقعی