12 KiB
بهینهسازی 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) و ضعیف.
مشکل / هدف
دو مشکل بحرانی:
- فیلد
titleدر هیچکدام از ۳۴ رکورد وجود ندارد.layout.jsاولmatchedCity?.titleرا میخواند؛ چون نیست، همه شهرها به یک قالب یکسان fallback میکنند → تایتلهای تقریباً تکراری. باید به هر رکورد فیلدtitleیکتا و بهینه اضافه شود. description/keywords/slogan/footer_descriptionقالبی و تکراریاند → باید هرکدام برای هر شهر بازنویسی یکتا و بهینه شوند.
هدف: هر ۳۴ رکورد، ۵ فیلد متنی SEO در بالاترین کیفیت، بدون تکرار جمله بین شهرها.
فایلهای مرتبط
| فایل | نقش |
|---|---|
data/city.json |
تنها فایلی که ویرایش میشود — رکورد هر شهر |
app/layout.js |
مصرفکننده فیلدها (فقط برای درک، ویرایش نشود مگر task ۶) |
وضعیت فعلی
مصرف فیلدها در app/layout.js:
const title =
matchedCity?.title || // ← این فیلد وجود ندارد!
(matchedCity?.name
? `نوبتدهی آنلاین پزشکان ${matchedCity.name} | نوبت 724`
: "نوبت 724 | سیستم نوبتدهی آنلاین پزشکی");
const description = matchedCity?.description || "...";
// keywords: matchedCity.keywords
// openGraph.siteName: matchedCity.site_name
نمونه رکورد فعلی (تکراری/قالبی):
{
"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، خوانا، طبیعی.
مثال طلایی:
"title": "نوبتدهی آنلاین پزشکان اهواز | رزرو نوبت دکتر | نوبت ۷۲۴"
۲. بازنویسی description (متا دیسکریپشن)
قواعد:
- طول: ۱۵۰–۱۶۰ کاراکتر (نه کمتر از ۱۲۰، نه بیشتر از ۱۶۵).
- کلیدواژه اصلی front-load شده در ابتدای جمله.
- شامل: نام شهر + استان + اشاره به تخصصها/مراکز درمانی + CTA («همین حالا رزرو کنید» / «آنلاین نوبت بگیرید»).
- یکتا — هیچ دو شهری جملهی یکسان نداشته باشند. زاویهی متن را متنوع کن (یکی روی سرعت، یکی روی تنوع پزشکان، یکی روی ۲۴ساعتهبودن).
- بدون تکرار بیش از حد اسم شهر (حداکثر ۲ بار).
مثال طلایی:
"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/LocalBusinessper-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 را تأیید کن:
باید: valid، همه title دارند، titleها و descriptionها یکتا.
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))" - زبان فارسی رسمی و روان، RTL، بدون غلط املایی. اسامی شهر/استان دقیقاً مطابق فایل.
- این تغییر داده است، نه endpoint API → نیازی به بهروزرسانی
docs/api/نیست. - بعد از ویرایش، یک build سریع بزن که فایل درست پارس میشود:
npm run build(یا حداقل import شدن JSON).