Files
clinicpro/docs/new_feture/taskes/task-15-resource-first-model/checklist.md
T
hamedandClaude Opus 5 8280aa7578 Remove the policy, package, course, cancellation and event subsystems
The product owner scoped the booking model down to resources, services and
service options; everything else goes. Deleted, with their tables, tests, panel
pages and API routes:

  src/Policy      27 files   policy engine, simulation, templates
  src/Package     13 files   packages and the credit ledger
  src/Course      14 files   treatment protocols and courses
  src/Cancellation + src/Waitlist  19 files  penalties, no-shows, waitlist
  src/Report + src/Shared/Event    events outbox and the two reports

The surviving code had hooks into all of them, so this is not only deletion:

- AppointmentPlanBuilder loses the timing and resource policy passes, and the
  requirement-from-policy builder that had no other caller (449 → 379 lines)
- PricingEngine loses policy discounts and package coverage; PriceQuote loses
  its package fields and quote() its patient argument, which existed only to
  find a usable package
- BookingService no longer consumes credit, unlinks course sessions or emits
  events; HoldService and ResourceBlockController stop emitting too
- ServiceSelectionValidator keeps groups and relations, drops the policy layer
- the appointment loses its course_session link

Cancelling an appointment still works and still records who and why — it moves
through PATCH /api/v1/appointment/{uuid}/status. What it no longer does is
compute a penalty, so the panel dialog is a plain confirm now. That is the
visible cost of this change and it is intended, not an oversight.

The drop migration uses DROP TABLE IF EXISTS with foreign-key checks off: a
half-applied earlier run left some tables already gone, and a migration that
only works from a pristine schema is a trap on any environment that was
interrupted. messenger_messages is deliberately left alone — it is Symfony's,
not ours.

Suite green at 1258 tests, slot-mode-frozen green, phpstan back to its 14-error
baseline after removing two now-unused members it caught, tsc clean, and
app:seed-scenarios still builds all three environments.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 20:51:41 +03:30

9.8 KiB
Raw Blame History

چک‌لیست تسک ۱۵ — نوبت‌دهی بر پایهٔ منبع

پرامپت: .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/Policy/ (۲۷ فایل) حذف شد
۸.۲ src/Package/ حذف شد src/Package/ (۱۳ فایل) حذف شد
۸.۳ src/Course/ حذف شد src/Course/ (۱۴ فایل) حذف شد
۸.۴ src/Cancellation/ + src/Waitlist/ حذف شد src/Cancellation/ + src/Waitlist/ (۱۹ فایل) حذف شد
۸.۵ src/Report/ + src/Shared/Event/ حذف شد src/Report/ + src/Shared/Event/ حذف شد
۸.۶ قلاب‌ها از AppointmentPlanBuilder کنده شد applyTimingPolicies/applyResourcePolicies/requirementForRole برداشته شد — ۴۴۹ → ۳۷۹ خط
۸.۷ قلاب‌ها از PricingEngine کنده شد تخفیف سیاستی و پوشش پکیج از PricingEngine و PriceQuote رفت
۸.۸ قلاب‌ها از BookingController و BookingService کنده شد BookingPolicyGuard، PackageConsumption، CreditLedger، CourseSessionLinker و رویدادها کنده شد
۸.۹ قلاب‌ها از ServiceSelectionValidator کنده شد policyErrors() از validator رفت؛ گروه و رابطه دست‌نخورده ماند
۸.۱۰ GlobalTables و seeder پاک‌سازی شد GlobalTables، سیدر، Schedule.php و messenger.yaml پاک شد
۸.۱۱ صفحات پنل و مسیرهای App.tsx حذف شد ۱۱ صفحهٔ پنل + مسیرها + منوی تنظیمات + هوک‌ها + تایپ‌ها حذف شد
۸.۱۲ migration DROP TABLE با down() واقعی Version20260801170043 — ۱۵ جدول با IF EXISTS، ستون course_session_id نوبت
۸.۱۳ debug:router صفر مسیر حذف‌شده ۵ مسیر باقی‌مانده مربوط به «پکیج انبار» و «گزارش بیمه» است، نه دامنه‌های حذف‌شده
۸.۱۴ تست‌های دامنه‌های حذف‌شده پاک شد tests/{Policy,Package,Course,Cancellation,Waitlist,Report} + assertionهای رویداد در دو تست

۹. مستندات

# مورد وضعیت یادداشت
۹.۱ docs/api/appointment.mdresource_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 + کامیت گراف