Files
nobat724_front/.claude/prompt/booking-engine-task-00b-service-mode.md

27 KiB
Raw Permalink Blame History

تسک ۰۰ب — سازگارسازی سایت عمومی با نوبت‌دهی سرویسی

پروژه

nobat724_front (سایت عمومی)

پرامپت همتا (بک‌اند، باید اول تمام شده باشد): clinicpro/.claude/prompt/booking-engine-task-runner.md → تسک ۰۰

منبع کامل این تسک — چهار فایل، همه را بخوان:

clinicpro/docs/new_feture/taskes/task-00b-nobat724-service-mode/task.md
clinicpro/docs/new_feture/taskes/task-00b-nobat724-service-mode/architecture.md
clinicpro/docs/new_feture/taskes/task-00b-nobat724-service-mode/implementation_notes.md
clinicpro/docs/new_feture/taskes/task-00b-nobat724-service-mode/checklist.md   ← وضعیت

و سه سند حاکم:

clinicpro/docs/new_feture/taskes/_shared/red-lines.md
clinicpro/docs/new_feture/taskes/_shared/ui-conventions.md
clinicpro/docs/new_feture/taskes/_shared/definition-of-done.md

زمینه

سایت حالت نوبت‌دهی سرویسی را می‌شناسدcomponents/appointment/index.js روش را per محل تشخیص می‌دهد، components/appointment/service/index.js مرحلهٔ انتخاب سرویس را نشان می‌دهد، و lib/appointmentSlots.js پاسخ appointment-service-slots را به قالب اسلات تبدیل می‌کند. ولی سه دسته مشکل دارد: انحراف از تم، محاسبهٔ موازی مدت در فرانت، و نبود سرویس/مدت در پنل کاربر.

تسک ۰۰ در clinicpro سه endpoint جدید ساخته (service-reschedule، convert-reserve، پارامتر exclude_appointment_uuid) و دو ستون service_total_minutes/service_buffer_minutes اضافه کرده. این تسک سایت را با آن‌ها هم‌گام می‌کند.


مشکل / هدف

پنج شکاف مشخص:

# شکاف فایل
۱ چهار رنگ hard-code در مرحلهٔ انتخاب سرویس → دارک‌مود می‌شکند components/appointment/service/index.js
۲ مدت با reduce در فرانت حساب می‌شود، موازی با total_duration_minutes بک‌اند همان فایل
۳ adaptServiceSlots همهٔ زمان‌ها را در یک تب با برچسب ثابت «زمان‌های خالی» می‌ریزد و end_time را اشتباه می‌دهد lib/appointmentSlots.js
۴ پنل کاربر نام سرویس و مدت نوبت را نشان نمی‌دهد components/dashboard/userAccount/sidebars/turns/*
۵ جابه‌جایی نوبت سرویسی از پنل کاربر وجود ندارد .../turns/isTurnsDetails/ButtonData.js

شکاف ۲ مهم‌ترین است: وقتی تسک ۰۴ فرمول را به «زمان تنها / زمان اضافه» عوض کند، سایت عدد قدیمی نشان می‌دهد و بیمار مدتی می‌بیند که با مدت واقعی نوبتش نمی‌خواند.


معیار پذیرش

معیار کامل با همهٔ حالت‌های مرزی در task.md همان تسک است. خلاصهٔ اجباری:

  • موفق: مرحلهٔ انتخاب سرویس در دارک‌مود درست رندر می‌شود — هیچ متن تیره روی زمینهٔ تیره، هیچ کارت سفید.
  • موفق: مدت نمایش‌داده‌شده از total_duration_minutes پاسخ بک‌اند می‌آید؛ اگر بک‌اند عدد متفاوتی بدهد، UI همان را نشان می‌دهد.
  • موفق: پزشکی با دو شیفت (صبح ۹-۱۳، عصر ۱۶-۲۰) در حالت سرویسی → دو تب زمانی با برچسب واقعی هر شیفت.
  • موفق: کارت نوبت در پنل کاربر نام سرویس‌ها و مدت را نشان می‌دهد.
  • موفق: بیمار از پنل نوبت سرویسی‌اش را جابه‌جا می‌کند و عددی وارد نمی‌کند — مدت را بک‌اند حساب می‌کند.
  • موفق ( خط سرخ): رزرو اسلاتی سرتاسر بیت‌به‌بیت مثل قبل کار می‌کند و کارت نوبت اسلاتی در پنل هیچ تغییری نمی‌کند.
  • خطا: جابه‌جایی به زمان اشغال‌شده → پیام فارسی خودِ بک‌اند نمایش داده می‌شود (نه «خطای نامشخص») و فهرست زمان‌ها خودکار refetch می‌شود.
  • خطا: انتخاب صفر سرویس → دکمهٔ ادامه غیرفعال با راهنمای فارسی.
  • ⚠️ مرزی: پنل کاربری که فقط نوبت اسلاتی دارد → بدون هیچ تغییری رندر می‌شود (شرط && روی فیلدهای سرویسی).
  • ⚠️ مرزی: محل سرویسی بدون سرویس bookable → پیام روشن + پیشنهاد محل دیگر اگر باشد.
  • ⚠️ مرزی: total_duration_minutes در پاسخ نبود (بک‌اند قدیمی) → fallbackSum با console.warn، نه صفحهٔ خالی.
  • ⚠️ مرزی: نوبت سرویسیِ قدیمی بدون service_items → نام «—»، بدون کرش.
  • ⚠️ مرزی: نوبت رزرو (is_reserve) در پنل → فقط سرویس‌ها، بدون مدت (زمان ندارد).
  • ⚠️ مرزی: نوبت ۹۰ دقیقه‌ای با شکاف ۹۰ دقیقه → یک تب، نه تب‌های تک‌عضوی (آستانه = max(60, durationMin)).

فایل‌های مرتبط

فایل نقش
components/appointment/service/index.js مرحلهٔ انتخاب سرویس — بازنویسی با توکن تم
components/appointment/index.js ارکستراتور مراحل — تشخیص booking_mode per محل
components/appointment/date/index.js مصرف‌کنندهٔ adaptServiceSlots
components/appointment/detail/SubmitData.js ارسال service_item_uuids در ثبت
lib/appointmentSlots.js adaptSlots ( قفل) و adaptServiceSlots (بازنویسی)
services/response.js افزودن serviceReschedule و getServiceSlotsForReschedule
components/dashboard/userAccount/sidebars/turns/Card.js + نام سرویس و مدت
.../turns/isTurnsDetails/DetailLg.js · DetailSm.js همان
.../turns/isTurnsDetails/ButtonData.js + دکمهٔ جابه‌جایی
.../turns/isTurnsDetails/modal/index.js مودال موجود — بازاستفاده
mui/index.js · tailwind.config.js · app/globals.css منبع تم و توکن
CLAUDE.md + بخش «حالت‌های نوبت‌دهی»

وضعیت فعلی

۱. رنگ‌های hard-code — components/appointment/service/index.js

<h2 className="text-[16px] font-bold text-[#3B3B3B] mb-4">۱. انتخاب سرویس</h2>

{services.length === 0 ? (
  <p className="text-[14px] text-[#7A7A7A]">
    در حال حاضر سرویسی برای نوبتدهی آنلاین تعریف نشده است.
  </p>
) : (
  
    className={`flex items-center justify-between gap-3 p-3 rounded-xl border text-right transition-colors ${
      active
        ? "border-[#5559CE] bg-[#5559CE]/5"
        : "border-gray-200 bg-white hover:border-[#5559CE]"
    }`}

چهار رنگ ثابت. سایت darkMode: "class" دارد و صفحات عمومی با data-theme تم عوض می‌کنند (app/Providers.js با next-themes) — این کامپوننت در دارک‌مود می‌شکند، در حالی که بقیهٔ مراحل رزرو نمی‌شکنند.

۲. محاسبهٔ موازی مدت — همان فایل

const totalMinutes = services
  .filter((s) => draft.includes(s.uuid))
  .reduce((sum, s) => sum + (Number(s.duration_minutes) || 0), 0);

بک‌اند همان عدد را در total_duration_minutes پاسخ appointment-service-slots می‌دهد. دو منبع حقیقت.

۳. adaptServiceSlotslib/appointmentSlots.js

// حالت سرویسی: پاسخ appointment-service-slots فقط start_times دارد (همه کافی).
// آن‌ها را در یک session قالب‌بندی می‌کنیم تا مثل حالت اسلاتی رندر شوند.
export function adaptServiceSlots(slotsResponse) {
  const starts =
    slotsResponse?.data?.start_times ?? slotsResponse?.start_times ?? [];
  if (!starts.length) return [];
  return [
    {
      start_time: starts[0].start_time,
      end_time: starts[starts.length - 1].start_time,
      label: "زمان‌های خالی",
      slots: starts.map((s) => ({ ...s, is_available: true })),
    },
  ];
}

سه مشکل: همه در یک تب · برچسب ثابت · end_time برابر شروعِ آخرین اسلات، نه پایان نوبت.

تابع adaptSlots() بالای همین فایل (حالت اسلاتی) قفل است و یک خط هم عوض نمی‌شود:

export function adaptSlots(slotsResponse) {
  const sessions = slotsResponse?.data?.sessions ?? slotsResponse?.sessions ?? [];
  return sessions
    .filter((session) => Array.isArray(session.slots) && session.slots.length > 0)
    .map((session) => ({  }));
}

۴ و ۵. پنل کاربر

components/dashboard/userAccount/sidebars/turns/Card.js و isTurnsDetails/DetailLg.js/DetailSm.js هیچ ارجاعی به service یا مدت ندارند. ButtonData.js هیچ مسیر جابه‌جایی ندارد.

تشخیص حالت — components/appointment/index.js:125 (درست، دست‌نخورده بماند)

// روش نوبت‌دهی و سرویس‌ها per-location هستند: یک پزشک می‌تواند در مطب شخصی
// اسلاتی و در کلینیک سرویسی باشد.
const bookingMode = selectedLocation?.booking_mode === "service" ? "service" : "slot";
const bookingServices = selectedLocation?.services ?? [];

و changeLocation() که انتخاب‌های وابسته را باطل می‌کند — این رفتار درست است و حفظ می‌شود.


وظایف

todo را از ردیف‌های checklist.md همان تسک بساز (بخش‌های ۰ تا ۸)، نه از این هشت وظیفه. هر ردیف چک‌لیست را همان لحظه ⏳ → 🔄 → ✅ کن.

۱. پیش‌بررسی قرارداد API — پیش از هر خط کد

سه چیز را تأیید کن. اگر فیلدی نیست، کد نزن؛ به تسک ۰۰ برگردان.

TOKEN=<access_token یک کاربر تست>

# ۱. appointments/user چه فیلدهایی دارد؟
curl -s -H "Authorization: Bearer $TOKEN" \
  https://clinic-pro.ddev.site/api/v1/appointments/user | jq '.data[0] | keys'
# باید service_items و service_total_minutes داشته باشد

# ۲. هر start_times[i] فیلد end_time دارد؟
curl -s "https://clinic-pro.ddev.site/api/v1/appointment-service-slots?doctor_uuid=…&date=…&service_item_uuids[]=…" \
  | jq '.data.start_times[0], .data.total_duration_minutes, .data.buffer_minutes'

# ۳. exclude_appointment_uuid کار می‌کند؟
curl -s "…&exclude_appointment_uuid=<uuid نوبت موجود>" | jq '.data.start_times | length'

نحوه تست: خروجی واقعی هر سه دستور را در گزارش بگذار. ردیف‌های ۱.۱ تا ۱.۵ چک‌لیست با همین‌ها می‌شوند.


۲. بازنویسی service/index.js با توکن تم

اول رنگ‌های همسایه را ببین — هدف این است که این کامپوننت از بقیهٔ مراحل رزرو قابل تشخیص نباشد:

grep -n "className" components/appointment/location/index.js | head -30
grep -n "className" components/appointment/date/index.js | head -30

بعد همان الگو را اعمال کن. ساختار DOM و رفتار toggle عوض نمی‌شود — فقط منبع رنگ.

// نمونه؛ نام دقیق کلاس را از tailwind.config.js و mui/index.js همین پروژه بردار
<h2 className="text-base font-bold text-foreground mb-4">۱. انتخاب سرویس</h2>

className={active
  ? "border-primary bg-primary/5"
  : "border-border bg-surface hover:border-primary"}

اگر پروژه توکن معادل ندارد، توکن جدید نساز — همان کاری را بکن که location/index.js می‌کند. اگر دارک‌مود در آن هم شکسته است، این یک مسئلهٔ جداست: ردیف ⚠️ در چک‌لیست ثبت کن و دامنه را گسترش نده. صفحهٔ رزرو در این تسک بازطراحی نمی‌شود.

نحوه تست: سناریوهای ۶.۱ و ۶.۲ چک‌لیست — رزرو سرویسی کامل، یک بار در لایت و یک بار در دارک (data-theme). اسکرین‌شات هر دو حالت در گزارش.


۳. حذف محاسبهٔ موازی مدت

مدت از total_duration_minutes می‌آید. مسئلهٔ ترتیبی: مرحلهٔ انتخاب سرویس پیش از انتخاب روز است و آن endpoint تاریخ می‌خواهد. راه‌حل انتخاب‌شده (دلیل در architecture.md بخش ۲): فراخوانی با تاریخ امروز فقط برای گرفتن مدت — پاسخ ممکن است start_times خالی داشته باشد ولی total_duration_minutes می‌آید.

const { data } = useServiceDuration(doctorUuid, clinicUuid, draft);   // hook جدید

const minutes = data?.total_duration_minutes ?? (() => {
  console.warn('[booking] total_duration_minutes missing — falling back to client sum');
  return fallbackSum(draft, services);
})();

// پیش از انتخاب روز
<span>مدت تقریبی: {minutes} دقیقه</span>
// پس از انتخاب روز — از همان پاسخ appointment-service-slots
<span>مدت نوبت: {minutes} دقیقه</span>

fallbackSum موقت است و فقط برای بک‌اند قدیمی. حذفش را در چک‌لیست به‌عنوان ردیف با دلیل و تسک مقصد ثبت کن.

نحوه تست: دو سرویس انتخاب کن و عدد UI را با curl … | jq '.data.total_duration_minutes' مقایسه کن — باید یکی باشند. بعد یک بار total_duration_minutes را از پاسخ حذف کن (mock) و ببین console.warn می‌زند و صفحه خالی نمی‌شود.


۴. adaptServiceSlots شیفت‌آگاه

export function adaptServiceSlots(slotsResponse) {
  const payload = slotsResponse?.data ?? slotsResponse ?? {};
  const starts  = payload.start_times ?? [];
  if (!starts.length) return [];

  const durationMin = Number(payload.total_duration_minutes) || 0;
  // آستانه هرگز کمتر از مدت نوبت — وگرنه نوبت بلند به تب‌های تک‌عضوی می‌شکند
  const threshold = Math.max(60, durationMin);

  const groups = [];
  let current = null;

  for (const s of starts) {
    const gapMin = current
      ? (s.start - current.slots[current.slots.length - 1].start) / 60
      : Infinity;
    if (!current || gapMin > threshold) {
      current = { slots: [] };
      groups.push(current);
    }
    current.slots.push({ ...s, is_available: true });
  }

  return groups.map((g) => {
    const first = g.slots[0];
    const last  = g.slots[g.slots.length - 1];
    const endTime = last.end_time ?? addMinutes(last.start_time, durationMin);
    return {
      start_time: first.start_time,
      end_time:   endTime,
      label:      `${first.start_time} - ${endTime}`,   // همان قالب حالت اسلاتی
      slots:      g.slots,
    };
  });
}

کامنت بنویس که گروه‌بندی هیوریستیک است و راه دقیقش endpoint تسک ۰۶ است — تصمیم و دلیل رد گزینهٔ «گروه‌بندی از بک‌اند» در architecture.md بخش ۳ ثبت شده (تغییر قرارداد endpoint که سه کلاینت مصرفش می‌کنند).

adaptSlots() را لمس نکن.

نحوه تست: adaptServiceSlots تابع خالص است — بهترین کاندید تست واحد. پنج حالت:

یک شیفت → یک گروه
دو شیفت با شکاف ۳ ساعت → دو گروه با برچسب درست
نوبت ۹۰ دقیقه‌ای با شکاف ۹۰ دقیقه → یک گروه
start_times خالی → []
end_time از پاسخ می‌آید، نه محاسبه

و سناریوی دستی ۶.۴: پزشک دو-شیفته در حالت سرویسی → دو تب در UI.


۵. سرویس و مدت در پنل کاربر

// Card.js — شرط && اجباری است
{turn.service_items?.length > 0 && (
  <span className="…">{turn.service_items.map((s) => s.name).join("، ")}</span>
)}
{turn.service_total_minutes && !turn.is_reserve && (
  <span className="…">{turn.service_total_minutes} دقیقه</span>
)}

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

همین را در DetailLg.js و DetailSm.js هم اعمال کن.

نحوه تست: سناریوهای ۶.۵ تا ۶.۷ — پنل کاربری که فقط نوبت اسلاتی دارد باید بدون تغییر رندر شود؛ پنل با نوبت سرویسی سرویس و مدت را نشان دهد؛ هر دو در دارک‌مود پنل (class، نه data-theme — دو مکانیزم متفاوت‌اند).


۶. جابه‌جایی سرویس‌آگاه از پنل

// services/response.js
serviceReschedule: (uuid, body) =>
  request.post(`api/v1/appointment/${uuid}/service-reschedule`, body, { requireAuth: true }),

getServiceSlotsForReschedule: (doctor_uuid, date, service_uuids, exclude_uuid, clinic_uuid) =>
  request.get(
    `api/v1/appointment-service-slots?doctor_uuid=${doctor_uuid}&date=${date}` +
    service_uuids.map((u) => `&service_item_uuids[]=${encodeURIComponent(u)}`).join("") +
    `&exclude_appointment_uuid=${exclude_uuid}` + clinicQuery(clinic_uuid),
    { requireAuth: true }
  ),

ButtonData.js دکمهٔ «جابه‌جایی» می‌گیرد که مودال موجود (isTurnsDetails/modal/index.js) را با components/appointment/date/ باز می‌کند — انتخابگر زمان جدید نساز؛ آن کامپوننت هر دو حالت را از قبل می‌شناسد.

بیمار مدت وارد نمی‌کند: service-reschedule فقط start می‌گیرد.

خطا را با پیام خودِ بک‌اند نشان بده:

catch (err) {
  const msg = err?.response?.data?.errors?.[0]?.message ?? 'خطایی رخ داد';
  toast.error(msg);
  refetchSlots();          // بعد از خطای تداخل اجباری
}

ERR_SLOT_TAKEN پیام فارسی دقیق دارد؛ «خطای نامشخص» یعنی بیمار همان دکمه را ده بار می‌زند.

نحوه تست: سناریوهای ۶.۸ و ۶.۹ — جابه‌جایی موفق (مدت حفظ می‌شود، بیمار عددی وارد نکرده) و جابه‌جایی به زمانی که هم‌زمان توسط شخص دیگری گرفته شده (پیام فارسی + refetch). برای دومی، یک نوبت از پنل ادمین روی همان زمان بساز و بعد دکمه را بزن.


۷. به‌روزرسانی checklist.md — دو مخزن جدا

⚠️ این تسک دو مخزن git را لمس می‌کند:

مخزن چه چیزی
nobat724_front همهٔ تغییرات کد
clinicpro فقط docs/new_feture/taskes/task-00b-nobat724-service-mode/checklist.md

پس دو commit لازم است. فراموش کردن دومی یعنی راهبر تسک بعدی فکر می‌کند ۰۰ب تمام نشده و دوباره تحویلش می‌دهد.

# ۱. کد سایت
cd nobat724_front
git checkout -b feat/booking-service-mode-frontend   # اگر روی main هستی
git add -A
git commit -m "$(cat <<'EOF'
feat(booking): align public site with service booking mode

Theme tokens in service picker, backend-driven duration, shift-aware
slot grouping, service/duration in user panel, service-aware reschedule.
Slot-mode path untouched.

Task: clinicpro/docs/new_feture/taskes/task-00b-nobat724-service-mode/

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
EOF
)"

# ۲. چک‌لیست در مخزن clinicpro
cd ../clinicpro
git add docs/new_feture/taskes/task-00b-nobat724-service-mode/checklist.md
git commit -m "$(cat <<'EOF'
docs(booking): mark task 00b checklist complete

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
EOF
)"

نحوه تست: git log --oneline -1 در هر دو مخزن، و grep -c '| ⏳ |' clinicpro/docs/new_feture/taskes/task-00b-nobat724-service-mode/checklist.md که باید ۰ بدهد (یا فقط ردیف‌های با یادداشت دلیل).


۸. مستندات و گزارش پایانی

nobat724_front/CLAUDE.md              ← بخش «حالت‌های نوبت‌دهی»: slot و service،
                                        per محل تعیین می‌شوند، adaptSlots/adaptServiceSlots
                                        نقطهٔ تفکیک‌اند
clinicpro/docs/api/appointment.md     ← یادداشت: گروه‌بندی شیفت در حالت سرویسی
                                        هیوریستیک سمت فرانت است؛ راه دقیقش endpoint تسک ۰۶

گزارش پایانی:

✅ تسک ۰۰ب تمام شد

پیاده‌سازی
  • <فایل‌ها با مسیر>

تست
  • npm run build            : بدون خطا
  • npm run lint             : بدون خطای جدید
  • تست واحد adaptServiceSlots: <N> حالت، سبز
  • ۱۱ سناریوی دستی          : <فهرست با نتیجه>

خط سرخ
  • مسیر اسلاتی دست‌نخورده — adaptSlots عوض نشد؛ سناریوی ۶.۳ سرتاسر تست شد

کلاینت دیگر
  • clinic-pro-tauri: <چه بررسی شد — قرارداد service_item تکی>

به تعویق افتاد
  • fallbackSum — دلیل: تا deploy تسک ۰۰ · تسک مقصد: <XX>

commit سایت: <hash>   ·   commit چک‌لیست: <hash>

────────────────────────────────
🎯 بعدی: تسک ۰۱ — شعبه و اتاق
   اجرا کن:  /run-prompt clinicpro/.claude/prompt/booking-engine-task-runner.md

نکات مهم

خط سرخ — مسیر اسلاتی سایت

_shared/red-lines.md حاکم است. در این پروژه یعنی:

  • adaptSlots() یک خط هم عوض نمی‌شود
  • رندر تب‌های شیفت در حالت اسلاتی دست‌نخورده
  • کارت نوبت اسلاتی در پنل بدون تغییر (شرط && روی فیلدهای سرویسی)
  • سناریوی ۶.۳ (رزرو اسلاتی سرتاسر) اجباری است، نه اختیاری

اگر بعد از تغییرات، رزرو اسلاتی یک پیکسل هم فرق کرد، تغییر برمی‌گردد.

دامنه را گسترش نده

فقط service/index.js که خودمان اضافه کردیم و از بقیهٔ مراحل منحرف است بازنویسی می‌شود. اگر location/index.js یا date/index.js هم رنگ hard-code دارند و دارک‌مودشان شکسته است، این یک مسئلهٔ جداست: ردیف ⚠️ در چک‌لیست ثبت کن و بگذار. بازطراحی کل صفحهٔ رزرو در این تسک نیست.

قواعد سایت که رعایت می‌شوند

از _shared/ui-conventions.md بخش nobat724_front و CLAUDE.md پروژه:

  • تم MUI از mui/index.js با direction: rtlتم جدید نساز
  • Tailwind با darkMode: "class"؛ صفحات عمومی data-theme، پنل classهر دو تست شوند
  • فونت فقط Vazir از app/globals.css با @font-face — فونت دیگر اضافه نکن
  • فراخوانی API از services/response.jsrequest.*؛ برای auth { requireAuth: true } تا کوکی access_token به‌صورت Bearer ضمیمه شود
  • داده server-side با lib/req.jsfetchReq(url)
  • کامپوننت‌های موجود components/appointment/* توسعه داده می‌شوند، مسیر موازی نه
  • تاریخ شمسی با jalali-moment
  • RTL — ms-*/me-* نه ml-*/mr-*
  • هر صفحه‌ای که دست خورد، generateMetadata و await params سالم بماند
  • slug پزشک/کلینیک = uuid
  • شهر از subdomain: server-side lib/getStateInfo.js · client-side useProvince()

وابستگی سخت به تسک ۰۰

سه endpoint و دو ستون این تسک را تسک ۰۰ می‌سازد. اگر clinicpro/docs/new_feture/taskes/task-00-service-mode-completion/checklist.md کامل نیست، این تسک شروع نمی‌شود:

grep -c '| ⏳ |\|| 🔄 |' clinicpro/docs/new_feture/taskes/task-00-service-mode-completion/checklist.md
# باید ۰ بدهد

اگر نداد، پیام بده و بایست: /run-prompt clinicpro/.claude/prompt/booking-engine-task-runner.md

cross-repo — بررسی دستی اجباری

clinic-pro-tauri/src/service/response.js هم مصرف‌کنندهٔ همان /api/v1/... است. این تسک قرارداد بک‌اند را عوض نمی‌کند (فقط مصرف می‌کند)، ولی اگر تسک ۰۰ فیلدی را جابه‌جا کرده باشد، اپ دسکتاپ هم متأثر است. بررسی کن که service_item تکی هنوز در پاسخ هست و گزارش بده — «بررسی شد» بی‌ارزش است، نام فایل و فیلد را بنویس (guidelines §۳).

تست خودکار محدود است

پروژه تست خودکار کمی دارد، پس یازده سناریوی دستی بخش ۶ چک‌لیست اجباری‌اند، نه توصیه. هر ده مورد اول روی موبایل هم تکرار می‌شوند (سناریو ۶.۱۰) — بدون اسکرول افقی.

adaptServiceSlots تابع خالص است و بهترین کاندید تست واحد؛ اگر پروژه runner تست ندارد، یک فایل ساده در tests/appointmentSlots.test.js بساز و در چک‌لیست ثبت کن.