Files
nobat724_front/.claude/prompt/seo-post-deploy-verification.md
T
hamedandClaude Opus 4.8 21f5f07bc6 chore(prompt): record SEO audit and split remaining work
P1-P11 of the live SEO audit are implemented and verified against a local
production build, so the audit file becomes a reference rather than a
task list: it now records what shipped, the root causes that differed
from the original hypotheses, and the deliberate trade-offs.

Remaining work is split into smaller prompts, ordered by dependency:

- seo-post-deploy-verification: the acceptance criteria were "curl on
  production" but were only run against a local build
- blog-city-scoping-activate: blocked on the backend blog city column
- sitemap-simplify-with-city: drops the 35-sweep workaround once the
  doctors list exposes city

Each names its blocking dependency and carries reference numbers so a
regression is visible.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 08:09:21 +03:30

8.9 KiB
Raw Blame History

تأیید زندهٔ فیکس‌های SEO بعد از deploy

پروژه

nobat724_front

زمینه

فیکس‌های ممیزی SEO (P1–P11 از seo-critical-fixes-live-audit.md) پیاده و تست شده‌اند، اما تأیید روی build محلی production انجام شد، نه روی دامنه‌های واقعی:

NEXT_PUBLIC_API_URL=https://clinic-pro.ir DEV_MODE=FALSE npm run build
NODE_TLS_REJECT_UNAUTHORIZED=0 npx next start -p 3111
# سپس curl با هدر Host برای شبیه‌سازی دامنه‌های شهری

معیارهای پذیرش اصلی «curl روی production» بودند. این پرامپت همان‌ها را روی دامنه‌های واقعی اجرا می‌کند.

دو نکتهٔ حیاتی قبل از تفسیر هر خروجی:

۱. DEV_MODE باید FALSE باشد. با DEV_MODE=TRUE کل سایت noindex, nofollow, nocache می‌گیرد و همهٔ تست‌های robots بی‌معنی می‌شوند. این مقدار در next.config.js از طریق env در زمان build درون کد جاسازی می‌شود — تغییر آن در runtime بی‌اثر است و نیاز به build مجدد دارد.

۲. تغییرات هنوز commit نشده‌اند (وضعیت کاری). قبل از deploy باید commit و push شوند.

هدف

اجرای کامل معیارهای پذیرش روی production و ثبت خروجی واقعی؛ و در صورت اختلاف با نتایج محلی، ریشه‌یابی.

وظایف

۱. پیش از deploy

  • git status را بررسی کن؛ تغییرات SEO را commit کن.
  • تأیید کن build با DEV_MODE=FALSE انجام می‌شود.
  • تأیید کن NEXT_PUBLIC_API_URL در محیط production درست است (نه clinic-pro.ddev.site که مقدار فعلی .env محلی است).

۲. اجرای معیارهای پذیرش روی production

بعد از deploy، این‌ها را اجرا کن و خروجی واقعی هر کدام را در گزارش نقل کن:

# P3 — noindex سیستمیک لیست‌ها (باید خالی باشد)
for h in yasuj-nobat.ir tehran-nobat.ir yazd-nobat.ir nobat724.com; do
  for p in doctors clinics; do
    printf "%s/%s: " "$h" "$p"
    curl -s "https://$h/$p" | grep -o '<meta name="robots"[^>]*>' | head -1; echo
  done
done

# P3 — فیلتر واقعی باید noindex بماند
curl -s "https://yasuj-nobat.ir/doctors?name=x" | grep -o 'content="noindex[^"]*"'
curl -s "https://yasuj-nobat.ir/doctors?specialty=پوست%20و%20مو&gender=woman" | grep -o 'content="noindex[^"]*"'

# P4 — C1-a self-canonical
for h in yazd-nobat.ir nobat724.com yasuj-nobat.ir; do
  for p in "" doctors clinics specialties blogs; do
    printf "%s/%s -> " "$h" "$p"
    curl -s "https://$h/$p" | grep -o 'rel="canonical" href="[^"]*"'; echo
  done
done

# P4 — C1-c استاتیک مشترک → دامنهٔ اصلی
curl -s https://yasuj-nobat.ir/about-us   | grep -o 'rel="canonical" href="[^"]*"'
curl -s https://yasuj-nobat.ir/contact-us | grep -o 'rel="canonical" href="[^"]*"'

# P4 — C1-b موجودیت → دامنهٔ شهر خودش
D=beaca548-816f-4613-937d-360db01bd7c8   # شهر: یاسوج
C=9c163d69-0051-4745-a423-c830135b1c01   # شهر: یاسوج
curl -s "https://nobat724.com/doctor/$D"   | grep -o 'rel="canonical" href="[^"]*"'   # → yasuj-nobat.ir
curl -s "https://yazd-nobat.ir/doctor/$D"  | grep -o 'rel="canonical" href="[^"]*"'   # → yasuj-nobat.ir
curl -s "https://nobat724.com/clinic/$C"   | grep -o 'rel="canonical" href="[^"]*"'   # → yasuj-nobat.ir

# P4 — هماهنگی JSON-LD با canonical (تناقض زندهٔ قبلی)
curl -s "https://nobat724.com/clinic/$C" | grep -o '"url":"[^"]*"'

# M3-B — pagination
curl -s "https://yasuj-nobat.ir/doctors?page=2" | grep -o 'rel="canonical" href="[^"]*"'  # → ?page=2
curl -s "https://yasuj-nobat.ir/doctors?page=1" | grep -o 'rel="canonical" href="[^"]*"'  # → بدون page

# P6 — Soft-404 (هر چهار باید 404 بدهند)
for p in doctor/invalid-xxx clinic/invalid-xxx blog/invalid-xxx specialties/invalid-slug; do
  printf "%s -> " "$p"; curl -o /dev/null -s -w "%{http_code}\n" "https://nobat724.com/$p"
done
# و موجودیت معتبر باید 200 بماند
curl -o /dev/null -s -w "valid doctor: %{http_code}\n" "https://nobat724.com/doctor/$D"

# P7 — دقیقاً یک h1 و شهرمحور
for p in doctors clinics specialties; do
  printf "%s h1count=" "$p"; curl -s "https://yasuj-nobat.ir/$p" | grep -c "<h1"
  curl -s "https://yasuj-nobat.ir/$p" | grep -o "<h1[^>]*>[^<]*"
done
curl -s "https://yasuj-nobat.ir/clinic/$C" | grep -c "<h1"      # → 1 (قبلاً 4)
curl -s "https://nobat724.com/doctors" | grep -o "<title>[^<]*" # → بدون «نوبت 724» به‌جای شهر

# P8 — breadcrumb
curl -s https://yasuj-nobat.ir/clinics | grep -c 'aria-label="breadcrumb"'
curl -s https://yasuj-nobat.ir/clinics | grep -c 'BreadcrumbList'
curl -s "https://yasuj-nobat.ir/clinic/$C" | grep -c 'aria-label="breadcrumb"'

# P9 — صفحات فرود تخصص
curl -o /dev/null -s -w "%{http_code}\n" https://tehran-nobat.ir/specialties/dermatology       # → 200
curl -o /dev/null -s -w "%{http_code}\n" https://tehran-nobat.ir/specialties/invalid-slug      # → 404
curl -s "https://tehran-nobat.ir/doctors?specialty=پوست%20و%20مو" | grep -o 'rel="canonical" href="[^"]*"'
curl -s https://yasuj-nobat.ir/specialties | grep -c "doctors?specialty="   # → 0

# P5 — sitemap
curl -s https://nobat724.com/sitemap.xml   | grep -c "<loc>"
curl -s https://yasuj-nobat.ir/sitemap.xml | grep -c "<loc>"
curl -s https://yasuj-nobat.ir/sitemap.xml | grep -c "$D"        # → 1
curl -s https://nobat724.com/sitemap.xml   | grep -c "$D"        # → 0
curl -s https://yasuj-nobat.ir/sitemap.xml | grep -c "9c163d69"  # → 0 (کلینیک بی‌محتوا)

# P11 — FAQPage بدون شکستن اسکیماهای موجود
curl -s https://tehran-nobat.ir/specialties/dermatology | grep -c FAQPage
curl -s "https://yasuj-nobat.ir/doctor/$D" | grep -c FAQPage
curl -s "https://yasuj-nobat.ir/doctor/$D" | grep -c Physician   # باید سالم بماند

۳. اعتبارسنجی ساختاریافته

  • Rich Results Test گوگل روی یک صفحهٔ پزشک و یک صفحهٔ تخصص: تأیید کن Physician / MedicalClinic / Review / BreadcrumbList قبلی سالم‌اند و FAQPage معتبر است.
  • تأیید کن همهٔ بلوک‌های JSON-LD پارس می‌شوند (در تست محلی: ۰ خطای پارس، انواع Organization, WebSite, Physician, FAQPage, BreadcrumbList).

۴. بازبینی بصری

صفحات تغییریافته را با نسخهٔ قبل مقایسه کن. تغییر تگ‌ها باید بدون اثر بصری باشد:

صفحه تغییر انتظار
/ خط برند h1p؛ شعار h2h1 ظاهر یکسان
/doctors متن دکمهٔ موقعیت h1span + h1 جدید و پاراگراف مقدمه دکمه بدون تغییر؛ عنوان و متن جدید بالای لیست
/clinics عنوان پویا + پاراگراف مقدمه + breadcrumb با «خانه» «خانه >» به breadcrumb اضافه شده
/clinic/[id] ۳ عنوان بخش h1h2؛ breadcrumb بصری جدید تایپوگرافی یکسان

۵. Search Console

برای هر دامنهٔ درگیر: URL Inspection روی صفحات کلیدی (/، /doctors، /clinics، یک صفحهٔ پزشک، یک صفحهٔ تخصص) و ثبت sitemap. re-index چند هفته طول می‌کشد.

نکات مهم

  • رگرسیون احتمالی که باید مشخصاً چک شود: حذف loading.js از سه مسیر doctor/[slug]، clinic/[slug]، blog/[slug]. این کار برای رفع Soft-404 لازم بود (Suspense باعث می‌شد پاسخ با ۲۰۰ استریم شود و notFound() دیگر نتواند status را عوض کند). هزینه‌اش نبودِ اسکلت لودینگ هنگام ناوبری کلاینتی است — تجربهٔ کاربری این سه مسیر را عملاً بررسی کن.
  • اگر robots روی همهٔ صفحات noindex, nofollow, nocache بود، تقریباً قطعاً DEV_MODE=TRUE در build بوده — کد را دنبال نکن، اول build را بررسی کن.
  • ArvanCloud ممکن است روی دامنهٔ اصلی bot-challenge داشته باشد؛ اگر curl خروجی غیرمنتظره داد، قبل از دیباگ کد این را رد کن. (خارج از دامنهٔ اپ — DevOps)
  • sitemap دامنهٔ اصلی ~۱۳ ثانیه طول می‌کشد (۳۵ sweep برای تفکیک شهر). اگر timeout خورد، این انتظار است نه باگ — رفعش در sitemap-simplify-with-city.md.