Add AST JSON file for blog category breadcrumb and filter prompt with detailed nodes and edges
This commit is contained in:
@@ -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` بساز و در چکلیست ثبت کن.
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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._
|
||||
graphify-out/cache/ast/v0.8.44/8886fd414c3128992605fa57a2a61a9597357c51c0690d130678fc09371fba5c.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/971ea738fd4afba12d4dc73c5791958baf674c845e26104d4e5d9f1e92ce9367.json
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1136
-146
File diff suppressed because it is too large
Load Diff
+48
-33
@@ -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": ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user