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` بساز و در چک‌لیست ثبت کن.
+7 -1
View File
@@ -405,5 +405,11 @@
"403": "Community 403",
"404": "Community 404",
"405": "Community 405",
"406": "Community 406"
"406": "Community 406",
"407": "Community 407",
"408": "Community 408",
"409": "Community 409",
"410": "Community 410",
"411": "Community 411",
"412": "Community 412"
}
+66 -40
View File
@@ -1,16 +1,16 @@
# Graph Report - nobat724_front (2026-07-27)
# Graph Report - nobat724_front (2026-07-30)
## Corpus Check
- 639 files · ~576,045 words
- 642 files · ~582,216 words
- Verdict: corpus is large enough that graph structure adds value.
## Summary
- 2422 nodes · 2500 edges · 407 communities (372 shown, 35 thin omitted)
- 2473 nodes · 2548 edges · 413 communities (377 shown, 36 thin omitted)
- Extraction: 93% EXTRACTED · 7% INFERRED · 0% AMBIGUOUS · INFERRED: 176 edges (avg confidence: 0.8)
- Token cost: 0 input · 0 output
## Graph Freshness
- Built from commit: `19ae08c0`
- Built from commit: `8a24579a`
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
- Run `graphify update .` after code changes (no API cost).
@@ -177,6 +177,12 @@
- [[_COMMUNITY_Community 398|Community 398]]
- [[_COMMUNITY_Community 402|Community 402]]
- [[_COMMUNITY_Community 403|Community 403]]
- [[_COMMUNITY_Community 407|Community 407]]
- [[_COMMUNITY_Community 408|Community 408]]
- [[_COMMUNITY_Community 409|Community 409]]
- [[_COMMUNITY_Community 410|Community 410]]
- [[_COMMUNITY_Community 411|Community 411]]
- [[_COMMUNITY_Community 412|Community 412]]
## God Nodes (most connected - your core abstractions)
1. `getStateInfo()` - 29 edges
@@ -205,7 +211,7 @@
## Import Cycles
- None detected.
## Communities (407 total, 35 thin omitted)
## Communities (413 total, 36 thin omitted)
### Community 0 - "Community 0"
Cohesion: 0.05
@@ -224,8 +230,8 @@ Cohesion: 0.23
Nodes (16): getCurrentDomain(), robots(), cityFilterParams(), fetchAllPages(), getBlogUrls(), getCityScope(), getClinicUrls(), getCurrentDomain() (+8 more)
### Community 4 - "Community 4"
Cohesion: 0.06
Nodes (22): ContentDetail(), About(), ListBime(), Services(), Specialties(), TextDetail(), listTab, AddComment() (+14 more)
Cohesion: 0.05
Nodes (33): ContentDetail(), About(), ListBime(), Services(), Specialties(), TextDetail(), listTab, AddComment() (+25 more)
### Community 5 - "Community 5"
Cohesion: 0.07
@@ -240,8 +246,8 @@ Cohesion: 0.07
Nodes (4): degreeVal, NAME_HONORIFICS, normalizeBlog(), removeTokenHead
### Community 8 - "Community 8"
Cohesion: 0.07
Nodes (28): devDependencies, babel-plugin-react-compiler, cross-env, eslint, eslint-config-next, @eslint/eslintrc, jsdom, prettier (+20 more)
Cohesion: 0.13
Nodes (15): devDependencies, babel-plugin-react-compiler, cross-env, eslint, eslint-config-next, @eslint/eslintrc, jsdom, prettier (+7 more)
### Community 9 - "Community 9"
Cohesion: 0.07
@@ -324,8 +330,8 @@ Cohesion: 0.12
Nodes (16): دیپلوی nobat724_front روی Liara (پلتفرم Next.js), زمینه, فایل‌های مرتبط, مشکل / هدف, نکات مهم, وضعیت فعلی, وظایف, پروژه (+8 more)
### Community 29 - "Community 29"
Cohesion: 0.08
Nodes (20): generateMetadata(), Blogs(), generateMetadata(), Clinics(), Appointment(), metadata, Doctors(), generateMetadata() (+12 more)
Cohesion: 0.13
Nodes (11): generateMetadata(), Blogs(), generateMetadata(), Appointment(), metadata, fetchSiteContext(), getStateInfo(), siteContextCache (+3 more)
### Community 30 - "Community 30"
Cohesion: 0.12
@@ -388,8 +394,8 @@ Cohesion: 0.14
Nodes (13): `hours/List.js`, آبجکت اسلات (از `adaptSlots` / API), تأیید و سخت‌سازی غیرفعال‌بودن اسلات‌های گذشته در صفحه‌ی نوبت, زمینه, فایل‌های مرتبط, مشکل / هدف, نکات مهم, وضعیت فعلی (کد واقعی) (+5 more)
### Community 45 - "Community 45"
Cohesion: 0.40
Nodes (9): generateMetadata(), blogCover(), imageUrl(), domainScopeCityId(), findCityById(), isBlogVisibleOnDomain(), Blog(), getBlog (+1 more)
Cohesion: 0.20
Nodes (20): generateMetadata(), generateMetadata(), generateMetadata(), DoctorPage(), blogCover(), doctorTitle(), imageUrl(), domainScopeCityId() (+12 more)
### Community 46 - "Community 46"
Cohesion: 0.22
@@ -488,8 +494,8 @@ Cohesion: 0.20
Nodes (9): رفع جهت تبدیل تاریخ تولد هنگام ایجاد پروفایل, زمینه, فایل‌های مرتبط, مشکل / هدف, نکات مهم, وضعیت فعلی (کد واقعی), وظایف, پروژه (+1 more)
### Community 70 - "Community 70"
Cohesion: 0.13
Nodes (13): ClinicsPage(), AutoComplete(), ButtonFilter(), Content(), ModalSearchCity(), AutoSearch(), FilterButton(), SearchBar() (+5 more)
Cohesion: 0.20
Nodes (7): AutoComplete(), ButtonFilter(), Content(), ModalSearchCity(), AutoSearch(), FilterButton(), SearchBar()
### Community 71 - "Community 71"
Cohesion: 0.22
@@ -520,8 +526,8 @@ Cohesion: 0.17
Nodes (11): زمینه, سایت دامنه اختصاصی نماینده سراسری — تشخیص دامنه، فیلتر پزشکان/کلینیک‌ها, فایل‌های مرتبط, مشکل / هدف, نکات مهم, وضعیت فعلی, وظایف, پروژه (+3 more)
### Community 81 - "Community 81"
Cohesion: 0.24
Nodes (14): generateMetadata(), Detail(), getClinicAddress(), getClinicCity(), getClinicPhone(), getClinicState(), hasClinicContact(), telHref() (+6 more)
Cohesion: 0.07
Nodes (28): cross-repo — بررسی دستی اجباری, تست خودکار محدود است, تسک ۰۰ب — سازگارسازی سایت عمومی با نوبت‌دهی سرویسی, تشخیص حالت — `components/appointment/index.js:125` (درست، دست‌نخورده بماند), ⛔ خط سرخ — مسیر اسلاتی سایت, دامنه را گسترش نده, زمینه, فایل‌های مرتبط (+20 more)
### Community 82 - "Community 82"
Cohesion: 0.17
@@ -532,8 +538,8 @@ Cohesion: 0.24
Nodes (5): Head(), Article(), LatestArticles(), Title(), ItemTitle()
### Community 86 - "Community 86"
Cohesion: 0.16
Nodes (15): RootLayout(), generateMetadata(), safeJsonLd(), bodyVariants(), buildSpecialtyFaq(), buildSpecialtyIntro(), closingVariants(), openingVariants() (+7 more)
Cohesion: 0.27
Nodes (10): generateMetadata(), bodyVariants(), buildSpecialtyFaq(), buildSpecialtyIntro(), closingVariants(), openingVariants(), pick(), findSpecialty() (+2 more)
### Community 87 - "Community 87"
Cohesion: 0.33
@@ -608,8 +614,8 @@ Cohesion: 0.15
Nodes (12): اصلاح بخش «اطلاعات تماس» صفحه کلینیک, زمینه, فایل‌های مرتبط, مشکل / هدف, نکات مهم, وضعیت فعلی, وظایف, پروژه (+4 more)
### Community 140 - "Community 140"
Cohesion: 0.53
Nodes (4): Pageguide(), absoluteUrl(), buildBreadcrumbJsonLd(), normalizeBreadcrumb()
Cohesion: 0.36
Nodes (6): RootLayout(), Pageguide(), absoluteUrl(), buildBreadcrumbJsonLd(), normalizeBreadcrumb(), safeJsonLd()
### Community 354 - "Community 354"
Cohesion: 0.11
@@ -632,16 +638,16 @@ Cohesion: 0.19
Nodes (9): Card(), PAYMENT_STATUS, TYPE_LABELS, Head(), listTab, Transactions(), List(), PAYMENT_STATUS (+1 more)
### Community 369 - "Community 369"
Cohesion: 0.33
Nodes (5): buildDoctorParams(), normalizeDoctorNameQuery(), QueryForDoctorsClinicReq(), QueryForDoctorsReq(), buildSearchUrl()
Cohesion: 0.29
Nodes (6): Doctors(), buildDoctorParams(), normalizeDoctorNameQuery(), QueryForDoctorsClinicReq(), QueryForDoctorsReq(), buildSearchUrl()
### Community 370 - "Community 370"
Cohesion: 0.29
Nodes (4): ProvinceContext, ProvinceProvider(), Probe(), useProvince()
Cohesion: 0.25
Nodes (5): ProvinceContext, ProvinceProvider(), Probe(), useProvince(), SubmitData()
### Community 372 - "Community 372"
Cohesion: 0.22
Nodes (14): generateMetadata(), DoctorPage(), doctorTitle(), hasRealName(), isNoindexDoctor(), isThinClinic(), isThinDoctor(), isUnclaimedDoctor() (+6 more)
Cohesion: 0.48
Nodes (6): hasRealName(), isNoindexDoctor(), isThinClinic(), isThinDoctor(), isUnclaimedDoctor(), PLACEHOLDER_NAMES
### Community 373 - "Community 373"
Cohesion: 0.12
@@ -683,10 +689,6 @@ Nodes (10): زمینه, فعال‌سازی بلاگ شهر-محور (بعد ا
Cohesion: 0.20
Nodes (9): زمینه, ساده‌سازی sitemap با شهرِ موجود در پاسخ + آستانهٔ sitemap-index, نکات مهم, وضعیت فعلی, وظایف, پروژه, ۱. حذف ۳۵ sweep و یکسان‌سازی با الگوی کلینیک, ۲. آستانهٔ sitemap-index (مستقل از backend) (+1 more)
### Community 388 - "Community 388"
Cohesion: 0.36
Nodes (3): Form(), SubmitData(), ButtonFixed()
### Community 390 - "Community 390"
Cohesion: 0.40
Nodes (3): Allergies(), ItemAllergie(), ModalAddAlergie()
@@ -703,37 +705,61 @@ Nodes (3): ModalAddRelatives(), Relatives(), ItemRelatives()
Cohesion: 0.40
Nodes (3): ModalAddSurgeries(), Surgeries(), ItemSurgeries()
### Community 395 - "Community 395"
Cohesion: 0.31
Nodes (3): Content(), Form(), EditField()
### Community 397 - "Community 397"
Cohesion: 0.50
Nodes (3): formatToman(), rialToToman(), Paying()
### Community 402 - "Community 402"
Cohesion: 0.38
Nodes (4): DoctorsPage(), resolveCityDisplayName(), isRootCity(), ListDoctors()
Cohesion: 0.21
Nodes (10): ClinicsPage(), DoctorsPage(), resolveCityDisplayName(), buildClinicsIntro(), buildDoctorsIntro(), CLINIC_INTROS(), DOCTOR_INTROS(), pick() (+2 more)
### Community 403 - "Community 403"
Cohesion: 0.29
Nodes (6): CARD, lines, mark, OUT, PARAGRAPH, ROOT
### Community 407 - "Community 407"
Cohesion: 0.10
Nodes (19): زمینه, صفحهٔ بلاگ: بردکرامب دسته‌بندی، فیلتر دسته‌بندی، و اصلاح ستون «مطالب مرتبط», فایل‌های مرتبط, مشکل / هدف, معیار پذیرش, نکات مهم, وضعیت فعلی, وظایف (+11 more)
### Community 408 - "Community 408"
Cohesion: 0.17
Nodes (8): Clinics(), generateMetadata(), buildClinicParams(), isMaintenanceError(), isNextRedirectError(), axiosInstance, fetchReq(), getClinicDoctors()
### Community 409 - "Community 409"
Cohesion: 0.25
Nodes (8): scripts, build, dev, lint, start, test, test:cov, test:watch
### Community 410 - "Community 410"
Cohesion: 0.33
Nodes (5): engines, node, name, private, version
### Community 411 - "Community 411"
Cohesion: 0.67
Nodes (3): IDS_WITH_ACTIVE_CHILDREN, isCategorySpecialty(), isIndexableSpecialty()
## Knowledge Gaps
- **904 isolated node(s):** `metadata`, `fallbackLabels`, `MaterialUISwitch`, `fixedIconData`, `metadata` (+899 more)
- **945 isolated node(s):** `metadata`, `fallbackLabels`, `MaterialUISwitch`, `fixedIconData`, `metadata` (+940 more)
These have ≤1 connection - possible missing edges or undocumented components.
- **35 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
- **36 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `imageUrl()` connect `Community 45` to `Community 0`, `Community 4`, `Community 7`, `Community 392`, `Community 81`, `Community 83`, `Community 372`, `Community 55`, `Community 56`, `Community 380`?**
- **Why does `imageUrl()` connect `Community 45` to `Community 0`, `Community 4`, `Community 7`, `Community 392`, `Community 83`, `Community 55`, `Community 56`, `Community 380`?**
_High betweenness centrality (0.028) - this node is a cross-community bridge._
- **Why does `getStateInfo()` connect `Community 29` to `Community 0`, `Community 6`, `Community 72`, `Community 377`, `Community 45`, `Community 14`, `Community 16`, `Community 81`, `Community 402`, `Community 51`, `Community 372`, `Community 86`, `Community 89`?**
_High betweenness centrality (0.023) - this node is a cross-community bridge._
- **Why does `doctorTitle()` connect `Community 372` to `Community 5`, `Community 7`?**
- **Why does `getStateInfo()` connect `Community 29` to `Community 89`, `Community 0`, `Community 6`, `Community 72`, `Community 140`, `Community 45`, `Community 14`, `Community 16`, `Community 369`, `Community 402`, `Community 51`, `Community 86`, `Community 408`, `Community 377`?**
_High betweenness centrality (0.025) - this node is a cross-community bridge._
- **Why does `doctorTitle()` connect `Community 45` to `Community 5`, `Community 7`?**
_High betweenness centrality (0.012) - this node is a cross-community bridge._
- **Are the 27 inferred relationships involving `getStateInfo()` (e.g. with `generateMetadata()` and `AboutUsPage()`) actually correct?**
_`getStateInfo()` has 27 INFERRED edges - model-reasoned connections that need verification._
- **Are the 14 inferred relationships involving `imageUrl()` (e.g. with `generateMetadata()` and `generateMetadata()`) actually correct?**
_`imageUrl()` has 14 INFERRED edges - model-reasoned connections that need verification._
- **What connects `metadata`, `fallbackLabels`, `MaterialUISwitch` to the rest of the system?**
_904 weakly-connected nodes found - possible documentation gaps or missing edges._
_945 weakly-connected nodes found - possible documentation gaps or missing edges._
- **Should `Community 0` be split into smaller, more focused modules?**
_Cohesion score 0.05263157894736842 - nodes in this community are weakly interconnected._
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1136 -146
View File
File diff suppressed because it is too large Load Diff
+48 -33
View File
@@ -35,8 +35,8 @@
"semantic_hash": ""
},
"app/blog/[slug]/page.js": {
"mtime": 1785166314.496041,
"ast_hash": "32f4bfdb268aa713430b5c767d00d3f5",
"mtime": 1785321773.581832,
"ast_hash": "63829871fbd0997f501943a7d7bd8434",
"semantic_hash": ""
},
"app/blogs/loading.js": {
@@ -45,8 +45,8 @@
"semantic_hash": ""
},
"app/blogs/page.js": {
"mtime": 1784832329.025042,
"ast_hash": "97b0d9e4eba0d139778da068d733a73f",
"mtime": 1785321715.0718546,
"ast_hash": "4e3ad910d597037910ed57005169e2f8",
"semantic_hash": ""
},
"app/clinic/[slug]/page.js": {
@@ -405,7 +405,7 @@
"semantic_hash": ""
},
"app/doctor/[slug]/page.js": {
"mtime": 1785044477.0383642,
"mtime": 1785390286.0929785,
"ast_hash": "bf73e97801745d1f7d3c5b5b8d2bc8de",
"semantic_hash": ""
},
@@ -625,13 +625,13 @@
"semantic_hash": ""
},
"components/blog/detail/index.js": {
"mtime": 1785166238.324126,
"ast_hash": "9ac790637a46dc59c6b5e5c3faf539d1",
"mtime": 1785321814.7924728,
"ast_hash": "129d178826d0458b8359d378325e98fb",
"semantic_hash": ""
},
"components/blog/head/index.js": {
"mtime": 1785166181.3036282,
"ast_hash": "95505c8593f351fc86101198f4a0394e",
"mtime": 1785321745.6454604,
"ast_hash": "41c7e5db9766de55d3ba5de70e637f79",
"semantic_hash": ""
},
"components/blog/index.js": {
@@ -640,13 +640,13 @@
"semantic_hash": ""
},
"components/blog/relatedContent/Item.js": {
"mtime": 1785166045.5371826,
"ast_hash": "6d256c5de1f7663a2f6a8f76e8181caf",
"mtime": 1785321808.3911443,
"ast_hash": "e4d7207096bcb103da6a9d624ffafd6b",
"semantic_hash": ""
},
"components/blog/relatedContent/index.js": {
"mtime": 1783776875.690278,
"ast_hash": "5ab9429569a0f2ddcd3f7bc953262012",
"mtime": 1785321794.1455808,
"ast_hash": "1adc88c1ddf1e380ee7a05e48707cc7b",
"semantic_hash": ""
},
"components/blogs/Head.js": {
@@ -655,28 +655,28 @@
"semantic_hash": ""
},
"components/blogs/index.js": {
"mtime": 1784454676.4674513,
"ast_hash": "fbe480d6e3d2de8a89333ba113ee9984",
"mtime": 1785321684.1219358,
"ast_hash": "f882d5b7eb1f62d05e9e60675d0fe5ab",
"semantic_hash": ""
},
"components/blogs/latestArticles/Article.js": {
"mtime": 1785166038.3059208,
"ast_hash": "f46ca7aa88bbfd03bb9b5656e85801b4",
"mtime": 1785321822.4066951,
"ast_hash": "afdbb1a204687a130f1f8212a9f9d9e8",
"semantic_hash": ""
},
"components/blogs/latestArticles/index.js": {
"mtime": 1764813617.2898006,
"ast_hash": "21e130dc1ae1b1218de92cff9139884c",
"mtime": 1785321827.7459514,
"ast_hash": "64e96debcd5a9e024d9333aa6f3f5243",
"semantic_hash": ""
},
"components/blogs/title/ItemTitle.js": {
"mtime": 1783776875.6916404,
"ast_hash": "8e75e6d66e4b33b852dfcc568cd0d702",
"mtime": 1785321700.8509915,
"ast_hash": "9e480559035e25659cf372a2374108b9",
"semantic_hash": ""
},
"components/blogs/title/index.js": {
"mtime": 1783776875.6919754,
"ast_hash": "3bd4a6959c2aa3260e457fd85bc89d15",
"mtime": 1785321694.6543539,
"ast_hash": "3caabfa8aec534e4d966eec221a105d5",
"semantic_hash": ""
},
"components/clinic/components/about/ContentDetail.js": {
@@ -1290,7 +1290,7 @@
"semantic_hash": ""
},
"components/doctor/detailDoctor/Title.js": {
"mtime": 1784463399.0264654,
"mtime": 1785390230.8862507,
"ast_hash": "7c0add5b45ac48be79694fa07cc369ac",
"semantic_hash": ""
},
@@ -1310,7 +1310,7 @@
"semantic_hash": ""
},
"components/doctor/detailDoctor/cards/comments/index.js": {
"mtime": 1783837705.9181259,
"mtime": 1785390248.517856,
"ast_hash": "2441bb0ee5b5ce732c025c9d62a29a85",
"semantic_hash": ""
},
@@ -1350,18 +1350,18 @@
"semantic_hash": ""
},
"components/doctor/detailDoctor/index.js": {
"mtime": 1784454676.4695086,
"mtime": 1785390198.6057413,
"ast_hash": "8ac9b7256d5ced072351f10dc9fdfe67",
"semantic_hash": ""
},
"components/doctor/index.js": {
"mtime": 1784463423.1275866,
"mtime": 1785390214.3664908,
"ast_hash": "f74f47d714f1bd3fe0f8e8a5fa01824e",
"semantic_hash": ""
},
"components/doctor/poster/PosterLight.js": {
"mtime": 1784463446.2595298,
"ast_hash": "3685d1d29a7e24be560cb6f994f55bb9",
"mtime": 1785389990.876683,
"ast_hash": "8f392954b0d988237663ad0b9c791a3d",
"semantic_hash": ""
},
"components/doctor/poster/QrImg.js": {
@@ -1375,8 +1375,8 @@
"semantic_hash": ""
},
"components/doctor/poster/index.js": {
"mtime": 1784463446.2592826,
"ast_hash": "619b989fd7baba15912b62db0da2d78f",
"mtime": 1785389974.6539223,
"ast_hash": "9394bebdf67e38f37b3b83954b2892d5",
"semantic_hash": ""
},
"components/doctors/head/FilterLocate.js": {
@@ -2695,8 +2695,8 @@
"semantic_hash": ""
},
"services/response.js": {
"mtime": 1784454676.5209222,
"ast_hash": "def782ce4b119ca064b7fed204b04271",
"mtime": 1785321664.0579662,
"ast_hash": "9aeb29f5aaa325343aa5a10fdecccd1d",
"semantic_hash": ""
},
"services/services.test.js": {
@@ -3648,5 +3648,20 @@
"mtime": 1785167425.6682634,
"ast_hash": "38eecafd2e27b74b36fe34e820c479b8",
"semantic_hash": ""
},
"config/features.js": {
"mtime": 1785389938.8777816,
"ast_hash": "c437c1b648577f0ba38c46a58ab89f27",
"semantic_hash": ""
},
".claude/prompt/blog-category-breadcrumb-and-filter.md": {
"mtime": 1785321252.4877784,
"ast_hash": "4187e1c0548086a6381c3705170ee6aa",
"semantic_hash": ""
},
".claude/prompt/booking-engine-task-00b-service-mode.md": {
"mtime": 1785401488.2600272,
"ast_hash": "6f6014815f282908ac95eb61125f1af0",
"semantic_hash": ""
}
}