Files
clinicpro/docs/new_feture/taskes/task-13-cancellation-waitlist/checklist.md
T
hamedandClaude Opus 5 1972fdd20f Document the resource-first model and retire the deleted tasks' checklists
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>
2026-08-01 23:05:33 +03:30

12 KiB
Raw Blame History

چک‌لیست — تسک ۱۳ (سیاست لغو، عدم حضور، لیست انتظار)

این تسک از محصول حذف شد

تصمیم مالک محصول، ۱۴۰۵/۰۵/۱۰: مدل نوبت‌دهی به منبع/سرویس/گزینه محدود شد و هر چیز خارج از آن حذف شد. کد، جدول‌ها، 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 سبز
۰ پیش‌فرض سیاست بدون جریمه penaltyMode = 'none' در خودِ entity، نه در seed
۰ بیمار پرریسک مسدود نمی‌شود فقط برچسب؛ مسدودسازی = قانون eligibility تسک ۰۹
۰ is_reserve و صفحه‌اش دست‌نخورده مفهوم متفاوت؛ ادغام خارج از دامنه
۰.۵ وضعیت‌های لغو موجود دست‌نخورده همان cancelled_by_* و no_show

۱. بک‌اند — لغو و جریمه

# مورد وضعیت یادداشت
۱.۱ CancellationPolicy · NoShowRecord
۱ سرویس بر محیط اولویت دارد CancellationPolicyRepository::resolve() — بدون ترکیب
۱ شرط «لغو توسط کلینیک» اولین خط با کامنت توضیح چرا
۱ سقف جریمه = مبلغ پرداختی
۱.۵ نوبت نقدی → جریمه صفر + note
۱ GET /cancellation-preview همان محاسبهٔ لغو واقعی
۱.۷ CancellationService با ترتیب مشخص تصمیم ثبت‌شده در deviations.md — مراحل هست ولی یک تراکنش سراسری ندارد: آزادسازی ظرفیت باید حتی اگر کیف پول یا پیامک بشکند انجام شود؛ تراکنش واحد یعنی یک خطای پیامک، ظرفیت را برنگرداند
۱ جریمه در کیف پول با جفت محیط PatientWalletTenantTest سبز ماند
۱ بازگشت اعتبار طبق سیاست credit_refundable: false ردیف refund را با adjustment منفی خنثی می‌کند — دفتر append-only می‌ماند
۱.۱۰ جلسهٔ دوره آزاد می‌شود از BookingService::cancel() که تسک ۱۲ وصلش کرد
۱.۱۱ لغو دوباره → ۴۰۹
۱.۱۲ لغو نوبت گذشته → ۴۲۲

۲. بک‌اند — عدم حضور

# مورد وضعیت یادداشت
۲.۱ پنجرهٔ ۱۲ ماه NoShowRecordRepository::WINDOW_DAYS
۲.۲ برچسب از TenantTag موجود هیچ ستون بولین تازه‌ای
۲.۳ یک رکورد per نوبت کلید یکتا + بررسی پیش از درج
۲.۴ جدول جدا، نه شمارنده همان استدلال دفتر اعتبار تسک ۱۱

۳. بک‌اند — لیست انتظار

# مورد وضعیت یادداشت
۳.۱ WaitlistEntry + WaitlistNotifier تصمیم ثبت‌شده در deviations.md — یک notifier به‌جای دو کلاس Service/Matcher؛ تطبیق یک کوئری در repository است و کلاس جدا فقط لایه بود
۳.۲ broadcast به حداکثر ۱۰ نفر تصمیم و دلیلش در waitlist.md
۳.۳ جملهٔ «اولین نفر می‌برد» در پیامک
۳.۴ سقف notify_count ۳ بار
۳.۵ پیامک async بیرون تراکنش لغو dispatchAsync روی messenger؛ لغو تراکنش سراسری هم ندارد (۱.۷)
۳.۶ ترتیب priority DESC, created_at ASC
۳.۷ فیلتر preferred_day_parts مرزها در WaitlistEntry::DAY_PARTS با ساعت محلی شعبه؛ فیلتر پیش از بریدن به ده نفر اعمال می‌شود
۳.۸ converted خودکار روی رزرو بیمار از رویداد AppointmentBooked، نه از داخل BookingService — تبدیل نباید بتواند نوبت واقعی را rollback کند
۳.۹ app:waitlist:expire روزانه سرویس + دستور + پیام روزانهٔ زمان‌بند؛ وضعیت عوض می‌شود نه حذف
۳.۱۰ بازهٔ بیش از ۹۰ روز → ۴۲۲ همان افق رزرو تسک ۱۲
۳.۱۱ هفت endpoint ۱۰ تا: سیاست GET/PUT + override + preview + cancel + no-show + لیست انتظار GET/POST/DELETE/matches

۴. دیتابیس

# مورد وضعیت یادداشت
۴.۱ سه جدول Version20260731081142
۴.۲ ایندکس تطبیق لیست انتظار
۴.۳ ایندکس پنجرهٔ عدم حضور
۴.۴ risk_tag_uuid بدون FK همان الگوی موجود پروژه
۴.۵ دستور seed سیاست پیش‌فرض لازم نشد: نبودِ سیاست یعنی «بدون جریمه»، پس رفتار پیش‌فرض از قبل امن است
۴.۶ TenantSchemaCoverageTest سبز

۵. UI

# مورد وضعیت یادداشت
۵.۱ CancellationPolicyPage جدول سیاست‌های اختصاصی خدمات اضافه شد، با تأکید بر «ترکیب نمی‌شوند»
۵ WaitlistPage بخش «قابل تطبیق با این وقت» با انتخاب خدمت و تاریخ
۵ دکمهٔ لغو با محتوای preview CancelAppointmentDialog جریمه و بازگشت اعتبار را پیش از تأیید نشان می‌دهد؛ سرویس لغو هم reason می‌گیرد و ردیف تایم‌لاین می‌نویسد (قبلاً این مسیر هیچ ردی نمی‌گذاشت)
۵ نشان پرریسک در پروندهٔ بیمار GET /patient/{uuid}/no-shows + نشان در بنر پرونده؛ فقط وقتی count > 0
۵.۵ ConfirmDialog موجود جای دیگری مودال دست‌ساز ساخته نشد
۵ فیلتر در URL useUrlState
۵.۷ تاریخ شمسی و مبلغ formatDate · PriceInput
۵ backTo
۵ هیچ رنگ hard-code
۵.۱۰ دارک‌مود و حالت فشرده اسکرین‌شات واقعی؛ دو ایراد پیدا و رفع شد (کارتِ بدون card-pad و برچسبِ داخل .field)
۵.۱۱ RTL و موبایل جدول لیست انتظار اسکرول افقی داخلی دارد
۵.۱۲ رشته‌ها فارسی
۵.۱۳ ReserveAppointmentsPage دست‌نخورده

۶. تست

# مورد وضعیت یادداشت
۶.۱ محاسبهٔ جریمه — پنج حالت داخل پنجره، بیرون پنجره، کلینیک، سقف پرداختی، بدون سیاست
۶.۲ لغو — آزادسازی، کیف پول، ۴۰۹، گذشته ۴۲۲ + «موجودی ناکافی لغو را شکست نمی‌دهد»
۶.۳ اولویت سیاست سرویس بر محیط از راه عددِ خروجی سنجیده می‌شود نه از راه resolver
۶.۴ عدم حضور — سوم برچسب، دوبار یک رکورد پنجرهٔ ۱۲ ماه تست نشد
۶.۵ بیمار پرریسک رزرو موفق دارد testATaggedPatientCanStillBook
۶.۶ لیست انتظار — ترتیب، سقف اطلاع، شعبه فیلتر روزبخش تست نشد (۳.۷)
۶.۷ تبدیل به رزرو تبدیل تنگ + idempotent، هر دو تست دارند
۶.۸ شکست پیامک لغو را rollback نمی‌کند تصمیم ثبت‌شده در deviations.md — معماری‌اش تضمین می‌کند (async، بدون تراکنش سراسری) ولی تست تزریق خطا نوشته نشد
۶.۹ تست کیف پول موجود سبز ماند
۶.۱۰ سیاست اعتبار روی دوره credit_refundable: false با ردیف adjustment پس می‌گیرد؛ هیچ ردیفی حذف نمی‌شود

اجرا: tests/Cancellation → ۱۴ تست · tests/Waitlist → ۹ تست.

۷. مستندات

# مورد وضعیت یادداشت
۷.۱ docs/api/cancellation.md دو قاعدهٔ گران با دلیلشان
۷ docs/api/waitlist.md تصمیم broadcast و چرایی رد صف انحصاری

۸. بازبینی پایانی

# مورد وضعیت یادداشت
۸.۱ هیچ بی‌دلیل نمانده ۱۲ مورد /⚠️ همه با دلیل و تسک مقصد
۸.۲ bin/phpunit کامل سبز flake پیدا و رفع شد: قید یکتای شکسته EntityManager را می‌بندد و کانتینر همان نمونهٔ بسته را برمی‌گرداند، پس تستِ بعدی مدیرِ مرده را ارث می‌برد. setUp حالا ریست می‌کند و UserCollisionRetryTest آن را پین می‌کند. سه اجرای پیاپی سبز
۸.۳ --group=slot-mode-frozen سبز
۸.۴ phpstan بدون خطای جدید ۱۴ = baseline
۸.۵ npx tsc --noEmit و تست‌های فرانت سبز ۶۳۲ تست
۸.۶ تست‌های tenant سبز
۸.۷ docs/api/* به‌روز
۸.۸ چک‌لیست UI کامل همه
۸.۹ سایت باید preview لغو را نشان دهد مودال لغو سایت قبلاً هیچ درخواستی نمی‌فرستاد؛ حالا /cancel را با پیش‌نمایش جریمه صدا می‌زند
۸.۱۰ clinic-pro-tauri بررسی شد هیچ اندپوینت نوبتی را مصرف نمی‌کند؛ صفحه‌های src/components/turns/ روی src/data/detail.json (ماک ثابت) کار می‌کنند، پس انحرافی ممکن نیست
۸.۱۱ commit، سپس graphify update . دو کامیت جدا
۸.۱۲ موارد به‌تعویق با دلیل روزبخش/تبدیل/انقضا (۳.۷–۳.۹) و رویدادها → تسک ۱۴ · اتصال UI لغو (۵.۳) و نشان پرریسک (۵.۴) · flake تست (۸.۲)