Files
hamed 92b8f474c1 Add SEO fields to city.json for local branding optimization
- Introduced a new `title` field for each city record, incorporating local brand names.
- Rewrote `slogan` for each city to reflect startup tone and include city keywords.
- Optimized `keywords` with relevant local and long-tail search terms.
- Ensured compliance with SEO best practices and maintained JSON structure.
2026-07-08 11:57:31 +03:30

127 lines
8.1 KiB
Markdown

# بهینه‌سازی SEO فیلدهای city.json — افزودن title برند‌دار + بازنویسی slogan و keywords
## پروژه
`nobat724_front`
## زمینه
سایت چند-دامنه‌ای است: هر شهر دامنه خودش را دارد (`tabriz-nobat.ir`، `esf-nobat.ir`، ...) و همه SEO هر شهر از `data/city.json` تغذیه می‌شود. `app/layout.js` در `generateMetadata` اول `matchedCity?.title` را می‌خواند و چون **هیچ‌کدام از ۳۴ رکورد شهر فیلد `title` ندارند**، همیشه به الگوی fallback با برند سراسری «نوبت 724» می‌افتد — در حالی که هر شهر برند محلی خودش (`site_name` مثل «اراک نوبت») را دارد. `slogan` هم متن قابل ایندکس صفحات است (hero صفحه اصلی، about-us، پوستر پزشک) و باید هم مفهوم استارت‌آپی داشته باشد هم کلمه کلیدی شهر.
## مشکل / هدف
نقش: متخصص حرفه‌ای SEO فارسی (local SEO سلامت/نوبت‌دهی پزشکی).
سه فیلد در هر ۳۴ رکورد `data/city.json` باید ساخته/بازنویسی شود:
1. **`title`** (فیلد جدید): عنوان متا برای هر شهر که **حتماً برند محلی (`site_name`) در آن باشد**. الگو:
`نوبت‌دهی آنلاین پزشکان <name> | <site_name>`
مثال هدف: `"title": "نوبت‌دهی آنلاین پزشکان اراک | اراک نوبت"`
2. **`slogan`**: بازنویسی با مفهوم استارت‌آپی + SEO (کلمه کلیدی شهر داخلش باشد).
3. **`keywords`**: بهینه‌سازی با کلمات کلیدی محلی و long-tail واقعی جستجوی فارسی.
## فایل‌های مرتبط
| فایل | نقش |
|------|-----|
| `nobat724_front/data/city.json` | **تنها فایل قابل تغییر** — ۳۴ رکورد شهر |
| `nobat724_front/app/layout.js` | مصرف‌کننده — فقط بخوان، تغییر نده |
| `nobat724_front/components/home/TextHeader.js` | نمایش `slogan` در hero صفحه اصلی |
| `nobat724_front/components/aboutUs/index.js` | نمایش `slogan` در about-us |
| `nobat724_front/components/doctor/poster/index.js` | نمایش `slogan` در پوستر پزشک |
## وضعیت فعلی
`app/layout.js` (تغییر نمی‌کند — از قبل `title` را می‌خواند):
```js
const title =
matchedCity?.title ||
(matchedCity?.name
? `نوبت‌دهی آنلاین پزشکان ${matchedCity.name} | نوبت 724`
: "نوبت 724 | سیستم نوبت‌دهی آنلاین پزشکی");
```
نمونه رکورد فعلی `data/city.json` (فیلد `title` وجود ندارد):
```json
{
"id": 101,
"name": "تبریز",
"site_name": "تبریز نوبت",
"description": "نوبت تبریز، سامانه تخصصی نوبت‌دهی پزشکی شمال‌غرب کشور است. ...",
"slogan": "سریع‌ترین نوبت‌دهی پزشکی تبریز",
"domain": "tabriz-nobat.ir",
"keywords": "نوبت تبریز, دکتر تبریز, پزشک متخصص تبریز, رزرو نوبت اینترنتی تبریز, کلینیک تبریز, بیمارستان تبریز, نوبت آنلاین آذربایجان شرقی",
"province_id": 1
}
```
## وظایف
### ۱. افزودن فیلد `title` به هر ۳۴ رکورد
بعد از فیلد `site_name` (یا کنار فیلدهای SEO) در هر رکورد اضافه کن:
```json
"title": "نوبت‌دهی آنلاین پزشکان تبریز | تبریز نوبت"
```
قواعد:
- الگوی ثابت: `نوبت‌دهی آنلاین پزشکان <name> | <site_name>` — کلمه کلیدی اصلی اول، برند آخر.
- جداکننده ` | ` با فاصله در دو طرف (مثال کاربر فاصله نداشت — نسخه استاندارد با فاصله بنویس).
- طول کل ≤ ۶۰ کاراکتر (برای عدم truncate در گوگل). همه نام‌های شهر ایران در این الگو جا می‌شوند.
- `name` و `site_name` را **دقیقاً از همان رکورد** بردار — دست‌ساز ننویس (مثلاً اصفهان → «اصفهان نوبت»).
- نیم‌فاصله در «نوبت‌دهی» حفظ شود (‌ = U+200C).
### ۲. بازنویسی `slogan` هر ۳۴ رکورد — استارت‌آپی + SEO
قواعد:
- حتماً نام شهر + یکی از کلمات کلیدی (نوبت / پزشک / دکتر) داخل جمله باشد — این متن در H-level صفحه اصلی ایندکس می‌شود.
- لحن استارت‌آپی: تمرکز بر سرعت، سادگی، دسترسی ۲۴ساعته، حذف صف — نه شعار خشک اداری.
- کوتاه: ۴ تا ۸ کلمه؛ برای هر شهر **یکتا** (duplicate content بین ۳۴ دامنه ممنوع — گوگل دامنه‌ها را جدا ایندکس می‌کند ولی الگوی تکراری ارزش برند را می‌کشد).
- نمونه‌های جهت‌دهنده (کپی نکن، برای هر شهر متفاوت بساز):
- «نوبت دکتر در تبریز، ساده‌تر از همیشه»
- «پزشکان اصفهان، یک کلیک تا ویزیت»
- «سلامت اهواز، بدون صف و انتظار»
### ۳. بهینه‌سازی `keywords` هر ۳۴ رکورد
قواعد:
- ۷ تا ۱۰ عبارت، جدا با `, ` (فرمت فعلی حفظ شود — string، نه array).
- ترکیب اجباری برای هر شهر:
- `نوبت دکتر <شهر>` و `نوبت‌دهی آنلاین <شهر>` (پرجستجوترین الگوهای فارسی)
- `دکتر خوب <شهر>` (الگوی long-tail رایج)
- `پزشک متخصص <شهر>`
- یک عبارت استانی (مثل `نوبت آنلاین آذربایجان شرقی`) از `state.json` با `province_id`
- برند محلی: `<site_name>` (مثل `تبریز نوبت`)
- عبارت‌های کم‌ارزش/تکراری فعلی (مثل `کلینیک <شهر>, بیمارستان <شهر>` خالی) را با long-tail هدفمند جایگزین کن: `رزرو نوبت پزشک <شهر>`، `نوبت اینترنتی دکتر <شهر>`.
- keyword stuffing ممنوع — هر عبارت باید نیت جستجوی واقعی داشته باشد.
### ۴. اعتبارسنجی
```bash
cd nobat724_front
node -e "const d=require('./data/city.json'); \
console.assert(d.length===34,'count'); \
d.forEach(c=>{ \
if(!c.title) throw new Error('no title: '+c.name); \
if(!c.title.includes(c.site_name)) throw new Error('title missing site_name: '+c.name); \
if(c.title.length>60) throw new Error('title too long: '+c.name); \
if(!c.slogan.includes(c.name)&&!c.keywords.includes(c.name)) throw new Error('city name missing: '+c.name); \
}); \
const slogans=new Set(d.map(c=>c.slogan)); \
console.assert(slogans.size===34,'duplicate slogans'); \
console.log('OK')"
npm run build # فقط اگر سریع بود؛ حداقل: node parse بالا باید OK بدهد
```
## نکات مهم
- **فقط `data/city.json` تغییر می‌کند.** `app/layout.js` از قبل `matchedCity?.title` را می‌خواند؛ hero و about-us هم `slogan` را مستقیم نمایش می‌دهند — هیچ تغییر کدی لازم نیست.
- ساختار JSON دست نخورد: هیچ فیلدی حذف/تغییرنام نشود، ترتیب رکوردها حفظ شود، encoding UTF-8 و نیم‌فاصله‌ها سالم بمانند.
- `description` و `footer_description` در scope این پرامپت نیستند — ولی اگر با title/slogan جدید تناقض آشکار داشتند (مثلاً برند متفاوت)، فقط گزارش بده، تغییر نده.
- نام استان هر شهر از `data/state.json` با `province_id` قابل استخراج است.
- برای شهرهایی که `site_name` آن‌ها با الگوی `<شهر> نوبت` نیست، همان مقدار واقعی فایل ملاک است.
- زبان همه مقادیر: فارسی (محصول تماماً فارسی/RTL است).