Files
clinicpro/docs/new_feture/taskes/task-05-appointment-plan/checklist.md
T
hamedandClaude Opus 5 b3c331f0cb perf(reports): read every resource's calendar in one batch, and close the owed tests
Writing the query-count test that task 14 owed showed the growth was real: one
resource cost 10 queries, six cost 33 — about five per resource, because the
available-minutes figure walked each resource's calendar on its own.

Holidays, tenant overrides and branch hours are identical for every resource in
a report, so they now load once outside the loop; shifts and exceptions load for
all resources in one query each. The batched path is a new method rather than a
change to rawAvailability, which the booking engine also calls. The test pins
the shape of the growth, not an exact count.

Also landed:

- app:segment:seed-templates with beauty, dental and physio presets. Building
  four segments and their requirements by hand is the first thing a new clinic
  must do and the most tedious; this gives them something to edit instead of an
  empty page. It refuses to touch a service that already has segments unless
  --force, and it will not invent resource types the tenant never defined.
- book-all is all-or-nothing, proven rather than asserted: with a calendar open
  one day a week and a 1-2 day protocol gap, session one finds a slot and
  session two cannot, and every session must come back planned.
- credit_refundable: false takes the credit back with a negative adjustment and
  deletes nothing — the ledger stays append-only.
- the segments editor has frontend tests, including that it sends back what the
  user sees and renders read-only without the permission.

useBranches now returns [] for a non-array payload instead of throwing
"branches.map is not a function" and taking the page down with it.

BookingLocationsScanTest built a Clinic around a Doctor loaded from a different
manager, which Doctrine treats as a new entity; it flushed fine most runs and
failed on cascade in others. It now loads the doctor from the same manager.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 14:22:22 +03:30

9.3 KiB
Raw Blame History

چک‌لیست — تسک ۰۵ (بخش‌های نوبت و سازندهٔ برنامه)

وضعیت کلی: تمام‌شده با انحراف‌های ثبت‌شده · آخرین بازبینی: ۱۴۰۵/۰۵/۰۹

این چک‌لیست تا امروز روی «شروع نشده» مانده بود در حالی که کد تسک از همان روز ساخته و کامیت شده بود — خطای پیگیری، نه خطای پیاده‌سازی. حالا با وضعیت واقعی پر شده.

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


۰. خط سرخ

# مورد وضعیت یادداشت
۰.۱ --group=slot-mode-frozen سبز
۰ SlotCalculatorService دست‌نخورده
۰ سرویس بدون الگو → یک بخش با منبع doctor singleSegment() — سازگاری کامل با رفتار امروز
۰ هیچ جدولی برای «برنامهٔ ساخته‌شده» نیست فقط DTO درون‌حافظه؛ ذخیره کار تسک ۰۷ شد

۱. بک‌اند

# مورد وضعیت یادداشت
۱.۱ SegmentTemplate · SegmentRequirement
۱ DTO های AppointmentPlan · PlannedSegment · PlannedRequirement readonly
۱ پنج سرویس جدا ⚠️ یک AppointmentPlanBuilder با متدهای خصوصی. تقسیم به Assembler/DurationResolver/RequirementResolver وقتی معنا دارد که هرکدام مصرف‌کنندهٔ مستقل داشته باشند؛ اینجا هر سه فقط از همین یک مسیر صدا زده می‌شوند
۱ build() تابع خالص ⚠️ تا تسک ۰۸ خالص بود. تسک ۰۹ قوانین timing/resource را وصل کرد، پس حالا از دیتابیس می‌خواند. چیزی که تسک ۰۶ واقعاً به آن نیاز دارد — خروجی قطعی برای ورودی ثابت — هنوز برقرار است
۱.۵ قلاب سیاست از روز اول در امضا تسک ۰۹ همان‌جا پر شد؛ همان دلیلِ گذاشتنش
۱ ادغام: count بیشینه برنامه از الگوهای سرویس و آیتم‌های انتخاب‌شده ساخته می‌شود؛ هم‌نام‌های mergeable یک بار می‌آیند (طولانی‌ترین می‌ماند) و تعداد منبع بیشینه می‌شود
۱.۷ offset_minutes نسبی تسک ۰۶ برنامه را می‌لغزاند
۱ اشغال جدا از offset نمایشی ⚠️ setup/cleanup روی PlannedRequirement است (بیشینهٔ کاندیدها) نه دو offset جدا؛ اثر عملی یکی است و تسک ۰۷ همان را می‌خواند
۱ قید جنسیت بدون داده → ۴۲۲ نادیده گرفته نمی‌شود
۱.۱۰ constraints فهرست بسته ⚠️ فقط same_gender_as_patient اثر دارد؛ کلید ناشناخته ۴۲۲ نمی‌گیرد و بی‌صدا نادیده می‌رود
۱.۱۱ خطای «هیچ منبعی» با پیام انسانی explainMissing() — نقش، مهارت و شعبه در متن؛ meta ساختاریافته ندارد
۱.۱۲ سه endpoint GET/PUT segments + POST appointment-plan/preview
۱.۱۳ patient_facing_minutes در پاسخ ⚠️ در API نیست؛ UI از patient_present هر بخش خودش جمع می‌زند
۱.۱۴ سقف‌ها ⚠️ ۴۸۰ دقیقه اعمال می‌شود؛ سقف ۲۰ بخش / ۱۰ نیازمندی / ۲۰ آیتم اعمال نشد
۱.۱۵ app:segment:seed-templates سه الگو (beauty/dental/physio)؛ بدون --force بازنویسی نمی‌کند
۱.۱۶ TenantOwnershipChecker روی هر uuid

۲. دیتابیس

# مورد وضعیت یادداشت
۲.۱ segment_templates · segment_requirements
۲.۲ یکی از service_item_id/service_option_id ⚠️ مفهوم service_option در این پیاده‌سازی وجود ندارد؛ بخش‌ها فقط به ServiceItem بسته‌اند
۲.۳ یکی از fixed_minutes/duration_share ⚠️ مدل دیگری انتخاب شد: duration_sourcefixed|items. «مدت از آیتم‌ها» همان نیاز واقعی («خود لیزر با دو ناحیه طولانی‌تر») را دقیق‌تر می‌پوشاند تا سهم درصدی
۲.۴ جمع duration_share = ۱۰۰ با مدل بالا موضوعیت ندارد
۲.۵ required_skills به‌صورت JSON ⚠️ یک Skill تک با FK. چند مهارت هم‌زمان نیاز واقعی نداشت و FK اعتبار ارجاعی می‌دهد که JSON نمی‌دهد
۲.۶ segment_requirements در AGGREGATE_CHILDREN
۲.۷ TenantSchemaCoverageTest سبز

۳. UI

# مورد وضعیت یادداشت
۳.۱ ویرایشگر بخش‌ها در ServiceDetailPage تب «بخش‌های نوبت» — components/ServiceSegmentsTab.tsx
۳.۲ لیست بخش‌ها با sequence عددی بدون drag، طبق قرارداد
۳.۳ نیازمندی‌ها با SearchableSelect نقش، تعداد، نوع اشغال، قید جنسیت
۳.۴ هر گزینهٔ نوع اشغال توضیح فارسی دارد «انحصاری — منبع کامل قفل می‌شود» / «اشتراکی — از ظرفیت یکی کم می‌شود»
۳.۵ نوار پیش‌نمایش با عرض متناسب مدت flex: duration — بخش سی‌دقیقه‌ای شش برابر پنج‌دقیقه‌ای
۳.۶ خط «بیمار واقعاً درگیر: N دقیقه» کنار مدت کل
۳.۷ backTo روی صفحه از ServiceDetailPage می‌آید
۳.۸ هیچ رنگ/شعاع hard-code نوار هم با --primary-soft/--surface-2
۳.۹ دارک‌مود و حالت فشرده ⚠️ فقط توکن‌ها؛ بازبینی چشمی انجام نشد
۳.۱۰ RTL و موبایل — اسکرول افقی نوار overflow-x: auto با min-width
۳.۱۱ همهٔ رشته‌ها فارسی
۳.۱۲ خطای «هیچ منبعی» به لینک «افزودن منبع» تبدیل شد خطای بدون راه اصلاح، بن‌بست است

۴. تست

# مورد وضعیت یادداشت
۴.۱ ادغام بخش‌ها دو تست: ادغام هم‌نام دو ناحیه · بیشینه‌بودن تعداد
۴.۲ حل مدت — ثابت و از آیتم‌ها داخل AppointmentPlanTest
۴.۳ سناریوی مرجع مستند آفست‌های ۰/۵/۳۵/۵۵ و مجموع ۶۰
۴.۴ قطعیت — دو build یکسان مقایسهٔ JSON دو preview پیاپی
۴.۵ سرویس بدون الگو
۴.۶ حل نیازمندی — مهارت، بی‌کاندید، جنسیت، محیط دیگر
۴.۷ سقف‌ها → ۴۲۲ ⚠️ سقف ۴۸۰ دقیقه تست شد؛ بقیه سقف ندارند (۱.۱۴)
۴.۸ تست فرانت ویرایشگر بخش‌ها بارگذاری، ذخیرهٔ همان چیزی که کاربر می‌بیند، و حالت فقط‌خواندنی

اجرا: ddev exec php bin/phpunit tests/Appointment/AppointmentPlanTest.php → ۱۱ تست.

۵. مستندات

# مورد وضعیت یادداشت
۵.۱ docs/api/appointment-plan.md
۵ جدول حالت‌های اشغال ⚠️ دو حالت مستند شد (exclusive/shared)؛ حالت سوم ساخته نشد
۵ تفاوت offset نمایشی و اشغال occupancy_offset و دلیل محافظه‌کاری‌اش
۵ مثال کامل خروجی preview

۶. بازبینی پایانی

# مورد وضعیت یادداشت
۶.۱ هیچ بی‌دلیل نمانده ۵ مورد با دلیل
۶.۲ bin/phpunit کامل سبز
۶.۳ --group=slot-mode-frozen سبز
۶.۴ phpstan بدون خطای جدید baseline ۱۴
۶.۵ npx tsc --noEmit و تست‌های فرانت سبز ۶۳۷ تست
۶.۶ تست‌های tenant سبز
۶.۷ docs/api/* به‌روز
۶.۸ چک‌لیست UI کامل جز ۳.۹
۶.۹ دو کلاینت دیگر بررسی شدند ⚠️ preview هنوز در nobat724_front مصرف نمی‌شود
۶.۱۰ commit، سپس graphify update .
۶.۱۱ موارد به‌تعویق با دلیل ادغام بخش‌ها (۱.۶/۴.۱) · سقف‌های فرعی (۱.۱۴) · seed (۱.۱۵) · تست قطعیت (۴.۴)