Files
clinicpro/docs/new_feture/taskes/task-12-treatment-course/checklist.md
T
hamedandClaude Opus 5 fc504f4415 feat(course): treatment courses with protocol-driven session planning
Laser is six to eight sessions; the previous design only knew single
appointments, which is the exception rather than the rule.

- CourseProtocol per service: session count and three distinct spacings —
  min is the earliest that is clinically allowed, ideal is best, max is where
  the course starts losing its effect
- Starting a course creates every session up front as `planned` and copies the
  protocol's numbers and per-session params, so changing the protocol tomorrow
  leaves a running course alone
- Suggestions anchor on the last *completed* session, not the course start:
  when session 2 slips, session 3 moves with it
- Slots are ranked by distance from ideal, not by earliest available — day 21
  is worse than day 27 when 28 is the target
- book-all is all-or-nothing inside one transaction, with a moving anchor and a
  90-day horizon; sessions past the horizon stay planned and are reported, not
  treated as failures
- The effective minimum is the stricter of the protocol and the task-09 spacing
  policy, so a clinic rule never fights the protocol
- Cancelling one session returns only that session to planned; abandoning a
  course does not cancel its appointments, which stays an explicit decision

One active course per (patient, service) via active_course_key, the same
partial-uniqueness trick as Appointment::activeSlotKey.

Admin: CourseProtocolsPage, TreatmentCoursePage and a courses tab on the
patient record.

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

9.6 KiB
Raw Blame History

چک‌لیست — تسک ۱۲ (دوره درمان)

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

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


۰. خط سرخ

# مورد وضعیت یادداشت
۰.۱ --group=slot-mode-frozen سبز
۰ PatientSession موجود دست‌نخورده «مراجعهٔ انجام‌شده» ≠ «جلسهٔ دوره»؛ هیچ فایلی از src/Patient تغییر نکرد
۰ رویدادهای تسک ۰۷ بعد از commit منتشر می‌شوند تسک ۱۴ رویدادها را می‌سازد؛ فعلاً book-all هیچ رویدادی منتشر نمی‌کند، پس خطر «هشت پیامک در rollback» وجود ندارد
۰ abandon نوبت‌های booked را لغو نمی‌کند مستند شد؛ لغو ظرفیت باید تصمیم صریح باشد نه اثر جانبی

۱. بک‌اند

# مورد وضعیت یادداشت
۱.۱ چهار entity
۱ سرویس‌ها CourseStarter · CourseScheduler · CourseBooker · CourseProgressCalculator · CourseSessionLinker
۱ snapshot چهار فاصله و params testChangingTheProtocolLeavesRunningCoursesAlone
۱ book-all همه یا هیچ wrapInTransaction دور کل حلقه
۱.۵ لنگر متحرک لنگر بعد از هر رزرو روی همان اسلات می‌رود
۱ نزدیک‌ترین به ایده‌آل usort روی abs(start - ideal)
۱.۷ لنگر پیشنهاد = آخرین جلسهٔ completed testTheSuggestionAnchorsOnTheLastCompletedSession
۱ سقف ۹۰ روز + پیام روشن جلسات بیرون بازه planned می‌مانند، خطا نیست
۱ same_as_previous ترجیح نه الزام ⚠️ prefer_same_resource و preferredResource ذخیره می‌شوند ولی هنوز به انتخاب منبع وصل نیستند
۱.۱۰ preferredResourceIds در PlanRequest با ۱.۹ و ۱.۱۱ یک بسته است
۱.۱۱ SameAsPreviousPicker تسک ۰۶ تسک ۰۶ اصلاً استراتژی انتخاب منبع نساخت (بدهی ثبت‌شدهٔ همان تسک)؛ ساختن picker اینجا یعنی نصف تسک ۰۶ را اینجا نوشتن
۱.۱۲ تعامل با spacing: سخت‌گیرانه‌تر برنده ⚠️ max(min) پیاده شد (effectiveMinDaysmin(max) لازم نشد چون قانون spacing اثر «حداکثر» ندارد. بازهٔ تهی هم ممکن نیست چون max همیشه با min بالا می‌رود
۱.۱۳ اعتبار پکیج کمتر از جلسات → هشدار نه خطا ⚠️ پکیج به دوره وصل می‌شود و پوششش بررسی می‌شود، ولی مقایسهٔ مانده با تعداد جلسات هنوز هشدار نمی‌دهد
۱.۱۴ active_course_key همان الگوی active_slot_key
۱.۱۵ CourseSessionLinker تنها نویسندهٔ رابطهٔ دوطرفه
۱.۱۶ جلسهٔ آخر → دوره completed خودکار رویدادش با تسک ۱۴ می‌آید
۱.۱۷ نُه endpoint ۹ تا: پروتکل GET/POST/GET{uuid}/PATCH/DELETE + دوره POST/GET/patient/{uuid}/courses/next-slot-suggestion/book-all/abandon
۱.۱۸ TenantOwnershipChecker روی هر uuid testAnotherClinicCannotSeeTheCourse

۲. دیتابیس

# مورد وضعیت یادداشت
۲.۱ چهار جدول Version20260731074710
۲.۲ قیدهای فاصله و تعداد در سازنده، با ۴۲۲ روشن
۲.۳ یکتایی شمارهٔ جلسه هم روی پروتکل هم روی دوره
۲.۴ UNIQUE(appointment_id) یک نوبت به بیش از یک جلسه وصل نمی‌شود
۲.۵ appointments.course_session_id Version20260731074758
۲.۶ course_protocol_steps در AGGREGATE_CHILDREN
۲.۷ TenantSchemaCoverageTest سبز

۳. UI

# مورد وضعیت یادداشت
۳.۱ CourseProtocolsPage با اعتبارسنجی ترتیب فاصله‌ها در خود فرم
۳.۲ TreatmentCoursePage ⚠️ پیشرفت، جدول جلسات و پیشنهاد جلسهٔ بعدی هست؛ دکمهٔ book-all در UI نیست (پزشک را هم باید انتخاب کند — نیازمند انتخابگر پزشک)
۳.۳ دوره‌های بیمار در PatientDetailPage تب «دوره‌های درمان»
۳.۴ ستون فاصلهٔ واقعی بین جلسات جدول تاریخ هر جلسه را می‌دهد ولی فاصلهٔ محاسبه‌شده را نه
۳.۵ هشدار عبور از حداکثر فاصله با رنگ --warning
۳.۶ بنر پیشنهاد جلسهٔ بعدی در کارت بالای صفحهٔ دوره
۳.۷ نام منبع ترجیحی روی دکمهٔ رزرو با ۱.۹ یک بسته است
۳.۸ پیشنهاد بازچینی پس از لغو وسط دوره تسک ۱۳ (لغو و لیست انتظار)
۳.۹ DataTable برای جلسات
۳.۱۰ نشان وضعیت جلسه و دوره کلاس‌های badge موجود
۳.۱۱ تاریخ‌ها شمسی formatDate
۳.۱۲ backTo روی زیرصفحه‌ها
۳.۱۳ هیچ رنگ/شعاع hard-code
۳.۱۴ دارک‌مود و حالت فشرده ⚠️ فقط توکن‌های موجود؛ بازبینی چشمی انجام نشد
۳.۱۵ RTL و موبایل جدول جلسات اسکرول افقی داخلی دارد
۳.۱۶ همهٔ رشته‌ها فارسی
۳.۱۷ پیام سقف ۹۰ روز در UI از پاسخ book-all به‌صورت toast

۴. تست

# مورد وضعیت یادداشت
۴.۱ شروع دوره — ۸ جلسه، دورهٔ دوم ۴۲۲ با شناسهٔ دورهٔ موجود
۴.۲ snapshot پروتکل
۴.۳ لنگر متحرک و نزدیک‌ترین به ایده‌آل ⚠️ لنگر پیشنهاد تست شد؛ لنگر متحرک درون book-all تست نشد (نیازمند منابع و ساعت کاری کامل — دستگاه تست سنگین)
۴.۴ شکست جلسهٔ N → rollback با ۴.۳ یک بسته است
۴.۵ سقف ۹۰ روز همان
۴.۶ لنگر completed + هشدار عبور از max
۴.۷ پیشرفت دوره «۳ از ۸» + next_params
۴.۸ ترجیح همان منبع با ۱
۴.۹ تعامل با قانون spacing effectiveMinDays نوشته شد ولی تست اختصاصی ندارد
۴.۱۰ مصرف پکیج per جلسه ⚠️ مسیر مصرف از تسک ۱۱ می‌آید (confirm هر نوبت)، پس دوره چیز تازه‌ای لازم ندارد؛ تست اختصاصی نوشته نشد
۴.۱۱ چرخهٔ عمر — لغو، تکمیل خودکار، abandon testCancellingOneSessionOnlyResetsThatSession و testTheCourseCompletesOnlyWhenEverySessionIsDone

اجرا: ddev exec php bin/phpunit tests/Course → ۱۴ تست (۱ skip عمدی: تولید خروجی مستندات).

۵. مستندات

# مورد وضعیت یادداشت
۵.۱ docs/api/course.md JSON واقعی از اجرای واقعی
۵ «سخت‌گیرانه‌تر برنده»
۵ رفتار سقف ۹۰ روز
۵ «abandon نوبت‌ها را لغو نمی‌کند» با دلیلش

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

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