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>
149 lines
8.9 KiB
Markdown
149 lines
8.9 KiB
Markdown
<div dir="rtl" markdown="1">
|
||
|
||
# تأیید زندهٔ فیکسهای 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، اینها را اجرا کن و **خروجی واقعی هر کدام را در گزارش نقل کن**:
|
||
|
||
```bash
|
||
# 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`.
|
||
|
||
</div>
|