docs: prompt and checklist for the resource-first booking model

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
hamed
2026-08-01 20:13:55 +03:30
co-authored by Claude Opus 5
parent fc6b865c15
commit 4711ba0af7
2 changed files with 540 additions and 0 deletions
@@ -0,0 +1,155 @@
# چک‌لیست تسک ۱۵ — نوبت‌دهی بر پایهٔ منبع
پرامپت: [`.claude/prompt/resource-first-booking-model.md`](../../../../.claude/prompt/resource-first-booking-model.md)
وضعیت‌ها: ✅ انجام شد · 🔄 در حال انجام · ⏳ در صف · ⛔ خارج از محدوده با دلیل · ⚠️ ناقص با دلیل
---
## ۰. قواعد غیرقابل‌مذاکره
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۰.۱ | هیچ تم/پالت/فونت/کتابخانهٔ CSS تازه‌ای ساخته نشد | ⏳ | |
| ۰.۲ | رنگ‌ها فقط از توکن‌های `styles.css` — هیچ hex خام در کد جدید | ⏳ | |
| ۰.۳ | کامپوننت از `components/ui/``<select>` خام صفر | ⏳ | |
| ۰.۴ | دارک‌مود · حالت فشرده · موبایل ۳۹۰px هر سه سالم | ⏳ | با اسکرین‌شات واقعی |
| ۰.۵ | `.card` با `card-pad` و برچسب با `.field-block` | ⏳ | |
| ۰.۶ | دکمهٔ بازگشت در صفحات زیرمجموعه | ⏳ | |
| ۰.۷ | وضعیت لیست در query string با `useUrlState` | ⏳ | |
| ۰.۸ | هیچ صفحه/فیلد/endpointی خارج از سند اضافه نشد | ⏳ | |
| ۰.۹ | هیچ interface/کلاس پایه بدون بیش از یک پیاده‌سازیِ فعلی | ⏳ | |
| ۰.۱۰ | Controller نازک · منطق در Service · کوئری در Repository | ⏳ | |
## ۱. جدول رابطهٔ منبع↔سرویس
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۱.۱ | entity `ResourceServiceOffering` با `TenantOwnedTrait` | ⏳ | |
| ۱.۲ | قید یکتای `(resource_id, service_item_id)` | ⏳ | |
| ۱.۳ | ایندکس `(entity_type, entity_id, service_item_id)` | ⏳ | |
| ۱.۴ | `durationMinutes` و `priceRials` تهی‌پذیر = ارث | ⏳ | |
| ۱.۵ | migration ساخته و اجرا شد | ⏳ | |
| ۱.۶ | تست: ثبت ردیف | ⏳ | |
| ۱.۷ | تست: جفت تکراری → خطای یکتایی | ⏳ | |
| ۱.۸ | تست: جفت محیط از منبع مشتق می‌شود نه از ورودی | ⏳ | |
## ۲. Resolver مدت و قیمت
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۲.۱ | `ResourceServiceResolver` با زنجیرهٔ چهارسطحی | ⏳ | |
| ۲.۲ | `ResolvedServiceSpec` منبعِ هر مقدار را می‌گوید | ⏳ | |
| ۲.۳ | مدت و قیمت **جدا** حل می‌شوند | ⏳ | |
| ۲.۴ | تست سطح ۱ (منبع+گزینه) | ⏳ | |
| ۲.۵ | تست سطح ۲ (منبع+سرویس) | ⏳ | |
| ۲.۶ | تست سطح ۳ (شعبه) | ⏳ | |
| ۲.۷ | تست سطح ۴ (پیش‌فرض آیتم) | ⏳ | |
| ۲.۸ | تست مرزی: مدت از سطح ۱، قیمت از سطح ۳ | ⏳ | |
## ۳. فیلتر کاندیدها بر اساس سرویس
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۳.۱ | `findEligible()` آرگومان `?ServiceItem` گرفت | ⏳ | |
| ۳.۲ | سازگاری عقب‌رو: بدون ردیف = بدون فیلتر | ⏳ | |
| ۳.۳ | `AppointmentPlanBuilder` سرویس را پاس می‌دهد | ⏳ | |
| ۳.۴ | تست: دو منبع، یکی وصل → assignment همان یکی | ⏳ | |
| ۳.۵ | تست: غیرفعال‌کردن ردیف → slots خالی با reason | ⏳ | |
## ۴. منبع و snapshot روی نوبت
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۴.۱ | `Appointment::$resource` تهی‌پذیر | ⏳ | |
| ۴.۲ | `Appointment::$serviceOptionItem` تهی‌پذیر | ⏳ | |
| ۴.۳ | `service_total_minutes` از resolver پر می‌شود | ⏳ | |
| ۴.۴ | `PriceSnapshot` از resolver پر می‌شود | ⏳ | |
| ۴.۵ | `toArray()` منبع و گزینه را برمی‌گرداند | ⏳ | |
| ۴.۶ | migration بدون شکستن نوبت‌های موجود | ⏳ | |
| ۴.۷ | تست: تغییر قیمت سرویس، snapshot قدیمی ثابت | ⏳ | |
## ۵. رزرو با منبع در endpointها
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۵.۱ | `POST /api/v1/appointment` فیلد `resource_uuid` می‌گیرد | ⏳ | |
| ۵.۲ | با منبعِ پزشک، پزشک استنتاج می‌شود | ⏳ | |
| ۵.۳ | `Appointment.doctor` تهی‌پذیر شد (منبع دستگاهی) | ⏳ | |
| ۵.۴ | `GET /api/v1/resource/{uuid}/services` با مقادیر حل‌شده | ⏳ | |
| ۵.۵ | curl: رزرو با `resource_uuid` → ۲۰۱ | ⏳ | |
| ۵.۶ | curl: مسیر قدیمی `doctor_uuid` سالم ماند | ⏳ | |
| ۵.۷ | curl: منبع بی‌ارتباط → ۴۲۲ | ⏳ | |
| ۵.۸ | curl: بدون هیچ‌کدام → ۴۲۲ | ⏳ | |
## ۶. پنل ادمین — تب سرویس‌های منبع
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۶.۱ | تب روی صفحهٔ منبع موجود، بدون صفحهٔ جدید | ⏳ | |
| ۶.۲ | `DataTable` + `StatusBadge` + `ConfirmDialog` | ⏳ | |
| ۶.۳ | مقدار مؤثر به‌صورت placeholder با برچسب منبعش | ⏳ | |
| ۶.۴ | فرم با React Hook Form + Zod، داده با TanStack Query | ⏳ | |
| ۶.۵ | تست: نمایش مقدار مؤثر | ⏳ | |
| ۶.۶ | تست: ذخیرهٔ override | ⏳ | |
| ۶.۷ | تست: پاک‌کردن override → بازگشت به ارث | ⏳ | |
| ۶.۸ | اسکرین‌شات دارک‌مود | ⏳ | |
| ۶.۹ | اسکرین‌شات حالت فشرده | ⏳ | |
| ۶.۱۰ | اسکرین‌شات موبایل ۳۹۰px بدون اسکرول افقی | ⏳ | |
## ۷. دسته‌بندی سراسری با «شامل بودن»
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۷.۱ | `resource_catalog_categories` (m2m منبع↔دسته) | ⏳ | |
| ۷.۲ | `catalog_category_includes` (یال DAG) | ⏳ | |
| ۷.۳ | `CategoryClosureResolver::descendants()` با محافظ دور | ⏳ | |
| ۷.۴ | تعارض انتخاب در `ServiceSelectionValidator` → ۴۲۲ فارسی | ⏳ | |
| ۷.۵ | تقدم منابعِ پوشش‌دهندهٔ دسته در `findEligible` | ⏳ | |
| ۷.۶ | تست: «تمام بدن» → دست/پا | ⏳ | |
| ۷.۷ | تست: بستار گذرا سه‌سطحی | ⏳ | |
| ۷.۸ | تست: یال دوری → ۴۲۲ | ⏳ | |
| ۷.۹ | تست: دستهٔ بی‌یال → آرایهٔ خالی | ⏳ | |
| ۷.۱۰ | curl: «تمام بدن + دست» با هم → ۴۲۲ | ⏳ | |
## ۸. حذف زیرسیستم‌های خارج از مدل
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۸.۱ | `src/Policy/` حذف شد | ⏳ | |
| ۸.۲ | `src/Package/` حذف شد | ⏳ | |
| ۸.۳ | `src/Course/` حذف شد | ⏳ | |
| ۸.۴ | `src/Cancellation/` + `src/Waitlist/` حذف شد | ⏳ | |
| ۸.۵ | `src/Report/` + `src/Shared/Event/` حذف شد | ⏳ | |
| ۸.۶ | قلاب‌ها از `AppointmentPlanBuilder` کنده شد | ⏳ | |
| ۸.۷ | قلاب‌ها از `PricingEngine` کنده شد | ⏳ | |
| ۸.۸ | قلاب‌ها از `BookingController` و `BookingService` کنده شد | ⏳ | |
| ۸.۹ | قلاب‌ها از `ServiceSelectionValidator` کنده شد | ⏳ | |
| ۸.۱۰ | `GlobalTables` و seeder پاک‌سازی شد | ⏳ | |
| ۸.۱۱ | صفحات پنل و مسیرهای `App.tsx` حذف شد | ⏳ | |
| ۸.۱۲ | migration `DROP TABLE` با `down()` واقعی | ⏳ | |
| ۸.۱۳ | `debug:router` صفر مسیر حذف‌شده | ⏳ | |
| ۸.۱۴ | تست‌های دامنه‌های حذف‌شده پاک شد | ⏳ | |
## ۹. مستندات
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۹.۱ | `docs/api/appointment.md``resource_uuid` و پاسخ جدید | ⏳ | |
| ۹.۲ | `docs/api/appointment.md` — بخش‌های حذف‌شده پاک شد | ⏳ | |
| ۹.۳ | `docs/api/clinic.md` — endpoint سرویس‌های منبع | ⏳ | |
| ۹.۴ | سند معماری مدل منبع‌محور | ⏳ | |
| ۹.۵ | چک‌لیست تسک‌های ۹ تا ۱۴ با وضعیت «حذف‌شده» | ⏳ | |
| ۹.۶ | `TEST_USERS.md` به‌روز شد | ⏳ | |
## ۱۰. تأیید نهایی
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۱۰.۱ | `ddev exec php bin/phpunit` کامل سبز | ⏳ | |
| ۱۰.۲ | `--group=slot-mode-frozen` سبز | ⏳ | خط قرمز |
| ۱۰.۳ | `phpstan` روی baseline ۱۴ خطا | ⏳ | |
| ۱۰.۴ | `npx tsc --noEmit` بدون خطا | ⏳ | |
| ۱۰.۵ | `npx vitest run assets/admin` سبز | ⏳ | |
| ۱۰.۶ | `app:seed-scenarios --reset -n` بدون خطا | ⏳ | |
| ۱۰.۷ | کامیت + `graphify update` + کامیت گراف | ⏳ | |