From 3fdd8b3e8bc4587dfc98018d9718f3680c4a5e5a Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Fri, 3 Jul 2026 12:35:30 +0330 Subject: [PATCH] fix: update site_name for city record to remove redundancy --- .claude/prompt/city-seo-optimization.md | 178 ++++++++++++++++++++++++ data/city.json | 2 +- 2 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 .claude/prompt/city-seo-optimization.md diff --git a/.claude/prompt/city-seo-optimization.md b/.claude/prompt/city-seo-optimization.md new file mode 100644 index 0000000..a765b40 --- /dev/null +++ b/.claude/prompt/city-seo-optimization.md @@ -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). +``` diff --git a/data/city.json b/data/city.json index da11834..62c2548 100644 --- a/data/city.json +++ b/data/city.json @@ -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,