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

4.6 KiB
Raw Blame History

تسک ۰۷ — رزرو موقت و ثبت نهایی چندمنبعی

فاز: ۱ (هسته) · وابستگی: ۰۶ · زمان: ۱۶-۲۰ ساعت


هدف

مستند بند ۱۱ و قانون سوم جمع‌بندی: «جلوگیری از رزرو تکراری کار دیتابیس است، نه کار کد». سه مرحلهٔ جستجو → رزرو موقت → ثبت نهایی روی چند منبع پیاده شود، با تضمین یکتایی در سطح دیتابیس.

وضعیت فعلی — نقطهٔ قوت پروژه

// 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-confirm200، وضعیت 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/serviceactive_slot_key قدیمی همچنان کار می‌کند و ردیف اشغال هم برایشان ساخته می‌شود (تور ایمنی دوگانه).

خروجی

  • src/Appointment/Booking/
  • توسعهٔ Appointment entity با segments و رابطهٔ اشغال
  • docs/api/appointment-booking.md + به‌روزرسانی docs/api/appointment.md
  • تست همزمانی واقعی