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>
8.9 KiB
تأیید زندهٔ فیکسهای 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).
۴. بازبینی بصری
صفحات تغییریافته را با نسخهٔ قبل مقایسه کن. تغییر تگها باید بدون اثر بصری باشد:
| صفحه | تغییر | انتظار |
|---|---|---|
/ |
خط برند h1 → p؛ شعار h2 → h1 |
ظاهر یکسان |
/doctors |
متن دکمهٔ موقعیت h1 → span + h1 جدید و پاراگراف مقدمه |
دکمه بدون تغییر؛ عنوان و متن جدید بالای لیست |
/clinics |
عنوان پویا + پاراگراف مقدمه + breadcrumb با «خانه» | «خانه >» به breadcrumb اضافه شده |
/clinic/[id] |
۳ عنوان بخش h1 → h2؛ 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.