docs: reconcile checklists with what the last passes actually built
Rows closed by the resource-strategy and blocking work: task 06's picker interface and four strategies, task 07's ad-hoc blocking and 409 recovery, and task 12's same-as-previous preference, which had been blocked on task 06's missing strategies since it was written. Tasks 13 and 14 both carried the flaky-suite caveat against their final review; that flake has a diagnosed cause and a fix, so both now say so instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
| # | مورد | وضعیت | یادداشت |
|
| # | مورد | وضعیت | یادداشت |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ۱.۱ | `AvailabilityEngine` · `CandidateGenerator` · `ResourceAllocator` · `OccupancyIndex` | ✅ | |
|
| ۱.۱ | `AvailabilityEngine` · `CandidateGenerator` · `ResourceAllocator` · `OccupancyIndex` | ✅ | |
|
||||||
| ۱.۲ | چهار استراتژی + `ResourcePickerInterface` با tagged_iterator | ⏳ | فقط استراتژی پیشفرض (اولین منبعِ آزاد به ترتیب نام) پیاده شد؛ `ResourcePickerInterface` و سه استراتژی دیگر نیامدند. مقصد: تسک بهرهوری |
|
| ۱.۲ | چهار استراتژی + `ResourcePicker` با tagged_iterator | ✅ | ⭐ `first_available` · `least_gap` · `least_loaded` · `same_as_previous`؛ استراتژی **مرتب میکند، انتخاب نمیکند** |
|
||||||
| ۱.۳ | `DailyWindowCache` — **فقط پنجرهٔ تقویمی**، هرگز اشغال | ✅ | ⭐ |
|
| ۱.۳ | `DailyWindowCache` — **فقط پنجرهٔ تقویمی**، هرگز اشغال | ✅ | ⭐ |
|
||||||
| ۱.۴ | `MODE_RESOURCE` + `slot_granularity` + `picker_strategy` در `meta` | ✅ | با اعتبارسنجی |
|
| ۱.۴ | `MODE_RESOURCE` + `slot_granularity` + `picker_strategy` در `meta` | ✅ | با اعتبارسنجی |
|
||||||
| ۱.۵ | `POST /appointment-settings/upgrade-booking-mode` — یکطرفه، با شرط | ✅ | |
|
| ۱.۵ | `POST /appointment-settings/upgrade-booking-mode` — یکطرفه، با شرط | ✅ | |
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
| # | مورد | وضعیت | یادداشت |
|
| # | مورد | وضعیت | یادداشت |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ۴.۱ | انتخاب حالت `resource` + گام | ⚠️ | حالت سوم و «گام جستجوی وقت» به `ScheduleSection` اضافه شد. انتخابگر **استراتژی** ساخته نشد چون استراتژیای در بکاند وجود ندارد (ردیف ۱.۲) — منوی خالی بدتر از نبودنش است |
|
| ۴.۱ | انتخاب حالت `resource` + گام + استراتژی | ✅ | هر سه در `ScheduleSection`؛ فهرست استراتژیها از `GET /appointment-settings/resource-strategies` میآید، نه از فهرستی که در فرانت تکرار شود |
|
||||||
| ۴.۲ | چکلیست پیش از ارتقا با ✓/✗ | ✅ | ⭐ «حداقل یک منبع فعال» و «حداقل یک سرویس با بخش» با لینک اصلاح؛ همان شرطی که بکاند هم اعمال میکند |
|
| ۴.۲ | چکلیست پیش از ارتقا با ✓/✗ | ✅ | ⭐ «حداقل یک منبع فعال» و «حداقل یک سرویس با بخش» با لینک اصلاح؛ همان شرطی که بکاند هم اعمال میکند |
|
||||||
| ۴.۳ | تأیید برگشتناپذیری | ✅ | `ConfirmDialog` موجود، حالا با برچسب درست هر سه حالت |
|
| ۴.۳ | تأیید برگشتناپذیری | ✅ | `ConfirmDialog` موجود، حالا با برچسب درست هر سه حالت |
|
||||||
| ۴.۴ | جدول وقتها با ستون «منابع پیشنهادی» | ✅ | `ResourceBookingPage` — تاریخ، ساعت، منابع، انتخاب |
|
| ۴.۴ | جدول وقتها با ستون «منابع پیشنهادی» | ✅ | `ResourceBookingPage` — تاریخ، ساعت، منابع، انتخاب |
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
| ۵.۲ | `CandidateGeneratorTest` — هرس، گذشته، برنامهٔ جانشو | ✅ | |
|
| ۵.۲ | `CandidateGeneratorTest` — هرس، گذشته، برنامهٔ جانشو | ✅ | |
|
||||||
| ۵.۳ | `ResourceAllocatorTest` — منبع مشترک یکی؛ دو همشکل در یک بخش دو منبع | ✅ | |
|
| ۵.۳ | `ResourceAllocatorTest` — منبع مشترک یکی؛ دو همشکل در یک بخش دو منبع | ✅ | |
|
||||||
| ۵.۴ | `CapacityReleaseTest` — **آزادسازی ظرفیت** | ✅ | ⭐⭐ بدون این تسک تأیید نمیشود |
|
| ۵.۴ | `CapacityReleaseTest` — **آزادسازی ظرفیت** | ✅ | ⭐⭐ بدون این تسک تأیید نمیشود |
|
||||||
| ۵.۵ | `StrategyTest` — سه استراتژی | ⏳ | با ردیف ۱.۲ میآید |
|
| ۵.۵ | تست استراتژیها | ✅ | `ResourcePickerTest` — ۹ تست: ترتیب هر چهار استراتژی، رجیستری، بازگشت به پیشفرض روی کلید ناشناخته، رد شدن هنگام ذخیره |
|
||||||
| ۵.۶ | `BookingModeGuardTest` — حالت اشتباه دو طرفه ۴۲۲ + ارتقا با نوبت فعال | ✅ | |
|
| ۵.۶ | `BookingModeGuardTest` — حالت اشتباه دو طرفه ۴۲۲ + ارتقا با نوبت فعال | ✅ | |
|
||||||
| ۵.۷ | `AvailabilityPerformanceTest` | ✅ | |
|
| ۵.۷ | `AvailabilityPerformanceTest` | ✅ | |
|
||||||
| ۵.۸ | `LegacyBookingUnchangedTest` | ✅ | ⭐ |
|
| ۵.۸ | `LegacyBookingUnchangedTest` | ✅ | ⭐ |
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
| # | مورد | وضعیت | یادداشت |
|
| # | مورد | وضعیت | یادداشت |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ۶.۱ | `docs/api/appointment-availability.md` | ✅ | |
|
| ۶.۱ | `docs/api/appointment-availability.md` | ✅ | |
|
||||||
| ۶.۲ | جدول استراتژیها | ⏳ | با ردیف ۱.۲ میآید |
|
| ۶.۲ | جدول استراتژیها | ✅ | در `appointment-availability.md` با «کِی مناسب است» هر کدام |
|
||||||
| ۶.۳ | محدودیت تخصیص حریصانه مکتوب | ✅ | |
|
| ۶.۳ | محدودیت تخصیص حریصانه مکتوب | ✅ | |
|
||||||
| ۶.۴ | ماتریس «کدام endpoint در کدام حالت» | ✅ | |
|
| ۶.۴ | ماتریس «کدام endpoint در کدام حالت» | ✅ | |
|
||||||
| ۶.۵ | `docs/architecture/booking-modes.md` (تسک ۰۰) حالت سوم را گرفت | ✅ | |
|
| ۶.۵ | `docs/architecture/booking-modes.md` (تسک ۰۰) حالت سوم را گرفت | ✅ | |
|
||||||
|
|||||||
@@ -71,10 +71,10 @@
|
|||||||
| # | مورد | وضعیت | یادداشت |
|
| # | مورد | وضعیت | یادداشت |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ۴.۱ | تایمر شمارش معکوس hold | ✅ | ⭐ `HoldCountdown` — مبنا `expires_at` سرور است نه شمارندهٔ مرورگر؛ زیر یک دقیقه هشدار میشود. سه تست |
|
| ۴.۱ | تایمر شمارش معکوس hold | ✅ | ⭐ `HoldCountdown` — مبنا `expires_at` سرور است نه شمارندهٔ مرورگر؛ زیر یک دقیقه هشدار میشود. سه تست |
|
||||||
| ۴.۲ | خطای `409` با لیست جایگزین | ⚠️ | پیام سرور («این ساعت همین لحظه رزرو شد») نمایش داده میشود؛ **لیست جایگزین خودکار** ساخته نشد — کاربر باید دوباره جستجو بزند |
|
| ۴.۲ | خطای `409` با لیست جایگزین | ✅ | ⭐ انتخاب کهنه کنار گذاشته و جستجو دوباره اجرا میشود؛ جایگزینها بلافاصله روی صفحهاند |
|
||||||
| ۴.۳ | خطای `reschedule` شامل «نوبت فعلی تغییری نکرد» | ⏳ | جریان جابهجایی نوبت در پنل ساخته نشد؛ `rebook` از API کامل است |
|
| ۴.۳ | خطای `reschedule` شامل «نوبت فعلی تغییری نکرد» | ⏳ | جریان جابهجایی نوبت در پنل ساخته نشد؛ `rebook` از API کامل است |
|
||||||
| ۴.۴ | مسدودسازی موردی منبع از صفحهٔ منابع | ⏳ | مقصد: پاس بعدی صفحهٔ منابع |
|
| ۴.۴ | مسدودسازی موردی منبع از صفحهٔ منابع | ✅ | `ResourceBlocksModal` + سه اندپوینت تازه؛ ۶ تست بکاند |
|
||||||
| ۴.۵ | تفکیک «مسدودسازی موردی» از «بلندمدت» در UI | ⏳ | با ۴.۴ یک بسته است |
|
| ۴.۵ | تفکیک «مسدودسازی موردی» از «بلندمدت» در UI | ✅ | ⭐ تفاوتشان بالای همان مودال نوشته شده، نه فقط در مستندات |
|
||||||
| ۴.۶ | هیچ رنگ/شعاع hard-code | ✅ | |
|
| ۴.۶ | هیچ رنگ/شعاع hard-code | ✅ | |
|
||||||
| ۴.۷ | دارکمود و حالت فشرده | ⚠️ | فقط توکنها؛ بازبینی چشمی انجام نشد |
|
| ۴.۷ | دارکمود و حالت فشرده | ⚠️ | فقط توکنها؛ بازبینی چشمی انجام نشد |
|
||||||
| ۴.۸ | RTL و موبایل | ✅ | جدول وقتها اسکرول افقی داخلی دارد |
|
| ۴.۸ | RTL و موبایل | ✅ | جدول وقتها اسکرول افقی داخلی دارد |
|
||||||
|
|||||||
@@ -28,9 +28,9 @@
|
|||||||
| ۱.۶ | نزدیکترین به ایدهآل | ✅ | `usort` روی `abs(start - ideal)` |
|
| ۱.۶ | نزدیکترین به ایدهآل | ✅ | `usort` روی `abs(start - ideal)` |
|
||||||
| ۱.۷ | لنگر پیشنهاد = آخرین جلسهٔ `completed` | ✅ | ⭐ `testTheSuggestionAnchorsOnTheLastCompletedSession` |
|
| ۱.۷ | لنگر پیشنهاد = آخرین جلسهٔ `completed` | ✅ | ⭐ `testTheSuggestionAnchorsOnTheLastCompletedSession` |
|
||||||
| ۱.۸ | سقف ۹۰ روز + پیام روشن | ✅ | ⭐ جلسات بیرون بازه `planned` میمانند، خطا نیست |
|
| ۱.۸ | سقف ۹۰ روز + پیام روشن | ✅ | ⭐ جلسات بیرون بازه `planned` میمانند، خطا نیست |
|
||||||
| ۱.۹ | `same_as_previous` ترجیح نه الزام | ⚠️ | `prefer_same_resource` و `preferredResource` ذخیره میشوند ولی هنوز به انتخاب منبع وصل نیستند |
|
| ۱.۹ | `same_as_previous` ترجیح نه الزام | ✅ | ⭐ منبع ترجیحی جلو میآید، بقیه حذف نمیشوند؛ اجبار یعنی بیمار دو هفته منتظر بماند |
|
||||||
| ۱.۱۰ | `preferredResourceIds` در `PlanRequest` | ⏳ | با ۱.۹ و ۱.۱۱ یک بسته است |
|
| ۱.۱۰ | `preferredResourceIds` حمل میشود | ✅ | `POST /appointment-availability` فیلد `course_uuid` میگیرد و `preferred_resource` دوره را به موتور میدهد |
|
||||||
| ۱.۱۱ | `SameAsPreviousPicker` تسک ۰۶ | ⏳ | **تسک ۰۶ اصلاً استراتژی انتخاب منبع نساخت** (بدهی ثبتشدهٔ همان تسک)؛ ساختن picker اینجا یعنی نصف تسک ۰۶ را اینجا نوشتن |
|
| ۱.۱۱ | `SameAsPreviousPicker` تسک ۰۶ | ✅ | همراه سه استراتژی دیگر در تسک ۰۶ ساخته شد |
|
||||||
| ۱.۱۲ | تعامل با `spacing`: سختگیرانهتر برنده | ⚠️ | `max(min)` پیاده شد (`effectiveMinDays`)؛ `min(max)` لازم نشد چون قانون `spacing` اثر «حداکثر» ندارد. بازهٔ تهی هم ممکن نیست چون `max` همیشه با `min` بالا میرود |
|
| ۱.۱۲ | تعامل با `spacing`: سختگیرانهتر برنده | ⚠️ | `max(min)` پیاده شد (`effectiveMinDays`)؛ `min(max)` لازم نشد چون قانون `spacing` اثر «حداکثر» ندارد. بازهٔ تهی هم ممکن نیست چون `max` همیشه با `min` بالا میرود |
|
||||||
| ۱.۱۳ | اعتبار پکیج کمتر از جلسات → هشدار نه خطا | ⚠️ | پکیج به دوره وصل میشود و پوششش بررسی میشود، ولی مقایسهٔ **مانده با تعداد جلسات** هنوز هشدار نمیدهد |
|
| ۱.۱۳ | اعتبار پکیج کمتر از جلسات → هشدار نه خطا | ⚠️ | پکیج به دوره وصل میشود و پوششش بررسی میشود، ولی مقایسهٔ **مانده با تعداد جلسات** هنوز هشدار نمیدهد |
|
||||||
| ۱.۱۴ | `active_course_key` | ✅ | ⭐ همان الگوی `active_slot_key` |
|
| ۱.۱۴ | `active_course_key` | ✅ | ⭐ همان الگوی `active_slot_key` |
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
| ۳.۴ | ستون فاصلهٔ واقعی بین جلسات | ⏳ | جدول تاریخ هر جلسه را میدهد ولی فاصلهٔ محاسبهشده را نه |
|
| ۳.۴ | ستون فاصلهٔ واقعی بین جلسات | ⏳ | جدول تاریخ هر جلسه را میدهد ولی فاصلهٔ محاسبهشده را نه |
|
||||||
| ۳.۵ | هشدار عبور از حداکثر فاصله | ✅ | با رنگ `--warning` |
|
| ۳.۵ | هشدار عبور از حداکثر فاصله | ✅ | با رنگ `--warning` |
|
||||||
| ۳.۶ | بنر پیشنهاد جلسهٔ بعدی | ✅ | در کارت بالای صفحهٔ دوره |
|
| ۳.۶ | بنر پیشنهاد جلسهٔ بعدی | ✅ | در کارت بالای صفحهٔ دوره |
|
||||||
| ۳.۷ | نام منبع ترجیحی روی دکمهٔ رزرو | ⏳ | با ۱.۹ یک بسته است |
|
| ۳.۷ | نام منبع ترجیحی روی دکمهٔ رزرو | ⚠️ | ترجیح در بکاند اعمال میشود؛ نمایش نامش روی دکمهٔ رزرو دوره هنوز نیست |
|
||||||
| ۳.۸ | پیشنهاد بازچینی پس از لغو وسط دوره | ⏳ | تسک ۱۳ (لغو و لیست انتظار) |
|
| ۳.۸ | پیشنهاد بازچینی پس از لغو وسط دوره | ⏳ | تسک ۱۳ (لغو و لیست انتظار) |
|
||||||
| ۳.۹ | `DataTable` برای جلسات | ✅ | |
|
| ۳.۹ | `DataTable` برای جلسات | ✅ | |
|
||||||
| ۳.۱۰ | نشان وضعیت جلسه و دوره | ✅ | کلاسهای `badge` موجود |
|
| ۳.۱۰ | نشان وضعیت جلسه و دوره | ✅ | کلاسهای `badge` موجود |
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
| ۴.۵ | سقف ۹۰ روز | ⏳ | همان |
|
| ۴.۵ | سقف ۹۰ روز | ⏳ | همان |
|
||||||
| ۴.۶ | لنگر `completed` + هشدار عبور از max | ✅ | ⭐ |
|
| ۴.۶ | لنگر `completed` + هشدار عبور از max | ✅ | ⭐ |
|
||||||
| ۴.۷ | پیشرفت دوره | ✅ | «۳ از ۸» + `next_params` |
|
| ۴.۷ | پیشرفت دوره | ✅ | «۳ از ۸» + `next_params` |
|
||||||
| ۴.۸ | ترجیح همان منبع | ⏳ | با ۱.۹ |
|
| ۴.۸ | ترجیح همان منبع | ✅ | `ResourcePickerTest` — «جلو میآید و هیچ کاندیدی حذف نمیشود» |
|
||||||
| ۴.۹ | تعامل با قانون `spacing` | ⏳ | `effectiveMinDays` نوشته شد ولی تست اختصاصی ندارد |
|
| ۴.۹ | تعامل با قانون `spacing` | ⏳ | `effectiveMinDays` نوشته شد ولی تست اختصاصی ندارد |
|
||||||
| ۴.۱۰ | مصرف پکیج per جلسه | ⚠️ | مسیر مصرف از تسک ۱۱ میآید (`confirm` هر نوبت)، پس دوره چیز تازهای لازم ندارد؛ تست اختصاصی نوشته نشد |
|
| ۴.۱۰ | مصرف پکیج per جلسه | ⚠️ | مسیر مصرف از تسک ۱۱ میآید (`confirm` هر نوبت)، پس دوره چیز تازهای لازم ندارد؛ تست اختصاصی نوشته نشد |
|
||||||
| ۴.۱۱ | چرخهٔ عمر — لغو، تکمیل خودکار، `abandon` | ✅ | ⭐ `testCancellingOneSessionOnlyResetsThatSession` و `testTheCourseCompletesOnlyWhenEverySessionIsDone` |
|
| ۴.۱۱ | چرخهٔ عمر — لغو، تکمیل خودکار، `abandon` | ✅ | ⭐ `testCancellingOneSessionOnlyResetsThatSession` و `testTheCourseCompletesOnlyWhenEverySessionIsDone` |
|
||||||
|
|||||||
@@ -117,7 +117,7 @@
|
|||||||
| # | مورد | وضعیت | یادداشت |
|
| # | مورد | وضعیت | یادداشت |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ۸.۱ | هیچ ⏳ بیدلیل نمانده | ✅ | ۱۲ مورد ⏳/⚠️ همه با دلیل و تسک مقصد |
|
| ۸.۱ | هیچ ⏳ بیدلیل نمانده | ✅ | ۱۲ مورد ⏳/⚠️ همه با دلیل و تسک مقصد |
|
||||||
| ۸.۲ | `bin/phpunit` کامل سبز | ⚠️ | ۱۳۰۵ تست سبز است، ولی حدود ۴۰٪ اجراهای کامل یک خطای `EntityManager is closed` روی یک تست **تصادفیِ نامرتبط** میدهند. در اجرای زیرمجموعهها هرگز تکرار نمیشود و تست خطاده هر بار عوض میشود. با حذف تستهای این تسک هم دیده شد ⇒ احتمالاً flake محیط ddev، نه رگرسیون این تسک. **باید جدا بررسی شود** |
|
| ۸.۲ | `bin/phpunit` کامل سبز | ✅ | flake پیدا و رفع شد: قید یکتای شکسته `EntityManager` را میبندد و کانتینر همان نمونهٔ بسته را برمیگرداند، پس تستِ بعدی مدیرِ مرده را ارث میبرد. `setUp` حالا ریست میکند و `UserCollisionRetryTest` آن را پین میکند. سه اجرای پیاپی سبز |
|
||||||
| ۸.۳ | `--group=slot-mode-frozen` سبز | ✅ | |
|
| ۸.۳ | `--group=slot-mode-frozen` سبز | ✅ | |
|
||||||
| ۸.۴ | `phpstan` بدون خطای جدید | ✅ | ۱۴ = baseline |
|
| ۸.۴ | `phpstan` بدون خطای جدید | ✅ | ۱۴ = baseline |
|
||||||
| ۸.۵ | `npx tsc --noEmit` و تستهای فرانت سبز | ✅ | ۶۳۲ تست |
|
| ۸.۵ | `npx tsc --noEmit` و تستهای فرانت سبز | ✅ | ۶۳۲ تست |
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
| # | مورد | وضعیت | یادداشت |
|
| # | مورد | وضعیت | یادداشت |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ۷.۱ | هیچ ⏳ بیدلیل نمانده | ✅ | همه با دلیل |
|
| ۷.۱ | هیچ ⏳ بیدلیل نمانده | ✅ | همه با دلیل |
|
||||||
| ۷.۲ | `bin/phpunit` کامل سبز | ⚠️ | ۱۳۲۱ تست سبز؛ همان flake تصادفیِ `EntityManager is closed` که در تسک ۱۳ ثبت شد گاهی تکرار میشود — نامرتبط با این تسک، نیازمند بررسی جدا |
|
| ۷.۲ | `bin/phpunit` کامل سبز | ✅ | ۱۳۴۰ تست؛ flakeِ ثبتشده در تسک ۱۳ پیدا و رفع شد |
|
||||||
| ۷.۳ | `--group=slot-mode-frozen` سبز | ✅ | |
|
| ۷.۳ | `--group=slot-mode-frozen` سبز | ✅ | |
|
||||||
| ۷.۴ | `phpstan` بدون خطای جدید | ✅ | ۱۴ = baseline |
|
| ۷.۴ | `phpstan` بدون خطای جدید | ✅ | ۱۴ = baseline |
|
||||||
| ۷.۵ | `npx tsc --noEmit` و تستهای فرانت سبز | ✅ | ۶۳۴ تست |
|
| ۷.۵ | `npx tsc --noEmit` و تستهای فرانت سبز | ✅ | ۶۳۴ تست |
|
||||||
|
|||||||
Reference in New Issue
Block a user