Persian RTL clinic site with Meshkee blog, auth, sitemap config, and on-page SEO. Co-authored-by: Cursor <cursoragent@cursor.com>
8.8 KiB
8.8 KiB
Dr Asadian — AI / Project Context
Persian RTL rebuild of drasadian.com (مطب پوست، مو و زیبایی دکتر محمد اسدیان، قم). Keep this file current — other AI tools and later prompts read it first.
Source of truth
- Live site being cloned: https://www.drasadian.com/
- Prompt: Meshkee
basic-clonethenbackend(/api/v1/public/ai-prompts/dr-asadian/...) - Backend / Meshkee Website API: https://api.meshkee.com/docs/website
- OpenAPI: https://api.meshkee.com/docs/website/openapi.json
- Apex domain:
drasadian.com(nowww/api/customer/business) - Tenant:
GET /tenants/drasadian.com→businessId31 - Enabled modules:
products,blog,finance
Stack
- Next.js 15 (App Router) + React 19 + TypeScript
- Tailwind CSS v4 (
@import "tailwindcss"insrc/app/globals.css) + custom CSS - Language:
fa, direction:rtl - Fonts (downloaded from Meshkee CDN into
public/fonts/):kalameh(Persian UI: thin / regular / bold / black)a-glitch-in-time(English kickers)
Color palette (from live yoga3 theme CSS)
- Primary / headings / body:
#17543E - Theme gold (links, buttons, accents):
#D19C1D(hover#E9B948) - Mint button:
#D5E8E0on#17543Etext - Footer:
#195C46+public/images/footer/footer-bg.jpg - Page gray:
#F2F2F2 - Cards:
#F8F8F8 - Doctor band overlay:
#1F6C54 - Muted:
#A8A8A8
Routes
| Route | Purpose |
|---|---|
/ |
Homepage |
/services |
خدمات ما (original /services) — hair / skin / other |
/about |
درباره ما (original /aboutus) |
/contact |
تماس با ما (original /contactus) |
/gallery |
گالری تصاویر مطب (original /gallery) |
/blog |
مقالات — Meshkee GET /tenants/{domain}/blogs |
/blog/{id}/{titleSlug} |
مقاله — GET /tenants/{domain}/blogs/by-id/{id} |
/blog/{id} |
Redirects to canonical {id}/{titleSlug} |
Original also had /hair, /skin, /otherservices — not cloned as separate pages. Category cards on /services use in-page anchors (#hair, #skin, #other). Header: خدمات → /services, گالری → /gallery, مقالات → /blog.
Homepage order
- Hero slider (2 banners)
- Visible H1 intro (clinic name + description)
- Specialized service icons
- Latest blogs (8 from Meshkee). If the API has no posts yet, the original three cloned teasers are shown and link to
/blog - Testimonials (microneedling / microderm / e-light)
- Skin repair + about CTA band
Meshkee auth (customer portal)
- Logged-out user icon →
https://customer.drasadian.com(customerPortalUrlinsrc/lib/config.ts) - Logged-in:
{firstName lastName} عزیزwith dropdown:- پروفایل من →
https://customer.drasadian.com/profile - خروج (clears shared tokens)
- مدیریت وبسایت (admins/owners only) →
https://business.drasadian.comviaPOST /api/auth/handoff
- پروفایل من →
- Session:
src/lib/session.tsx+ cookiesmeshkee_customer_access_token/meshkee_customer_refresh_token(shared with customer portal on.drasadian.com) - Current user: website
GET /api/auth/me→ MeshkeeGET /auth/me - Header:
src/components/AccountMenu.tsx
Blog (Meshkee)
- List:
GET /tenants/drasadian.com/blogs?page=&pageSize= - Detail:
GET /tenants/drasadian.com/blogs/by-id/{id}(preferred). Slug route exists but is not used for public URLs. - Helpers:
src/lib/blog.ts(blogHref,blogImage,fetchBlogs,fetchBlogById) - Canonical URL:
/blog/{id}/{titleSlug}— Farsi title slug (spaces →-, keep Persian letters) - Homepage fetches
pageSize=8 - Listing paginates 12 per page
- Do not invent blog copy. Empty API → empty listing + homepage fallback teasers only
- Blog CMS HTML is rendered as
mainTextHtml(rich text)
Motion
- Header fades down on load
- Sections use
Reveal(src/components/Reveal.tsx) — Intersection Observer, one-shot - Children with
.stagger-childfade up in sequence (--idelay, 130ms steps) - Slider slides crossfade (1.15s)
prefers-reduced-motion: reducedisables the above
Inner page title
PageHerosits in.page-hero-rowwith a repeating minimal botanical-dot pattern (public/images/patterns/title-pattern.svg)
Original business data (do not invent replacements)
- Phone:
025-32907661 - Hours (contact): شنبه تا پنجشنبه، ۱۷ الی ۲۱
- Address: قم، میدان سپاه (جمهوری)، خیابان شهید اخلاقی، جنب مسجد امام حسن مجتبی، مطب دکترمحمد اسدیان
- Login icon →
https://customer.drasadian.com - Business dashboard →
https://business.drasadian.com - Instagram/Telegram URLs on the live site pointed to
/— no public handles cloned - Map coordinates were empty in site settings; contact page uses a Google Maps embed of the address
Content & assets
- Copy, hours table, testimonials, homepage teaser fallbacks:
src/data/site.ts - Logo:
public/images/logo.png(live themePMlhUjbrcj.png) - Favicon:
public/favicon.png(from logo; live favicon was empty) - Banners / icons / photos / gallery:
public/images/ - Fonts:
public/fonts/ - Remote CMS images:
meshkee-storage…,cdn.meshkee.com,c804387.parspack.net(seenext.config.ts)
Footer Meshkee credit
- Bottom row matches https://safeteb.com/ (site name + framed hover credit)
- Component:
src/components/Footer.tsx→.meshkee-credit - Styles:
src/app/globals.css - Links to
https://meshkee.com - Logo:
public/images/footer/MeshkeeLogo-White.png
Important paths
- Layout / shell:
src/app/layout.tsx(wrapsProviders+ session) - Header:
src/components/Header.tsx(split logo, RTL) - Account menu:
src/components/AccountMenu.tsx - Footer:
src/components/Footer.tsx - Home:
src/app/page.tsx,src/components/HeroSlider.tsx - Blog:
src/app/blog/page.tsx,src/app/blog/[id]/[slug]/page.tsx - Meshkee client:
src/lib/meshkee.ts,src/lib/meshkee-server.ts,src/lib/config.ts - Data:
src/data/site.ts
Env
NEXT_PUBLIC_WEBSITE_DOMAIN=drasadian.com
NEXT_PUBLIC_MESHKEE_API_BASE=https://api.meshkee.com/api/v1
# Optional overrides:
# NEXT_PUBLIC_CUSTOMER_PORTAL_URL=https://customer.drasadian.com
# NEXT_PUBLIC_BUSINESS_ORIGIN=https://business.drasadian.com
Commands
npm install
npm run dev
npm run build
npm run generate:sitemap-config
Sitemap + robots
- Do not add
public/sitemap.xmlorpublic/robots.txt(nginx proxies to Meshkee API) - Live sitemap is an index:
/sitemap.xml→/sitemap-main.xml+/sitemap-products.xml - Static pages config:
GET /meshkee/sitemap-config.json(generated at build from app routes) - Generator:
scripts/generate-sitemap-config.mjs→src/lib/sitemap-config.generated.json - Excludes
api,meshkee,admin,auth,login,checkout,cart,account - Blog / product / portfolio details are not listed in sitemap-config (Meshkee XML covers CMS URLs)
- After deploy: business dashboard → Website → Settings → Sync sitemap config (needed for static pages)
Canonical URL shapes (Meshkee defaults — do not add templates unless customized)
- Blog:
/blog/{id}/{titleSlug}→GET /tenants/{domain}/blogs/by-id/{id} - Product:
/products/{id}/{nameFaSlug}→GET /tenants/{domain}/products/by-id/{id}(not built yet; catalog empty) - Category:
/products/category/{id}/{nameFaSlug}→GET /tenants/{domain}/categories/by-id/{id} - Portfolio:
/portfolios/{id}/{titleFaSlug}→GET /tenants/{domain}/portfolios/by-id/{id}(not built yet) - Slugify (
src/lib/seo-slug.ts): keep Farsi letters, spaces →-, strip other punctuation. Do not use legacy DB slug in public URLs.
On-page SEO
- Helper:
src/lib/seo.ts(pageMetadata, unique absolute<title>, clipped meta description ~158 chars, canonical, OG) - Inner-page titles append
| دکتر محمد اسدیان. Homepage title is unique and does not use the Next.js default - Exactly one visible H1 per page (never
.sr-only/ CSS-hidden). Homepage H1 is.home-intro - Section headings default to
h2(SectionHeading). Service cards / article cards useh3under a sectionh2 - Prefer CMS
title/abstract/ image for blog metadata. Fallback teasers only when the API is empty - Content images have meaningful
alt(CMS title when available). Decorativedeco.pngusesalt="" src/app/not-found.tsx: unique title + one H1,noindex- Favicon:
public/favicon.png(tenant favicon API currently returns null)
Gallery
- 12 photos from the live
/gallerypage inpublic/images/gallery/01.jpg–12.jpg - Lightbox:
src/components/GalleryGrid.tsx(click to enlarge, arrows / Escape) - Header گالری →
/gallery
Next planned prompts
- Products / portfolio pages if the clinic starts publishing through Meshkee
- Image slots if a later prompt provides them