- ایجاد پرامپت برای رفع خطای 404 ناشی از لینک `/doctor/undefined` در سایتهای بهبهان و یاسوج.
- افزودن کامپوننت `CityHighlights` برای نمایش محتوای یکتا و آمار پزشکان و تخصصهای پرمراجعه در صفحهٔ اصلی هر شهر.
- بهروزرسانی تستهای مربوط به کامپوننتهای `ItemDoctor` و `CityHighlights` برای اطمینان از عدم وجود لینکهای نامعتبر و نمایش صحیح اطلاعات.
- ایجاد سند جدید برای مستندسازی خطاهای Search Console که باگ نیستند و نیاز به رفع ندارند.
- افزودن تستهای واحد برای توابع `buildCityIntro` و دیگر توابع مرتبط با تولید متن یکتا برای صفحات لیست.
- Introduced SpecialtyChips component to manage the display of doctor's specialties with a primary specialty and a count of additional specialties.
- Updated ItemDoctor component to utilize SpecialtyChips for better UI presentation.
- Enhanced PosterLight and Poster components to display primary specialties and a text line for sub-specialties.
- Implemented nextSpecialtyFilter function to improve specialty selection logic in the Content component.
- Updated search functionality to allow searching by both doctor name and specialty.
- Added new specialties to specialties.json for better coverage.
- Created sync-specialties script to synchronize specialties data with the backend during build.
- Added tests for new components and helper functions to ensure functionality and reliability.
Companion to clinicpro's doctor-multi-specialty-search prompt, which is already
merged and now returns specialties[].parent_id plus descendant-aware
specialty_id filtering.
Records what the code inspection turned up, so the implementation does not
rediscover it: data/specialties.json is a stale snapshot missing the five newest
children of جراحی عمومی, which is why /specialties/جراح-گوارش 404s and why the
parent/child UI cannot be built until it is synced at build time; the filters
modal force-selects the first child when a group is picked, silently narrowing
the search; and both poster variants slice specialties to a blind four, which
overflows the fixed 1080x1350 frame.
Not executed yet — committed so the plan is not carried around untracked.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Added `getBlogTagFacets` API call to fetch blog tags based on city scope.
- Updated `BlogsPage` to read selected tag from URL and handle tag changes with URL updates.
- Modified `Title` component to display tags from the new API and reflect active tag state.
- Enhanced breadcrumb navigation to link categories to their respective pages.
- Adjusted related content section to display articles from the same category and fixed layout issues.
- Corrected heading hierarchy across various components for better SEO compliance.
- Ensured consistent styling and spacing in related content items.
- Updated modification times and AST hashes for several files in the manifest.json.
- Added new entries for `app/api/revalidate/route.js`, `components/blog/detail/Faq.js`, `components/blog/detail/Sources.js`, and other files related to blog functionality.
- Introduced a new AST cache file for the blog frontend sync and default cover prompt, including detailed node and edge relationships.
- Introduced a new script `make-blog-cover.mjs` to create a default cover image for blog posts.
- The image is generated in PNG format with dimensions 1200x630, suitable for Open Graph.
- Utilizes the site's branding colors and logo from `public/nobat724.svg`.
- Includes custom font styling using the Vazirmatn font.
- The generated image is saved to `public/assets/images/blog-default-cover.png`.
- Updated modification times and AST hashes for several JavaScript files in the app/blog, app/component, app/doctor, and components/common directories.
- Added a new AST cache file for a data JSON that was skipped due to a non-object root.
Deactivated doctors are now absent from the public list, but their
/doctor/{uuid} page still loaded. getDoctor() now treats the backend's
raw `is_active === false` as not-found, so the profile 404s like the
list — matching the site's "hide inactive doctors" behavior.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The public list GET /api/v1/doctors only excluded inactive doctors
when an explicit `active` filter was passed; with no param it returned
everyone (deactivated doctors just ranked lower). Deactivated doctors
(admin toggled active_doctor_appointment off) leaked onto nobat724.
- DoctorRepository::findWithFilters: default (no `active` param) now
filters activeDoctorAppointment = true. The active=1 (bookable) and
active=0 (admin, inactive-only) escape hatches are unchanged.
- Doctor::toDetailArray: expose raw `is_active` (= activeDoctorAppointment,
independent of schedule) so public clients can 404 a deactivated
doctor's profile page; distinct from `active` (flag && has_schedule).
- Tests + docs/api/doctor.md updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Updated mtime and ast_hash for several files in manifest.json
- Added new AST cache files for the clinic contact info fix and maintenance mode client prompts
The backend now answers 503 with code MAINTENANCE_MODE while maintenance is
on. Without this change a visitor got a red error toast over a broken page
client-side, and a silently empty page server-side, because fetchReq discards
the status and returns null on any failure.
- lib/maintenance.js detects the state by BOTH status 503 and the error code;
a bare 503 can come from a reverse proxy and is not maintenance
- The axios interceptor checks it before the 401 branch, so a maintenance
response never triggers the refresh-token path or logs the user out
- fetchReq redirects to /maintenance, with a silentMaintenance opt-out used by
getStateInfo: that one runs inside generateMetadata and while rendering the
maintenance page itself, where a redirect is either ineffective or loops
- redirect() works by throwing, so the try/catch blocks in the doctors,
clinics and specialties pages now rethrow NEXT_REDIRECT instead of
swallowing it
- clinicApi.js handles 503 too; it previously rendered maintenance as a clinic
with zero doctors
- The page reuses the existing 404 design and is marked noindex
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Updated community IDs for various components in graph.json to reflect correct associations.
- Added new function `getPublishedDoctors()` in app/sitemap.js and established relationships with existing functions.
- Adjusted source locations for several functions in app/sitemap.js to ensure accurate mapping.
- Enhanced canonical URL handling in lib/getCanonicalUrl.js to prevent incorrect canonicalization for paginated specialty pages.
- Updated manifest.json with new modification times and AST hashes for affected files.
- Created a new JSON file for the blog city scoping activation prompt, including nodes and edges representing the document structure.
- Added a new JSON file for the SEO post-deploy verification prompt, detailing nodes and edges related to SEO verification tasks.
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>
- Implemented canonical URL strategies for city-specific domains and entities.
- Added helper functions for domain and city resolution.
- Created tests for canonical URL generation and domain resolution.
- Introduced entity quality checks for doctors and clinics to ensure meaningful content.
- Developed unique introductory texts for listing pages to avoid duplicate content.
- Established robots.txt policies for listing pages to manage indexing based on user filters.
- Enhanced specialty content with dynamic introductions and FAQs to improve SEO.
The profile decided "نوبتدهی غیرفعال است" from `doctor.active` alone, while the
page already had `booking_locations` — the more precise source, since the backend
only returns locations that are genuinely bookable. The two could disagree, and
for a doctor bookable only at a clinic they did.
A shared `bookingState` helper now drives both the desktop card and the mobile
bar: any location means bookable, the label comes from the earliest
`next_available_at`, and locations with no capacity yet read as "فعلاً نوبت خالی
ندارد" rather than disabled. With no locations at all it falls back to the
previous `doctor.active` / `free_turn` fields.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>