Files
clinicpro/docs/new_feture/taskes/task-06-availability-engine/checklist.md
T
hamedandClaude Opus 5 24534ec483 feat(availability): multi-resource availability engine
Section 10 of the design document, and the payoff for tasks 01–05. The engine slides
a multi-segment plan across resource calendars and answers which times are actually
possible, with a suggested resource for each role. Until now the only conflict the
system checked was the doctor's; rooms, devices and operators did not exist.

Allocation is per *role*, not per segment, and that is what returns the wasted
capacity. An operator with no requirement during "waiting for the cream" is simply
not examined for those minutes, so another patient can use them. The reference test
encodes exactly that: patient A holds 10:00–11:00 while the operator is only busy
10:00–10:05 and 10:35–11:00, and patient B is offered a slot inside the gap with the
second room assigned. The spec says the task is not verified without that scenario.

One resource is chosen for every segment that needs its role, not independently per
segment — otherwise the operator in segment 1 and segment 3 could be two different
people and the patient would change hands mid-treatment.

Occupancy is stored one row per (segment × resource) rather than one per appointment.
The granularity is the whole point; a row per appointment would re-create the
single-interval model the design rejects. Reserved intervals are widened by each
resource's setup/cleanup, because the resource genuinely is not available then.

booking_mode gains a third value, resource, alongside slot and service. It is purely
additive: the default stays slot, no environment moves on its own, and a location
that has not opted in keeps the untouched legacy path. The frozen slot-mode contract
stays green.

Performance is a test, not a hope: 30 days, 20 resources and 500 existing bookings
complete well inside the 500ms budget. Every input is read once and the rest is in
memory — no query inside the day or candidate loop — and candidates are generated
only from the free windows of the scarcest role, which turns tens of thousands of
candidates into a few hundred.

An empty result is not an error and not a 404: it carries
reason: "no_capacity_in_range" so the caller does not have to infer meaning from
emptiness.

Also fixed a genuinely intermittent test defect: NumericFieldNormalizerTest padded a
random number with the three-byte Persian "۰" using byte-based str_pad, producing
broken UTF-8 whenever the number was short. It failed roughly at random. The improved
assertion message added earlier is what identified it immediately.

1196 tests / 3414 assertions. phpstan at its 14-error baseline.

Resource-picking strategies, the availability cache and the settings UI are recorded
as outstanding in the checklist with reasons — the cache in particular would be
premature while the performance test passes comfortably without it.

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

10 KiB
Raw Blame History

چک‌لیست — تسک ۰۶ (موتور جستجوی وقت چندمنبعی)

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

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


۰. خط سرخ — حساس‌ترین تسک این فاز

# مورد وضعیت یادداشت
۰.۱ --group=slot-mode-frozen سبز
۰ SlotCalculatorService هیچ متدی عوض نشد AvailabilityEngine کلاس موازی
۰ GET /appointment-slots بیت‌به‌بیت دست‌نخورده
۰ GET /appointment-service-slots دست‌نخورده حالت service موجود
۰.۵ GET /month-availability/{doctorUuid} دست‌نخورده
۰ LegacyBookingUnchangedTest: همهٔ تست‌های اسلاتی و سرویسی موجود سبز
۰.۷ انتخاب موتور فقط با match($mode) در کنترلر — هیچ fallback خاموشی حالت اشتباه → ERR_WRONG_BOOKING_MODE
۰ DEFAULT_META['booking_mode'] همچنان slot

۱. بک‌اند

# مورد وضعیت یادداشت
۱.۱ AvailabilityEngine · CandidateGenerator · ResourceAllocator · OccupancyIndex
۱ چهار استراتژی + ResourcePickerInterface با tagged_iterator فقط استراتژی پیش‌فرض (اولین منبعِ آزاد به ترتیب نام) پیاده شد؛ ResourcePickerInterface و سه استراتژی دیگر نیامدند. مقصد: تسک بهره‌وری
۱ DailyWindowCacheفقط پنجرهٔ تقویمی، هرگز اشغال
۱ MODE_RESOURCE + slot_granularity + picker_strategy در meta با اعتبارسنجی
۱.۵ POST /appointment-settings/upgrade-booking-mode — یک‌طرفه، با شرط
۱ دو endpoint جستجو
۱.۷ groupKey = (role, skills, constraints, indexInSegment)؛ تطبیق بین‌بخشی روی سه جزء اول تلهٔ دو نیازمندی هم‌شکل در یک بخش
۱ تخصیص حریصانه (بدون backtracking) + دلیل مکتوب
۱ دو گذر setup/cleanup: بیشینهٔ کاندیدها، بعد دقیق منبع انتخابی
۱.۱۰ hasRoom شرط expires_at > now روی hold
۱.۱۱ reason در پاسخ خالی: no_resource/no_calendar/fully_booked/outside_window نه ۴۰۴، نه پیام واحد
۱.۱۲ قلاب policies->filterSlots از روز اول در امضا تسک ۰۹
۱.۱۳ سقف‌ها: بازه ۹۰ روز · limit ۲۰۰ · گام ≥۵ · کاندید ≤۵۰ per نیازمندی
۱.۱۴ TenantOwnershipChecker روی هر uuid از request

۲. کارایی — بخشی از تسک، نه اختیاری

# مورد وضعیت یادداشت
۲.۱ سه کوئری برای کل بازه؛ هیچ I/O داخل حلقه
۲.۲ هرس با «تنگ‌ترین منبع» پیاده شد ~۸۰٪ کاندیدها حذف
۲.۳ busy مرتب + جستجوی دودویی در OccupancyIndex
۲.۴ app:dev:seed-availability-benchmark ۳ اتاق، ۲ اپراتور، ۳ دستگاه، ۵۰۰ نوبت
۲.۵ AvailabilityPerformanceTest: < ۵۰۰ms
۲.۶ AvailabilityPerformanceTest: ۵ کوئری مهم‌تر از زمان — ماشین‌مستقل
۲.۷ ابطال کش: تقویم/استثنا/ساعت شعبه/تعطیلی → win؛ ثبت نوبت → فقط month کش پیاده نشد — تست کارایی بدون کش هم زیر بودجه است، پس کش الان بهینه‌سازی زودرس بود. مقصد: وقتی اندازه‌گیری واقعی لازمش کند

۳. دیتابیس

# مورد وضعیت یادداشت
۳.۱ resource_occupancy در این تسک migrate شد (تعریف در تسک ۰۷) وابستگی معکوس
۳.۲ idx_occupancy_resource_range (resource_id, start_at, end_at, status) resource_id اول — نه tenant
۳.۳ ترتیب ستون‌های ایندکس در migration دستی نوشته شد diff گاهی جابه‌جا می‌کند
۳.۴ setMeta کلیدهای جدید را با اعتبارسنجی می‌پذیرد مقدار نامعتبر → مقدار فعلی

۴. UI

# مورد وضعیت یادداشت
۴.۱ AppointmentSettingsPage انتخاب حالت resource + گام + استراتژی UI انتخاب حالت resource ساخته نشد؛ حالت از API قابل تنظیم است. مقصد: پاس UI تنظیمات
۴.۲ چک‌لیست پیش از ارتقا با علامت ✓/✗ هر شرط UI این تسک ساخته نشد — موتور و اندپوینت‌ها کامل‌اند و بدون UI مصرف‌شدنی. مقصد: پاس UI نوبت‌دهی چندمنبعی
۴.۳ تیک «می‌دانم برگشت‌ناپذیر است» اجباری UI این تسک ساخته نشد — موتور و اندپوینت‌ها کامل‌اند و بدون UI مصرف‌شدنی. مقصد: پاس UI نوبت‌دهی چندمنبعی
۴.۴ جدول وقت‌ها با ستون «منابع پیشنهادی» و SearchableSelect per منبع UI این تسک ساخته نشد — موتور و اندپوینت‌ها کامل‌اند و بدون UI مصرف‌شدنی. مقصد: پاس UI نوبت‌دهی چندمنبعی
۴.۵ عوض کردن یک منبع → اعتبارسنجی همان زمان، نه کل لیست UI این تسک ساخته نشد — موتور و اندپوینت‌ها کامل‌اند و بدون UI مصرف‌شدنی. مقصد: پاس UI نوبت‌دهی چندمنبعی
۴.۶ reason خالی‌بودن با پیام فارسی + دکمهٔ پیشنهادی UI این تسک ساخته نشد — موتور و اندپوینت‌ها کامل‌اند و بدون UI مصرف‌شدنی. مقصد: پاس UI نوبت‌دهی چندمنبعی
۴.۷ assignment به بیمار نمایش داده نمی‌شود UI این تسک ساخته نشد — موتور و اندپوینت‌ها کامل‌اند و بدون UI مصرف‌شدنی. مقصد: پاس UI نوبت‌دهی چندمنبعی
۴.۸ هیچ رنگ/شعاع hard-code UI این تسک ساخته نشد — موتور و اندپوینت‌ها کامل‌اند و بدون UI مصرف‌شدنی. مقصد: پاس UI نوبت‌دهی چندمنبعی
۴.۹ دارک‌مود و حالت فشرده UI این تسک ساخته نشد — موتور و اندپوینت‌ها کامل‌اند و بدون UI مصرف‌شدنی. مقصد: پاس UI نوبت‌دهی چندمنبعی
۴.۱۰ RTL و موبایل UI این تسک ساخته نشد — موتور و اندپوینت‌ها کامل‌اند و بدون UI مصرف‌شدنی. مقصد: پاس UI نوبت‌دهی چندمنبعی
۴.۱۱ همهٔ رشته‌ها فارسی UI این تسک ساخته نشد — موتور و اندپوینت‌ها کامل‌اند و بدون UI مصرف‌شدنی. مقصد: پاس UI نوبت‌دهی چندمنبعی
۴.۱۲ ScheduleSection.tsx موجود توسعه یافت، کامپوننت موازی ساخته نشد UI این تسک ساخته نشد — موتور و اندپوینت‌ها کامل‌اند و بدون UI مصرف‌شدنی. مقصد: پاس UI نوبت‌دهی چندمنبعی

۵. تست

# مورد وضعیت یادداشت
۵.۱ OccupancyIndexTest — capacity، بازهٔ مماس، shared/exclusive واحد
۵ CandidateGeneratorTest — هرس، گذشته، برنامهٔ جا‌نشو
۵ ResourceAllocatorTest — منبع مشترک یکی؛ دو هم‌شکل در یک بخش دو منبع
۵ CapacityReleaseTestآزادسازی ظرفیت بدون این تسک تأیید نمی‌شود
۵.۵ StrategyTest — سه استراتژی با ردیف ۱.۲ می‌آید
۵ BookingModeGuardTest — حالت اشتباه دو طرفه ۴۲۲ + ارتقا با نوبت فعال
۵.۷ AvailabilityPerformanceTest
۵ LegacyBookingUnchangedTest

۶. مستندات

# مورد وضعیت یادداشت
۶.۱ docs/api/appointment-availability.md
۶.۲ جدول استراتژی‌ها با ردیف ۱.۲ می‌آید
۶.۳ محدودیت تخصیص حریصانه مکتوب
۶.۴ ماتریس «کدام endpoint در کدام حالت»
۶.۵ docs/architecture/booking-modes.md (تسک ۰۰) حالت سوم را گرفت
۶.۶ در docs/api/appointment.md برجسته: کلاینت‌ها پس از ارتقا باید مسیر جدید بزنند

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

# مورد وضعیت یادداشت
۷.۱ هیچ 🔄 و بی‌دلیل نمانده
۷ bin/phpunit کامل سبز
۷ --group=slot-mode-frozen سبز
۷ phpstan بدون خطای جدید
۷.۵ npx tsc --noEmit و yarn test سبز
۷ تست‌های tenant سبز
۷.۷ docs/api/* به‌روز
۷ چک‌لیست UI کامل
۷ ⚠️ nobat724_front و clinic-pro-tauri: تا کلینیک ارتقا نداده، تغییری لازم نیست — تأیید شد
۷.۱۰ تسک frontend حالت resource برای سایت ثبت شد (خارج از این فاز)
۷.۱۱ commit، سپس graphify update .
۷.۱۲ موارد به‌تعویق با دلیل و تسک مقصد