fix: update site_name for city record to remove redundancy

This commit is contained in:
hamed
2026-07-03 12:35:30 +03:30
parent aa75fb858f
commit 3fdd8b3e8b
2 changed files with 179 additions and 1 deletions
+178
View File
@@ -0,0 +1,178 @@
# بهینه‌سازی SEO تک‌تک شهرها در city.json (سطح حرفه‌ای)
## پروژه
`nobat724_front` (سایت عمومی نوبت‌دهی، چند-دامنه‌ای — هر شهر یک دامنه)
## نقش
تو یک **متخصص حرفه‌ای SEO فارسی/محلی (Local SEO)** هستی. خروجی باید در سطح یک آژانس سئوی حرفه‌ای باشد: یکتا، کلیدواژه‌محور بدون stuffing، با رعایت طول بهینه، CTR-optimized.
## زمینه
`data/city.json` منبع واحد SEO هر دامنه‌ی شهری است. `app/layout.js``generateMetadata()` مقادیر این فایل را مستقیم به تگ‌های متا تبدیل می‌کند. یعنی کیفیت SEO هر شهر = کیفیت فیلدهای متنی همان رکورد در این فایل.
۳۴ رکورد وجود دارد (۳۳ شهر + رکورد اصلی `id:600` دامنه `nobat724.com`). محتوای فعلی با یک **قالب یکسان کلون** شده — جملات تقریباً تکراری بین شهرها (خطر duplicate content) و ضعیف.
## مشکل / هدف
دو مشکل بحرانی:
1. **فیلد `title` در هیچ‌کدام از ۳۴ رکورد وجود ندارد.** `layout.js` اول `matchedCity?.title` را می‌خواند؛ چون نیست، همه شهرها به یک قالب یکسان fallback می‌کنند → تایتل‌های تقریباً تکراری. **باید به هر رکورد فیلد `title` یکتا و بهینه اضافه شود.**
2. `description` / `keywords` / `slogan` / `footer_description` قالبی و تکراری‌اند → باید هرکدام برای هر شهر **بازنویسی یکتا و بهینه** شوند.
هدف: هر ۳۴ رکورد، ۵ فیلد متنی SEO در بالاترین کیفیت، **بدون تکرار جمله بین شهرها**.
## فایل‌های مرتبط
| فایل | نقش |
|------|-----|
| `data/city.json` | تنها فایلی که ویرایش می‌شود — رکورد هر شهر |
| `app/layout.js` | مصرف‌کننده فیلدها (فقط برای درک، ویرایش نشود مگر task ۶) |
## وضعیت فعلی
مصرف فیلدها در `app/layout.js`:
```js
const title =
matchedCity?.title || // ← این فیلد وجود ندارد!
(matchedCity?.name
? `نوبت‌دهی آنلاین پزشکان ${matchedCity.name} | نوبت 724`
: "نوبت 724 | سیستم نوبت‌دهی آنلاین پزشکی");
const description = matchedCity?.description || "...";
// keywords: matchedCity.keywords
// openGraph.siteName: matchedCity.site_name
```
نمونه رکورد فعلی (تکراری/قالبی):
```json
{
"id": 113, "name": "اهواز", "site_name": "اهواز نوبت",
"province_name": "خوزستان",
"description": "اهواز نوبت، سامانه نوبت‌دهی آنلاین در اهواز و استان خوزستان. امکان جستجو و رزرو نوبت در مراکز درمانی. اهواز نوبت بهترین راه دسترسی به پزشکان متخصص است.",
"slogan": "سامانه هوشمند نوبت‌دهی پزشکان اهواز",
"keywords": "رزرو نوبت اهواز, پزشکان خوزستان, کلینیک‌های اهواز, بیمارستان‌های اهواز, متخصصین پزشکی اهواز",
"footer_description": "اهواز نوبت، سامانه جامع نوبت‌دهی پزشکی در استان خوزستان. رزرو نوبت از پزشکان و مراکز درمانی اهواز بدون نیاز به مراجعه حضوری."
}
```
## فهرست ۳۴ رکورد (همه باید پردازش شوند)
| id | شهر | استان | دامنه |
|----|-----|-------|-------|
| 129 | اراک | مرکزی | arak-nobat.ir |
| 103 | اردبیل | اردبیل | ardabil-nobat.ir |
| 102 | ارومیه | آذربایجان غربی | urmia-nobat.ir |
| 104 | اصفهان | اصفهان | esf-nobat.ir |
| 113 | اهواز | خوزستان | ahvaz-nobat.ir |
| 106 | ایلام | ایلام | ilam-nobat.ir |
| 112 | بجنورد | خراسان شمالی | bojnord-nobat.ir |
| 130 | بندرعباس | هرمزگان | bandar-nobat.ir |
| 107 | بوشهر | بوشهر | bushehr-nobat.ir |
| 110 | بیرجند | خراسان جنوبی | birjand-nobat.ir |
| 101 | تبریز | آذربایجان شرقی | tabriz-nobat.ir |
| 108 | تهران | تهران | tehran-nobat.ir |
| 127 | خرم‌آباد | لرستان | lorestan-nobat.ir |
| 126 | رشت | گیلان | rasht-nobat.ir |
| 116 | زاهدان | سیستان و بلوچستان | zahedan-nobat.ir |
| 114 | زنجان | زنجان | zanjan-nobat.ir |
| 128 | ساری | مازندران | sari-nobat.ir |
| 115 | سمنان | سمنان | semnan-nobat.ir |
| 120 | سنندج | کردستان | sanandaj-nobat.ir |
| 109 | شهرکرد | چهارمحال و بختیاری | shkord-nobat.ir |
| 117 | شیراز | فارس | shiraz-nobat.ir |
| 118 | قزوین | قزوین | qazvin-nobat.ir |
| 119 | قم | قم | qom-nobat.ir |
| 105 | کرج | البرز | karaj-nobat.ir |
| 121 | کرمان | کرمان | kerman-nobat.ir |
| 122 | کرمانشاه | کرمانشاه | kermanshah-nobat.ir |
| 125 | گرگان | گلستان | golestan-nobat.ir |
| 111 | مشهد | خراسان رضوی | mashhad-nobat.ir |
| 131 | همدان | همدان | hamadan-nobat.ir |
| 123 | یاسوج | کهگیلویه و بویراحمد | yasuj-nobat.ir |
| 132 | یزد | یزد | yazd-nobat.ir |
| 133 | دهدشت | کهگیلویه و بویراحمد | dehdasht-nobat.ir |
| 134 | بهبهان | خوزستان | behbahan-nobat.ir |
| 600 | نوبت 724 (برند اصلی) | — | nobat724.com |
## وظایف
### ۱. افزودن فیلد `title` یکتا به هر رکورد (مهم‌ترین)
بعد از `site_name` در هر رکورد، فیلد `title` اضافه کن.
**قواعد `title`:**
- طول: **۵۰–۶۰ کاراکتر** (حداکثر ~۶۰ برای عدم truncate در گوگل).
- کلیدواژه اصلی **اول** جمله: «نوبت‌دهی آنلاین پزشکان {شهر}» یا واریانت.
- برند در انتها با جداکننده `|`: `... | نوبت ۷۲۴`.
- **یکتا بین شهرها** — فقط جای‌گذاری اسم شهر کافی نیست؛ ساختار/کلمات را بین گروه‌ها متنوع کن (مثلاً برخی «رزرو نوبت پزشک {شهر}»، برخی «نوبت اینترنتی دکتر {شهر}»).
- بدون stuffing، خوانا، طبیعی.
مثال طلایی:
```json
"title": "نوبت‌دهی آنلاین پزشکان اهواز | رزرو نوبت دکتر | نوبت ۷۲۴"
```
### ۲. بازنویسی `description` (متا دیسکریپشن)
**قواعد:**
- طول: **۱۵۰–۱۶۰ کاراکتر** (نه کمتر از ۱۲۰، نه بیشتر از ۱۶۵).
- کلیدواژه اصلی front-load شده در ابتدای جمله.
- شامل: نام شهر + استان + اشاره به تخصص‌ها/مراکز درمانی + **CTA** («همین حالا رزرو کنید» / «آنلاین نوبت بگیرید»).
- **یکتا** — هیچ دو شهری جمله‌ی یکسان نداشته باشند. زاویه‌ی متن را متنوع کن (یکی روی سرعت، یکی روی تنوع پزشکان، یکی روی ۲۴ساعته‌بودن).
- بدون تکرار بیش از حد اسم شهر (حداکثر ۲ بار).
مثال طلایی:
```json
"description": "با نوبت اهواز، آنلاین از پزشکان متخصص و عمومی خوزستان نوبت بگیرید. جستجوی دکتر بر اساس تخصص، بیمه و منطقه در اهواز؛ رزرو نوبت ۲۴ساعته بدون مراجعه حضوری. همین حالا نوبت خود را ثبت کنید."
```
### ۳. بهینه‌سازی `keywords`
- ۶–۹ عبارت هدفمند، جدا با `, `.
- ترکیب: `نوبت {شهر}`، `دکتر {شهر}`، `پزشک متخصص {شهر}`، `رزرو نوبت اینترنتی {شهر}`، `کلینیک {شهر}`، `بهترین پزشک {استان}`، عبارات intent-محور («نوبت آنلاین دکتر»).
- بدون تکرار عین‌به‌عین عبارات بین شهرها (اسم شهر متفاوت کافی نیست برای long-tailها).
### ۴. بازنویسی `slogan` یکتا
- کوتاه (۴–۸ کلمه)، جذاب، دارای کلیدواژه شهر، متمایز بین شهرها.
- نمونه: `"در اهواز، نوبت دکتر فقط با چند کلیک"`.
### ۵. بازنویسی `footer_description` یکتا
- ۱–۲ جمله، محلی، دارای شهر+استان، متفاوت از `description` (نه کپی).
- برای فوتر — لحن معرفی برند محلی.
### ۶. (اختیاری، اگر کاربر خواست) بهبود فنی در `layout.js`
اگر زمان بود، این‌ها را هم پیشنهاد بده (اما JSON اولویت است):
- `openGraph.images` و `twitter.images` الان هاردکد `nobat724.com/assets/images/logo.png` است — می‌توان per-city کرد.
- JSON-LD فعلی فقط `Organization` + `WebSite` با `siteUrl` ثابت `nobat724.com` است؛ افزودن `MedicalBusiness`/`LocalBusiness` per-city با دامنه و نام شهر، سیگنال Local SEO قوی می‌دهد.
### ۷. رکورد برند اصلی (`id: 600`)
این رکورد شهر نیست (دامنه‌ی مادر `nobat724.com`, `province_name: null`). برایش `title`/`description`/`keywords` سراسری و برندمحور بنویس (نه شهرمحور): تمرکز روی «سامانه سراسری نوبت‌دهی آنلاین پزشکی ایران».
## نکات مهم
- **فقط `data/city.json` ویرایش شود** (به‌جز task ۶ اختیاری). ساختار JSON، ترتیب رکوردها، و فیلدهای `id`, `uuid`, `status`, `weight`, `province_id`, `province_name`, `representation_id`, `contact_phone`, `email`, `domain`, `social_media`, `logo_url` **دست‌نخورده** بمانند.
- فیلد `title` جدید را بعد از `site_name` قرار بده (سازگاری با ترتیب منطقی).
- **اعداد در `title` فارسی** باشند (`۷۲۴` نه `724`) برای هماهنگی با UI فارسی — مگر اینکه در برند لاتین لازم باشد.
- **یکتایی سراسری**: بعد از اتمام، هیچ دو رکوردی نباید `title` یا `description` با ساختار جمله‌ی یکسان (فقط تغییر اسم شهر) داشته باشند. حداقل ۳–۴ الگوی متنی متفاوت بین ۳۴ رکورد بچرخان.
- **صحت جغرافیایی**: `province_name` هر رکورد را به‌عنوان واقعیت بپذیر (قبلاً بهبهان=خوزستان، دهدشت=کهگیلویه اصلاح شده). محتوای استان را با همین مقدار بنویس.
- بعد از ویرایش، **اعتبار JSON را تأیید کن**:
```bash
python3 -c "import json; d=json.load(open('data/city.json')); print('valid', len(d)); \
t=[c.get('title') for c in d]; assert all(t), 'missing title'; \
print('unique titles:', len(set(t))==len(t)); \
print('unique descriptions:', len(set(c['description'] for c in d))==len(d))"
```
باید: valid، همه title دارند، titleها و descriptionها یکتا.
- زبان فارسی رسمی و روان، RTL، بدون غلط املایی. اسامی شهر/استان دقیقاً مطابق فایل.
- این تغییر داده است، نه endpoint API → نیازی به به‌روزرسانی `docs/api/` نیست.
- بعد از ویرایش، یک build سریع بزن که فایل درست پارس می‌شود: `npm run build` (یا حداقل import شدن JSON).
```
+1 -1
View File
@@ -675,7 +675,7 @@
"id": 600,
"uuid": "7bfbad3c-646b-11f1-84d7-f26ca1845824",
"name": "نوبت 724",
"site_name": "نوبت 724 نوبت",
"site_name": "نوبت 724",
"status": 1,
"weight": 0,
"province_id": null,