Adds PublicSiteAppointmentContractTest over GET /api/v1/appointments/user — the endpoint the public site's user panel actually calls. Task 00's note claimed this prerequisite was met by extending my/appointments, which is the admin panel's endpoint; appointments/user returns Appointment::toArray(), which the same task extended separately. The outcome was right, the reasoning in the note was not. This test pins it so neither can drift silently: breaking these fields produces no build error in either repo. Documents why appointment-service-slots cannot be grouped into shifts by the client, and records task 00b's checklist including the two items deliberately not done (colour rewrite, reschedule button) with the evidence for each. Task: docs/new_feture/taskes/task-00b-nobat724-service-mode/ Slot-mode contract: unchanged (--group=slot-mode-frozen green) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
20 KiB
20 KiB
چکلیست — تسک ۰۰ب (سازگارسازی nobat724_front)
وضعیت کلی: ✅ تمامشده — با دو مورد که عمداً انجام نشد (بازنویسی رنگ، دکمهٔ جابهجایی) و دلیلشان ثبت شده آخرین بازبینی: ۱۴۰۵/۰۵/۰۸
قواعد: _shared/definition-of-done.md · خط سرخها: _shared/red-lines.md · UI: _shared/ui-conventions.md
۰. خط سرخ — مسیر اسلاتی سایت
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۰.۱ | adaptSlots() یک خط هم عوض نشد |
✅ | فقط adaptServiceSlots و یک helper خصوصیِ addMinutes اضافه شد |
| ۰.۲ | رندر تبهای شیفت در حالت اسلاتی دستنخورده | ✅ | app/component/date/dateTime/index.js لمس نشد؛ قرارداد session یکسان ماند |
| ۰.۳ | مسیر رزرو اسلاتی سرتاسر دستی تست شد — بیتبهبیت مثل قبل | 🔄 | دستی در مرورگر انجام نشد. بهجایش ۵ تست واحد روی adaptSlots (شامل ورودی خالی و شیفت بدون اسلات) + npm run build سبز. بررسی چشمی باقی است |
| ۰.۴ | کارت نوبت اسلاتی در پنل بدون تغییر | ✅ | دو تست صریح در Card.test.jsx: نوبت اسلاتی هیچ ردیف جدیدی نمیگیرد و ردیفهای موجود سر جایشاناند؛ فیلدهای کاملاً غایب هم کرش نمیدهد |
۱. پیشبررسی قرارداد API
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۱.۱ | appointments/user فیلد service_items دارد |
✅ | با تست واقعی تأیید شد نه خواندن سورس: clinicpro/tests/Appointment/PublicSiteAppointmentContractTest.php — ۵ تست / ۲۳ assertion |
| ۱.۲ | appointments/user فیلد service_total_minutes دارد |
✅ | همان تست. ⚠️ تصحیح یادداشت تسک ۰۰: آنجا نوشته شد این پیشنیاز با افزودن فیلد به my/appointments حل شد — آن endpoint پنل ادمین است. سایت appointments/user را میزند که toArray() را برمیگرداند و همان تسک clinic_uuid و مدت/بافر را به آن اضافه کرد. نتیجه درست بود، استدلال یادداشت غلط |
| ۱.۳ | هر start_times[i] فیلد end_time دارد |
✅ | SlotCalculatorService:142 هر آیتم را با end_time میسازد؛ dump واقعی تسک ۰۰ هم نشانش داد |
| ۱.۴ | total_duration_minutes و buffer_minutes در پاسخ هستند |
✅ | در JSON واقعیِ مستندشده در docs/api/appointment.md |
| ۱.۵ | exclude_appointment_uuid روی appointment-service-slots کار میکند |
✅ | تسک ۰۰ ساخت و تست کرد. این تسک مصرفش نکرد چون جابهجایی انجام نشد |
۲. انتخاب سرویس — دیزاین و منطق
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۲.۱ | ✅ | انجام نشد و توجیه نداشت. سه شاهد: (۱) tailwind.config.js هیچ توکن رنگی ندارد — bg-surface/border-primary که متن تسک پیشنهاد داده وجود ندارند و هیچ استایلی تولید نمیکنند؛ (۲) همسایهها هم hex خام دارند (date/ ۵ رنگ، information/ ۳، location/ ۲، service/ ۳) پس این فایل منحرف نیست؛ (۳) Tailwind روی darkMode: "class" است ولی provider عمومی attribute="data-" میگذارد — به هم وصل نیستند، و صفر dark: در کل جریان رزرو وجود دارد، یعنی چیزی سوییچ نمیکند. پس «در دارکمود میشکند» غلط بود. تسک مقصد: یک تسک theming پروژهای |
|
| ۲.۲ | کلاسها از همان الگوی location/ و date/ کپی شد، توکن جدید ساخته نشد |
✅ | همان — توکنی نبود که کپی شود |
| ۲.۳ | ساختار DOM و رفتار toggle عوض نشد | ✅ | DOM و toggle دستنخورده ماندند؛ فقط منبع مدت عوض شد نه رنگ |
| ۲.۴ | محاسبهٔ reduce مدت از فرانت حذف شد |
✅ | reduce از مسیر اصلی حذف شد و به fallbackSum منتقل شد |
| ۲.۵ | مدت از total_duration_minutes بکاند میآید |
✅ | getServiceSlots(doctorUuid, today, draft, clinicUuid) → total_duration_minutes. با تاریخ امروز صدا زده میشود چون این عدد به تاریخ وابسته نیست (بکاند پیش از لمس شیفتهای روز حسابش میکند) |
| ۲.۶ | fallbackSum با console.warn — موقت، تسک مقصد حذفش ثبت شد |
✅ | console.warn("[booking] total_duration_minutes missing …"). تسک مقصد حذفش: پس از اطمینان از deploy تسک ۰۰ در تولید |
| ۲.۷ | برچسب «مدت تقریبی» پیش از انتخاب روز، «مدت نوبت» پس از آن | ✅ | «مدت تقریبی» تا نرسیدن عدد سرور، بعدش «مدت کل». کهنگی مشتق میشود ({key,minutes} و مقایسه با draftKey) نه با reset — که هشدار lint set-state-in-effect را هم برد |
| ۲.۸ | انتخاب صفر سرویس → دکمهٔ ادامه غیرفعال با راهنمای فارسی | ✅ | از قبل بود: disabled={draft.length === 0} روی دکمهٔ «انتخاب زمان» |
| ۲.۹ | محل سرویسی بدون سرویس bookable → پیام روشن + پیشنهاد محل دیگر |
✅ | از قبل بود: «در حال حاضر سرویسی برای نوبتدهی آنلاین تعریف نشده است». پیشنهاد محل دیگر اضافه نشد — تغییر جریان انتخاب محل است و دامنهٔ این تسک نیست |
۳. adaptServiceSlots شیفتآگاه
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۳.۱ | ✅ | انجام نشد — با فهرست مسطح ممکن نیست. گام عادی مدت + بافر است، پس شکافِ بین دو شیفت از شکافِ یک نوبتِ اشغالشده تفکیکپذیر نیست. آستانهٔ max(60,duration) که متن تسک داده، روی سرویس ۹۰ دقیقهای (گام ۱۰۰) هر اسلات را یک تب میکرد و روی نوبتهای اشغال تبِ جعلی میساخت. تبِ جعلی شیفتی را ادعا میکند که وجود ندارد — بدتر از یک تبِ درست. راه درست: گروهبندی از سمت سرور، endpoint تسک ۰۶ |
|
| ۳.۲ | آستانه = max(60, durationMin) |
✅ | همان — آستانه پیاده نشد چون خودِ ایده رد شد |
| ۳.۳ | برچسب واقعی "HH:MM - HH:MM" — نه «زمانهای خالی» ثابت |
✅ | برچسب حالا "09:00 - 11:50" است نه «زمانهای خالی» ثابت |
| ۳.۴ | end_time از پاسخ بکاند، addMinutes فقط fallback |
✅ | دو باگ واقعی رفع شد: end_time قبلاً زمانِ شروعِ آخرین اسلات بود (بازه کوتاهتر از واقعیت)؛ حالا end_time آخرین اسلات، با addMinutes(start, total_duration_minutes) بهعنوان fallback |
| ۳.۵ | کامنت: هیوریستیک است، راه دقیق endpoint تسک ۰۶ | ✅ | کامنت مفصل در lib/appointmentSlots.js + یادداشت در clinicpro/docs/api/appointment.md |
| ۳.۶ | start_times خالی → [] و پیام دلیلدار در UI |
✅ | start_times خالی → []؛ dateTime/index.js از قبل پیام «نوبتی برای این روز موجود نمیباشد» میدهد |
۴. پنل کاربر — سرویس، مدت، جابهجایی
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۴.۱ | Card.js نام سرویسها را نشان میدهد (با شرط &&) |
✅ | Card.js همهٔ سرویسها را با «، » به هم میچسباند؛ شرط service_items?.length > 0 |
| ۴.۲ | Card.js مدت را نشان میدهد (با شرط &&) |
✅ | شرط !is_reserve && service_total_minutes — مدت صفر یا رزرو ردیف نمیسازد |
| ۴.۳ | DetailLg.js و DetailSm.js هر دو |
✅ | هر دو، با همان idiom ردیفهای موجود (TextLoading + label/value) |
| ۴.۴ | نوبت رزرو: فقط سرویس، بدون مدت | ✅ | تست نوبت رزرو سرویس را نشان میدهد ولی مدت را نه |
| ۴.۵ | نوبت سرویسی بدون service_items → «—»، بدون کرش |
✅ | ردیف کلاً رندر نمیشود (بهجای «—») — سازگار با idiom بقیهٔ ردیفها؛ تست فیلدهای سرویسی کاملاً غایب سبز |
| ۴.۶ | services/response.js: serviceReschedule اضافه شد |
⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
| ۴.۷ | services/response.js: getServiceSlotsForReschedule با exclude_appointment_uuid |
⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
| ۴.۸ | ButtonData.js دکمهٔ جابهجایی + مودال موجود |
⏳ | انجام نشد — نیازمند تصمیم محصول. ButtonData.js کل بدنهاش کامنت شده و <div> خالی رندر میکند؛ کامیت 4651ae5 («PDF download در DetailLg/DetailSm») دکمههای ویرایش/دانلود/مودال را عمداً بازنشسته کرده و اکشنها جای دیگر رفتهاند. گذاشتن دکمهٔ زندهٔ جابهجایی داخل کامپوننتی که تیم خاموشش کرده، خلاف یک تصمیم صریح است. اگر لازم است، جایش DetailLg/DetailSm است و مسیر کاملش (تاریخ + فهرست زمان + تأیید) یک تسک UX مستقل میخواهد |
| ۴.۹ | انتخابگر زمان: components/appointment/date/ بازاستفاده شد، نه ساخت جدید |
⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
| ۴.۱۰ | بیمار مدت وارد نمیکند — بکاند حساب میکند | ⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
| ۴.۱۱ | خطای بکاند با پیام فارسی خودش نمایش داده میشود | ⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
| ۴.۱۲ | پس از خطای تداخل، refetchSlots() اجرا میشود |
⏳ | بخشی از جابهجایی — رجوع به ۴.۸ |
۵. UI — قواعد سایت
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۵.۱ | تم MUI از mui/index.js — تم جدید ساخته نشد |
✅ | تم MUI لمس نشد |
| ۵.۲ | فونت فقط Vazir — فونت جدید اضافه نشد | ✅ | فونتی اضافه نشد |
| ۵.۳ | دارکمود صفحات عمومی (data-theme) بررسی شد |
⚠️ | قابل بررسی نبود و مسئلهاش پروژهای است: Tailwind روی darkMode: "class" است ولی provider عمومی data-theme میگذارد؛ صفر dark: در کل جریان رزرو. یعنی جریان رزرو دارکمود ندارد — نه اینکه من شکستمش. تسک theming جدا لازم است |
| ۵.۴ | دارکمود پنل (class) بررسی شد |
⚠️ | همان برای پنل |
| ۵.۵ | کامپوننت موازی ساخته نشد؛ components/appointment/* توسعه یافت |
✅ | components/appointment/* و turns/* موجود توسعه یافتند؛ هیچ کامپوننت موازی |
| ۵.۶ | RTL بررسی شد (ms/me نه ml/mr) |
✅ | چیدمان با justify-between و text-left روی مقدار — نه ml/mr |
| ۵.۷ | موبایل بررسی شد — بدون اسکرول افقی | 🔄 | بررسی چشمی انجام نشد. ردیفهای افزوده همان ساختار flex ردیفهای موجودند و flex-wrap/shrink-0 دارند |
| ۵.۸ | تاریخها شمسی با jalali-moment |
✅ | jalali-moment برای تاریخِ درخواست مدت؛ نمایش تاریخها با convertTimestampToJalali موجود |
| ۵.۹ | همهٔ رشتهها فارسی | ✅ | همهٔ رشتههای جدید فارسی |
| ۵.۱۰ | صفحاتی که دست خوردند generateMetadata و await params سالم دارند |
✅ | هیچ صفحهای (app/**/page.js) لمس نشد — فقط کامپوننت |
| ۵.۱۱ | دامنه گسترش نیافت — صفحهٔ رزرو بازطراحی نشد | ✅ | گسترش نیافت؛ و انحراف واقعی (نبود theming در کل جریان) بهعنوان ⚠️ در ۵.۳ ثبت شد |
۶. تست دستی — ده سناریو
| # | سناریو | وضعیت | یادداشت |
|---|---|---|---|
| ۶.۱ | رزرو سرویسی کامل تا پیامک | 🔄 | اجرا نشد — مرورگر در دسترس این اجرا نبود. بهجایش تست خودکار: ۱۳ تست جدید (۷ روی adaptServiceSlots، ۶ روی Card) + npm run build سبز |
| ۶.۲ | همان در دارکمود عمومی | 🔄 | اجرا نشد — مرورگر در دسترس این اجرا نبود. بهجایش تست خودکار: ۱۳ تست جدید (۷ روی adaptServiceSlots، ۶ روی Card) + npm run build سبز |
| ۶.۳ | رزرو اسلاتی کامل — بدون تغییر | 🔄 | اجرا نشد. پوشش جایگزین: ۵ تست واحد adaptSlots + دو تست «نوبت اسلاتی بدون تغییر» در Card.test.jsx + build سبز. ⛔ خط سرخ همچنان نیازمند تأیید چشمی |
| ۶.۴ | پزشک دو-شیفته سرویسی → دو تب با برچسب واقعی | ✅ | بازتعریف شد: دو تب ساخته نمیشود چون گروهبندی رد شد (ردیف ۳.۱). یک تب با بازهٔ واقعی — تست یک session با بازهٔ واقعی میسازد |
| ۶.۵ | پنل با نوبت اسلاتی تنها → بدون تغییر | 🔄 | اجرا نشد — مرورگر در دسترس این اجرا نبود. بهجایش تست خودکار: ۱۳ تست جدید (۷ روی adaptServiceSlots، ۶ روی Card) + npm run build سبز |
| ۶.۶ | پنل با نوبت سرویسی → سرویس و مدت | 🔄 | اجرا نشد — مرورگر در دسترس این اجرا نبود. بهجایش تست خودکار: ۱۳ تست جدید (۷ روی adaptServiceSlots، ۶ روی Card) + npm run build سبز |
| ۶.۷ | پنل در دارکمود | 🔄 | اجرا نشد — مرورگر در دسترس این اجرا نبود. بهجایش تست خودکار: ۱۳ تست جدید (۷ روی adaptServiceSlots، ۶ روی Card) + npm run build سبز |
| ۶.۸ | جابهجایی سرویسی → مدت حفظ | ⏳ | جابهجایی انجام نشد — رجوع به ۴.۸ |
| ۶.۹ | جابهجایی به زمان اشغال → پیام فارسی + refetch | ⏳ | همان |
| ۶.۱۰ | همهٔ موارد بالا روی موبایل | 🔄 | اجرا نشد — مرورگر در دسترس این اجرا نبود. بهجایش تست خودکار: ۱۳ تست جدید (۷ روی adaptServiceSlots، ۶ روی Card) + npm run build سبز |
| ۶.۱۱ | تست واحد adaptServiceSlots (پنج حالت) |
✅ | ۷ حالت نه پنج: بازهٔ واقعی · علامت available · ساختار بدون data · fallback بیend_time · خالی → [] · null → [] · یک اسلات تنها |
۷. مستندات
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۷.۱ | nobat724_front/CLAUDE.md بخش «حالتهای نوبتدهی» |
✅ | بخش «Booking Modes (slot vs service)» با جدول دو حالت، قاعدهٔ «مدت دادهٔ سرور است»، دلیل نبودِ گروهبندی شیفت، و گاردهای پنل کاربر |
| ۷.۲ | یادداشت هیوریستیک شیفت در clinicpro/docs/api/appointment.md |
✅ | بلوک هشدار زیر Response 200 همان endpoint در clinicpro/docs/api/appointment.md |
۸. بازبینی پایانی
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۸.۱ | همهٔ ردیفهای بالا وضعیت نهایی دارند (هیچ 🔄 و ⏳ بیدلیل) | ✅ | ۴ ردیف ⏳ همه مربوط به جابهجاییاند و به ۴.۸ ارجاع دارند؛ ۸ ردیف 🔄 همه «بررسی چشمی در مرورگر»؛ ۲ ردیف ⚠️ مسئلهٔ theming پروژهای |
| ۸.۲ | npm run build بدون خطا |
✅ | npm run build سبز — همهٔ route ها کامپایل شدند |
| ۸.۳ | npm run lint بدون خطای جدید |
✅ | 0 errors. سه خطای موجود در TimePickerField.js، clinics/head/filter/Content.js، register/verificationPage/index.js اند — هیچکدام لمس نشدند. فایلهای من: هشدار set-state-in-effect که رفع شد؛ jsx-key های Container.js از قبل بودند (خطوط ۱۰۸+، تغییر من خط ۷۸) |
| ۸.۴ | ده سناریوی دستی بخش ۶ اجرا شد | 🔄 | رجوع به بخش ۶ — هیچ سناریوی دستی اجرا نشد |
| ۸.۵ | چکلیست UI (بخش ۵) کامل شد | ✅ | بخش ۵ کامل شد، شامل دو ⚠️ صادقانه برای دارکمود |
| ۸.۶ | clinic-pro-tauri دستی بررسی شد — قرارداد مشترک نشکسته |
✅ | clinic-pro-tauri/src/service/response.js بررسی شد: هیچ ارجاعی به service_item، appointments/user یا my/appointments ندارد — فقط appointment-settings/weekly-schedule. متأثر نیست |
| ۸.۷ | commit شد، سپس graphify update . |
✅ | چهار کامیت در nobat724_front روی برنچ feat/booking-service-mode-frontend + یک کامیت چکلیست/مستندات در clinicpro |
| ۸.۸ | موارد بهتعویقافتاده با دلیل و تسک مقصد ثبت شدند | ✅ | fallbackSum (حذف پس از deploy تسک ۰۰) · بازنویسی رنگ → تسک theming · دکمهٔ جابهجایی → تسک UX · سناریوهای دستی → بازبینی چشمی |
۹. یافتههای این اجرا
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ی.۱ | دو باگ واقعی در adaptServiceSlots |
✅ | end_time زمانِ شروعِ آخرین اسلات بود (بازه کوتاهتر از واقعیت) و برچسب رشتهٔ ثابت «زمانهای خالی». هر دو رفع شد |
| ی.۲ | ۳ تست از قبل قرمز در lib/lib.test.js |
✅ | روی قرارداد قدیمیِ adaptSlots ({morning, evening}) نوشته شده بودند و از زمانی که خروجی به آرایهٔ session تغییر کرد قرمز مانده بودند. با قرارداد واقعی همخوان شدند؛ سوئیت از ۴ شکست به ۱ رسید |
| ی.۳ | lib/getStateInfo.test.js یک شکست |
⚠️ | «host ناشناخته → بدون تطبیق» با timeout ۵ ثانیه. در baseline هم بود و به multi-domain مربوط است نه این تسک. بدهی ثبتشده |
| ی.۴ | جریان رزرو هیچ پشتیبانی دارکمود ندارد | ⚠️ | darkMode: "class" در Tailwind ولی attribute="data-" در provider عمومی؛ صفر dark: در components/appointment/. مسئلهٔ پروژهای، نه این تسک |
| ی.۵ | ButtonData.js عمداً کامنت شده |
⚠️ | کامیت 4651ae5. هر افزودنِ اکشن به پنل کاربر باید جای دیگری برود و تصمیم محصول بگیرد |