Files
clinicpro/docs/new_feture/taskes/task-07-hold-and-book/checklist.md
T
hamedandClaude Opus 5 635bf3d2a8 fix(admin): correct two design-system mismatches found by looking at the pages
Screenshotting the pages under dark mode and compact density (rather than
trusting that design tokens were enough) turned up two mistakes repeated across
every page this feature set added:

- `.card` carries only the surface, border and radius — padding comes from the
  separate `.card-pad`. Fifteen cards were rendering with their content flush
  against the edges.
- `.field` *is* the input box, a 40px-tall flex row. Wrapping a label plus a
  control in it produced a joined addon rather than a label above its field.
  `.field-block` is the label-above layout, and thirty-seven wrappers now use it.

Both were invisible to type-checking and to the tests, which is exactly why the
visual pass was worth running. Numbers in the new UI now go through
formatNumber so they render as Persian digits, and the utilization page's
header no longer repeats the sentence that appears under its filters verbatim.

The QA driver gained a `--ui` flag: theme and density live in
localStorage['clinicpro-ui'], so without seeding them dark mode and compact
density cannot be screenshotted at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 21:42:11 +03:30

9.3 KiB
Raw Blame History

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

وضعیت کلی: بک‌اند، تضمین دیتابیسی، مستندات و جریان رزرو (چند مورد UI با مقصد) · آخرین بازبینی:

قواعد: _shared/definition-of-done.md · red-lines.md · ui-conventions.md


۰. خط سرخ

# مورد وضعیت یادداشت
۰.۱ --group=slot-mode-frozen سبز
۰ active_slot_key و refreshActiveSlotKey() دست‌نخورده و فعال دو تور ایمنی موازی
۰ slot_start/slot_end باقی ماندند چهار مصرف‌کننده رویشان کوئری می‌زنند
۰ is_reserve دست‌نخورده — رزرو هیچ ردیف اشغالی نمی‌سازد
۰.۵ POST /api/v1/appointment قدیمی بیت‌به‌بیت کار می‌کند LegacyBookingUnchangedTest
۰ PAYMENT_TTL و رفتار انقضای موجود حفظ شد

۱. تضمین همزمانی — قلب تسک

# مورد وضعیت یادداشت
۱.۱ resource_occupancy_slot با UNIQUE(resource_id, bucket, unit_index) کل تضمین اینجاست
۱ BUCKET_SECONDS = 300 ثابت + کامنت هشدار تغییرش
۱ سطل‌ها با intdiv($end - 1, 300) — نه بدون -1 وگرنه نوبت مجاور رد می‌شود
۱ unit_index با INSERT پشت‌سرهم، نه SELECT قبلش پنجرهٔ رقابت
۱.۵ ردیف‌ها مرتب بر (resource_id, bucket, unit_index) درج می‌شوند جلوگیری از deadlock
۱ SlotTakenException موجود بازاستفاده شد
۱.۷ محدودیت گرانولاریتی ۵ دقیقه در مستندات صریح

۲. بک‌اند

# مورد وضعیت یادداشت
۲.۱ ResourceOccupancy · AppointmentSegment
۲.۲ OccupancyWriterتنها نویسندهٔ resource_occupancy
۲.۳ HoldService · BookingService · RescheduleService
۲.۴ یک ردیف per (بخش × منبع) — نه per نوبت آزادسازی ظرفیت
۲.۵ برنامه در hold دوباره ساخته می‌شود؛ assignment کلاینت فقط اعتبارسنجی می‌شود سه نشتی ثبت‌شده از همین شکل بودند
۲.۶ منبع باید کاندید همان نیازمندی باشد، نه فقط هم‌محیط
۲.۷ confirm هفت مرحله در یک تراکنش
۲.۸ confirm idempotent — دوباره روی همان hold خطا نمی‌دهد
۲.۹ رویداد بعد از commit (DispatchAfterCurrentBusStamp) با uuid در payload تسک ۱۲ رویش حساب می‌کند
۲.۱۰ reschedule: اول hold جدید، بعد آزادسازی قدیم ترتیب
۲.۱۱ لغو = status='released' + حذف فیزیکی ردیف‌های سطل
۲.۱۲ setup/cleanup در بازهٔ اشغال، نه در appointment_segments
۲.۱۳ STATUS_RESCHEDULED + گذارهای مجاز
۲.۱۴ ExpireAppointmentsHandler موجود توسعه یافت AppointmentExpiryService::expireHolds() — همان زمان‌بند موجود
۲.۱۵ قلاب‌های تسک ۰۸ و ۰۹ در confirm (مراحل ۳ و ۶)
۲.۱۶ چهار endpoint
۲.۱۷ دو کد خطا در ErrorCodes.php با پیام فارسی ERR_SLOT_TAKEN · ERR_HOLD_EXPIRED

۳. دیتابیس

# مورد وضعیت یادداشت
۳.۱ resource_occupancy (BIGINT id) با چهار ایندکس
۳.۲ resource_occupancy_slot با UNIQUE
۳.۳ appointment_segments با snapshot name/segment_type قانون پنجم
۳.۴ سه ستون تهی‌پذیر روی appointments branch_id · plan_total_minutes · patient_facing_minutes
۳.۵ ترتیب ستون ایندکس‌ها دستی در migration
۳.۶ app:occupancy:backfill --force — idempotent، نوبت‌های بی‌منبع را گزارش می‌کند بدون آن رزرو جدید روی نوبت قدیم می‌نشیند
۳.۷ app:occupancy:prune --older-than=90d
۳.۸ resource_occupancy_slot در AGGREGATE_CHILDREN + هرگز کوئری مستقیم
۳.۹ TenantSchemaCoverageTest سبز

۴. UI

# مورد وضعیت یادداشت
۴.۱ تایمر شمارش معکوس hold HoldCountdown — مبنا expires_at سرور است نه شمارندهٔ مرورگر؛ زیر یک دقیقه هشدار می‌شود. سه تست
۴.۲ خطای 409 با لیست جایگزین انتخاب کهنه کنار گذاشته و جستجو دوباره اجرا می‌شود؛ جایگزین‌ها بلافاصله روی صفحه‌اند
۴.۳ خطای reschedule شامل «نوبت فعلی تغییری نکرد» جابه‌جایی با ?rebook=<uuid> روی همان صفحهٔ رزرو؛ رزرو جدید اول گرفته می‌شود، پس شکستش نوبت قدیم را دست‌نخورده می‌گذارد و پیام سرور همین را می‌گوید
۴.۴ مسدودسازی موردی منبع از صفحهٔ منابع ResourceBlocksModal + سه اندپوینت تازه؛ ۶ تست بک‌اند
۴.۵ تفکیک «مسدودسازی موردی» از «بلندمدت» در UI تفاوتشان بالای همان مودال نوشته شده، نه فقط در مستندات
۴.۶ هیچ رنگ/شعاع hard-code
۴.۷ دارک‌مود و حالت فشرده ⚠️ فقط توکن‌ها؛ بازبینی چشمی انجام نشد
۴.۸ RTL و موبایل جدول وقت‌ها اسکرول افقی داخلی دارد
۴.۹ همهٔ رشته‌ها فارسی
۴.۱۰ بخش‌های نوبت در AppointmentDetailPage GET /appointment/{uuid}/segments + AppointmentSegmentsCard؛ بخشِ بدون حضور بیمار کم‌رنگ است و فهرست خالی یعنی نوبت اسلاتی (کارت رندر نمی‌شود)
۴.۱۱ جریان سه‌مرحله‌ای رزرو ResourceBookingPage: جستجو → نگه‌داشتن → ثبت، با آزادسازی صریح
۴.۱۲ انتخاب پزشک پیش از ثبت ثبت نهایی بدون پزشک ممکن نیست؛ دکمه تا انتخاب نشدن غیرفعال است

۵. تست

# مورد وضعیت یادداشت
۵.۱ ConcurrentHoldTestدو اتصال واقعی، دقیقاً یکی موفق mock قبول نیست
۵ OccupancyWriterTest — بازهٔ مماس، capacity، ترتیب INSERT
۵ HoldLifecycleTest — hold/انقضا/آزادسازی زودهنگام
۵ BookingConfirmTest — hold دیگری ۴۰۴، منقضی ۴۰۹، idempotent
۵.۵ CapacityReleaseIntegrationTest اپراتور در بازهٔ انتظار ردیف ندارد
۵ RescheduleTest — شکست hold جدید → نوبت قدیم سالم
۵.۷ OccupancyBackfillTest — idempotent
۵ LegacyBookingUnchangedTest
۵ BookingTenantTest موجود سبز

۶. مستندات

# مورد وضعیت یادداشت
۶.۱ docs/api/appointment-booking.md
۶.۲ گرانولاریتی ۵ دقیقه و محدودیتش
۶.۳ قرارداد hold_uuid و TTL
۶.۴ تفکیک مسدودسازی موردی/بلندمدت
۶.۵ docs/architecture/booking-concurrency.md — سطل زمانی + دلیل رد دو گزینهٔ دیگر شش ماه بعد زیر سؤال می‌رود

۷. بازبینی پایانی

# مورد وضعیت یادداشت
۷.۱ هیچ 🔄 و بی‌دلیل نمانده
۷ bin/phpunit کامل سبز
۷ --group=slot-mode-frozen سبز
۷ phpstan بدون خطای جدید
۷.۵ npx tsc --noEmit و yarn test سبز
۷ تست‌های tenant سبز
۷.۷ docs/api/* به‌روز
۷ چک‌لیست UI کامل
۷ دو کلاینت دیگر بررسی شدند slot_start/slot_end سالم است؟
۷.۱۰ commit، سپس graphify update .
۷.۱۱ موارد به‌تعویق با دلیل و تسک مقصد