docs/architecture/resource-first-model.md describes the shape: the three entities, why an option is a ServiceItem rather than a fourth table, the four-level resolution chain, the two conditions on the eligibility filter and what each of them prevented, and why containment is a graph beside the display tree rather than the tree itself. docs/api/resource.md gains both offering endpoints with the response captured from a real call, including a row where the price comes from the branch and one where it comes from the resource — the two cases the *_source fields exist for. docs/api/appointment.md documents resource_uuid, the doctor inference, and the nullable resource/service_option in the response. The checklists for tasks 9 to 14 keep their rows but open with a banner saying the task was removed, when, by whose decision, and which commit to revert. They are history now; deleting them would erase the record of work that shipped and was then withdrawn. Verified end to end: 1304 tests, slot-mode-frozen green, phpstan at 14, tsc clean, 648 panel tests, and app:seed-scenarios --reset builds all three environments. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
11 KiB
11 KiB
چکلیست — تسک ۱۲ (دوره درمان)
⛔ این تسک از محصول حذف شد
تصمیم مالک محصول، ۱۴۰۵/۰۵/۱۰: مدل نوبتدهی به منبع/سرویس/گزینه محدود شد و هر چیز خارج از آن حذف شد. کد، جدولها، endpointها، تستها و صفحات پنل این تسک در کامیت «Remove the policy, package, course, cancellation and event subsystems» برداشته شدند.
ریسکش پیش از اجرا دو بار مطرح و دو بار تأیید شد. ردیفهای زیر تاریخچهاند، نه کار جاری؛ برای برگرداندن به همان کامیت رجوع کنید.
مدل جایگزین:
docs/architecture/resource-first-model.mdو چکلیست تسک ۱۵.
وضعیت کلی: ✅ تمامشده با انحرافهای ثبتشده · آخرین بازبینی: ۱۴۰۵/۰۵/۰۹
قواعد: _shared/definition-of-done.md · red-lines.md · ui-conventions.md
۰. خط سرخ
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۰.۱ | --group=slot-mode-frozen سبز |
✅ | |
| ۰.۲ | PatientSession موجود دستنخورده |
✅ | «مراجعهٔ انجامشده» ≠ «جلسهٔ دوره»؛ هیچ فایلی از src/Patient تغییر نکرد |
| ۰.۳ | رویدادهای تسک ۰۷ بعد از commit منتشر میشوند | ✅ | صندوق خروجی تسک ۱۴ همین را تضمین میکند: record() فلاش نمیکند، پس rollbackِ book-all رویدادی جا نمیگذارد |
| ۰.۴ | abandon نوبتهای booked را لغو نمیکند |
✅ | مستند شد؛ لغو ظرفیت باید تصمیم صریح باشد نه اثر جانبی |
۱. بکاند
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۱.۱ | چهار entity | ✅ | |
| ۱.۲ | سرویسها | ✅ | CourseStarter · CourseScheduler · CourseBooker · CourseProgressCalculator · CourseSessionLinker |
| ۱.۳ | snapshot چهار فاصله و params |
✅ | ⭐ testChangingTheProtocolLeavesRunningCoursesAlone |
| ۱.۴ | book-all همه یا هیچ |
✅ | ⭐⭐ wrapInTransaction دور کل حلقه |
| ۱.۵ | لنگر متحرک | ✅ | ⭐ لنگر بعد از هر رزرو روی همان اسلات میرود |
| ۱.۶ | نزدیکترین به ایدهآل | ✅ | usort روی abs(start - ideal) |
| ۱.۷ | لنگر پیشنهاد = آخرین جلسهٔ completed |
✅ | ⭐ testTheSuggestionAnchorsOnTheLastCompletedSession |
| ۱.۸ | سقف ۹۰ روز + پیام روشن | ✅ | ⭐ جلسات بیرون بازه planned میمانند، خطا نیست |
| ۱.۹ | same_as_previous ترجیح نه الزام |
✅ | ⭐ منبع ترجیحی جلو میآید، بقیه حذف نمیشوند؛ اجبار یعنی بیمار دو هفته منتظر بماند |
| ۱.۱۰ | preferredResourceIds حمل میشود |
✅ | POST /appointment-availability فیلد course_uuid میگیرد و preferred_resource دوره را به موتور میدهد |
| ۱.۱۱ | SameAsPreviousPicker تسک ۰۶ |
✅ | همراه سه استراتژی دیگر در تسک ۰۶ ساخته شد |
| ۱.۱۲ | تعامل با spacing: سختگیرانهتر برنده |
✅ | تصمیم ثبتشده در deviations.md — max(min) پیاده شد (effectiveMinDays)؛ min(max) لازم نشد چون قانون spacing اثر «حداکثر» ندارد. بازهٔ تهی هم ممکن نیست چون max همیشه با min بالا میرود |
| ۱.۱۳ | اعتبار پکیج کمتر از جلسات → هشدار نه خطا | ✅ | package_balance و package_shortfall در پاسخ، هشدار در صفحهٔ دوره. یادداشت قبلی: مقایسهٔ مانده با تعداد جلسات هنوز هشدار نمیدهد |
| ۱.۱۴ | 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 |
✅ | دکمهٔ «رزرو همهٔ جلسات» با انتخابگر پزشک اضافه شد. یادداشت قبلی: (پزشک را هم باید انتخاب کند — نیازمند انتخابگر پزشک) |
| ۳.۳ | دورههای بیمار در PatientDetailPage |
✅ | تب «دورههای درمان» |
| ۳.۴ | ستون فاصلهٔ واقعی بین جلسات | ✅ | ⭐ فاصلهٔ واقعی با جلسهٔ قبلی؛ عبور از حداکثر پروتکل با رنگ هشدار |
| ۳.۵ | هشدار عبور از حداکثر فاصله | ✅ | با رنگ --warning |
| ۳.۶ | بنر پیشنهاد جلسهٔ بعدی | ✅ | در کارت بالای صفحهٔ دوره |
| ۳.۷ | نام منبع ترجیحی روی دکمهٔ رزرو | ✅ | preferred_resource_name در پاسخ دوره؛ متن صریح میگوید ترجیح است نه الزام |
| ۳.۸ | پیشنهاد بازچینی پس از لغو وسط دوره | ✅ | ⭐ بنر «N روز از آخرین جلسه گذشته» از خودِ دوره حساب میشود، پس به انتخاب شعبه وابسته نیست |
| ۳.۹ | DataTable برای جلسات |
✅ | |
| ۳.۱۰ | نشان وضعیت جلسه و دوره | ✅ | کلاسهای badge موجود |
| ۳.۱۱ | تاریخها شمسی | ✅ | formatDate |
| ۳.۱۲ | backTo روی زیرصفحهها |
✅ | |
| ۳.۱۳ | هیچ رنگ/شعاع hard-code | ✅ | |
| ۳.۱۴ | دارکمود و حالت فشرده | ✅ | اسکرینشات واقعی |
| ۳.۱۵ | RTL و موبایل | ✅ | جدول جلسات اسکرول افقی داخلی دارد |
| ۳.۱۶ | همهٔ رشتهها فارسی | ✅ | |
| ۳.۱۷ | پیام سقف ۹۰ روز در UI | ✅ | از پاسخ book-all بهصورت toast |
۴. تست
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۴.۱ | شروع دوره — ۸ جلسه، دورهٔ دوم ۴۲۲ با شناسهٔ دورهٔ موجود | ✅ | |
| ۴.۲ | snapshot پروتکل | ✅ | ⭐ |
| ۴.۳ | لنگر متحرک و نزدیکترین به ایدهآل | ✅ | تصمیم ثبتشده در deviations.md — لنگر پیشنهاد، افق، و مسیر شکستِ book-all تست دارند؛ مسیر موفقِ چندجلسهای هنوز نه |
| ۴.۴ | شکست جلسهٔ N → rollback | ✅ | ⭐ تقویم فقط یکروزه: جلسهٔ اول وقت پیدا میکند، دومی نه، و هیچ جلسهای رزرو نمیماند |
| ۴.۵ | سقف ۹۰ روز | ✅ | testSessionsBeyondTheHorizonAreSkippedNotFailed — جلسهٔ بیرون افق رد میشود، دوره دستنخورده میماند |
| ۴.۶ | لنگر completed + هشدار عبور از max |
✅ | ⭐ |
| ۴.۷ | پیشرفت دوره | ✅ | «۳ از ۸» + next_params |
| ۴.۸ | ترجیح همان منبع | ✅ | ResourcePickerTest — «جلو میآید و هیچ کاندیدی حذف نمیشود» |
| ۴.۹ | تعامل با قانون spacing |
✅ | ⭐ testTheStricterOfProtocolAndSpacingPolicyWins — پروتکل ۷ روز، قانون ۲۱ روز، مؤثر ۲۱ |
| ۴.۱۰ | مصرف پکیج per جلسه | ✅ | مسیر مصرف از تسک ۱۱ میآید و credit_refundable روی دوره هم تست شد. یادداشت قبلی: تست اختصاصی نوشته نشد |
| ۴.۱۱ | چرخهٔ عمر — لغو، تکمیل خودکار، 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 کامل | ✅ | همه؛ بازبینی چشمی دارکمود/فشرده انجام شد |
| ۶.۹ | دو کلاینت دیگر بررسی شدند | ✅ | با graphify بررسی شدند؛ هیچکدام دوره را مصرف نمیکنند. یادداشت قبلی: نمایش «نوبت جزو دوره» در nobat724_front دیده نشد |
| ۶.۱۰ | commit، سپس graphify update . |
✅ | دو کامیت جدا |
| ۶.۱۱ | موارد بهتعویق با دلیل | ✅ | ترجیح منبع (۱.۹/۱.۱۰/۱.۱۱/۳.۷/۴.۸) وابسته به بدهی تسک ۰۶ · بازچینی پس از لغو (۳.۸) تسک ۱۳ · رویدادها (۰.۳/۱.۱۶) تسک ۱۴ |