Files
dr-asadian/CONTEXT.md
T
Alireza HassaniandCursor 7c4b59c6f8 Initial commit of the Dr Asadian Next.js site.
Persian RTL clinic site with Meshkee blog, auth, sitemap config, and on-page SEO.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-01 09:14:52 +03:30

169 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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-clone` then `backend` (`/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` (no `www` / `api` / `customer` / `business`)
- Tenant: `GET /tenants/drasadian.com` → `businessId` `31`
- Enabled modules: `products`, `blog`, `finance`
## Stack
- Next.js 15 (App Router) + React 19 + TypeScript
- Tailwind CSS v4 (`@import "tailwindcss"` in `src/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: `#D5E8E0` on `#17543E` text
- 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
1. Hero slider (2 banners)
2. Visible H1 intro (clinic name + description)
3. Specialized service icons
4. Latest blogs (8 from Meshkee). If the API has no posts yet, the original three cloned teasers are shown and link to `/blog`
5. Testimonials (microneedling / microderm / e-light)
6. Skin repair + about CTA band
## Meshkee auth (customer portal)
- Logged-out user icon → `https://customer.drasadian.com` (`customerPortalUrl` in `src/lib/config.ts`)
- Logged-in: `{firstName lastName} عزیز` with dropdown:
- پروفایل من → `https://customer.drasadian.com/profile`
- خروج (clears shared tokens)
- مدیریت وبسایت (admins/owners only) → `https://business.drasadian.com` via `POST /api/auth/handoff`
- Session: `src/lib/session.tsx` + cookies `meshkee_customer_access_token` / `meshkee_customer_refresh_token` (shared with customer portal on `.drasadian.com`)
- Current user: website `GET /api/auth/me` → Meshkee `GET /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-child` fade up in sequence (`--i` delay, 130ms steps)
- Slider slides crossfade (1.15s)
- `prefers-reduced-motion: reduce` disables the above
## Inner page title
- `PageHero` sits in `.page-hero-row` with 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 theme `PMlhUjbrcj.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` (see `next.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` (wraps `Providers` + 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
```bash
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
```bash
npm install
npm run dev
npm run build
npm run generate:sitemap-config
```
## Sitemap + robots
- **Do not** add `public/sitemap.xml` or `public/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 use `h3` under a section `h2`
- 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). Decorative `deco.png` uses `alt=""`
- `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 `/gallery` page in `public/images/gallery/01.jpg`–`12.jpg`
- Lightbox: `src/components/GalleryGrid.tsx` (click to enlarge, arrows / Escape)
- Header گالری → `/gallery`
## Next planned prompts
1. Products / portfolio pages if the clinic starts publishing through Meshkee
2. Image slots if a later prompt provides them