Add AST JSON file for blog category breadcrumb and filter prompt with detailed nodes and edges

This commit is contained in:
hamed
2026-07-30 12:22:55 +03:30
parent 8a24579a50
commit 29881eede0
9 changed files with 1828 additions and 225 deletions
@@ -0,0 +1,564 @@
# تسک ۰۰ب — سازگارسازی سایت عمومی با نوبت‌دهی سرویسی
## پروژه
`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`
```jsx
<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`) — این کامپوننت در دارک‌مود می‌شکند، در حالی
که بقیهٔ مراحل رزرو نمی‌شکنند.
### ۲. محاسبهٔ موازی مدت — همان فایل
```js
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` می‌دهد.
دو منبع حقیقت.
### ۳. `adaptServiceSlots` — `lib/appointmentSlots.js`
```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()` بالای همین فایل (حالت اسلاتی) **قفل است** و یک خط هم عوض نمی‌شود:
```js
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` (درست، دست‌نخورده بماند)
```js
// روش نوبت‌دهی و سرویس‌ها per-location هستند: یک پزشک می‌تواند در مطب شخصی
// اسلاتی و در کلینیک سرویسی باشد.
const bookingMode = selectedLocation?.booking_mode === "service" ? "service" : "slot";
const bookingServices = selectedLocation?.services ?? [];
```
و `changeLocation()` که انتخاب‌های وابسته را باطل می‌کند — این رفتار درست است و حفظ می‌شود.
---
## وظایف
`todo` را از ردیف‌های `checklist.md` همان تسک بساز (بخش‌های ۰ تا ۸)، نه از این هشت وظیفه.
هر ردیف چک‌لیست را همان لحظه `⏳ → 🔄 → ✅` کن.
### ۱. پیش‌بررسی قرارداد API — پیش از هر خط کد
سه چیز را تأیید کن. اگر فیلدی نیست، **کد نزن**؛ به تسک ۰۰ برگردان.
```bash
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` با توکن تم
**اول رنگ‌های همسایه را ببین** — هدف این است که این کامپوننت از بقیهٔ مراحل رزرو قابل
تشخیص نباشد:
```bash
grep -n "className" components/appointment/location/index.js | head -30
grep -n "className" components/appointment/date/index.js | head -30
```
بعد همان الگو را اعمال کن. ساختار DOM و رفتار `toggle` **عوض نمی‌شود** — فقط منبع رنگ.
```jsx
// نمونه؛ نام دقیق کلاس را از 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` می‌آید.
```js
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` شیفت‌آگاه
```js
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.
---
### ۵. سرویس و مدت در پنل کاربر
```jsx
// 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` — دو مکانیزم متفاوت‌اند).
---
### ۶. جابه‌جایی سرویس‌آگاه از پنل
```js
// 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` می‌گیرد.
خطا را با پیام خودِ بک‌اند نشان بده:
```js
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** لازم است. فراموش کردن دومی یعنی راهبر تسک بعدی فکر می‌کند ۰۰ب تمام
نشده و دوباره تحویلش می‌دهد.
```bash
# ۱. کد سایت
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.js``request.*`؛ برای auth `{ requireAuth: true }`
تا کوکی `access_token` به‌صورت Bearer ضمیمه شود
- داده server-side با `lib/req.js``fetchReq(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` کامل ✅
نیست، **این تسک شروع نمی‌شود**:
```bash
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` بساز و در چک‌لیست ثبت کن.