Files
ayoubi-gallery/CONTEXT.md
T
Alireza HassaniandCursor 2ee76f4566 Ship Meshkee-backed Ayoubi Gallery storefront.
Replace the coming-soon page with products, mega menu, home slots, and catalog UI polish.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 23:44:59 +03:30

118 lines
6.6 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.
# Ayoubi Gallery — AI / Project Context
## Source of truth
- Live domain: `https://ayoubi.jewelry`
- Design language: black ground, ivory type, gold lines, Doran + Cinzel, flat surfaces
- Backend: https://api.meshkee.com/docs/website
- Domain: `ayoubi.jewelry` (`NEXT_PUBLIC_WEBSITE_DOMAIN`)
- API base: `https://api.meshkee.com/api/v1` (`NEXT_PUBLIC_MESHKEE_API_BASE`)
- Tenant business id: `42` (`GET /tenants/ayoubi.jewelry`, nameFa: گالری ایوبی فخیم)
- Enabled modules: `products`, `blog`, `finance`. `specialProductsSource`: `store_item`
- Prompt reference: `https://api.meshkee.com/api/v1/public/ai-prompts/ayoubi-gallery/backend/253d39eea2a4047c39296d1a`
## Stack
- Next.js 15 App Router + React 19 + TypeScript
- `output: "standalone"` in `next.config.ts` (required for the Meshkee websites VM)
- Language: `fa`, direction: `rtl`
- Fonts: Doran (`--font-doran`), Cinzel (`--font-cinzel`)
- Styling: `src/app/globals.css` only (no Tailwind)
## Color palette
- Background: `#070708` (`--bg`)
- Elevated: `#101012`
- Ivory text: `#f3eee6` (`--fg`)
- Muted: `rgba(243, 238, 230, 0.62)`
- Gold: `#c9a86a` (`--accent`)
- Hairline: `rgba(243, 238, 230, 0.14)`
- Flat: no shadows, square corners, 1px borders
- Header is fixed. Frosted over the home video; solid `#000` after scroll (`.header--solid`)
- Header tools: account menu, cart (badge + popup), phone, Instagram
## Auth (customer dashboard)
- Do **not** add `/login`, `/register`, `/cart`, or `/checkout` on this site
- Anonymous account icon → `https://customer.ayoubi.jewelry`
- Logged in (cookie `meshkee_customer_access_token`, may be chunked): show `{firstName|nameFa|name} عزیز`
- Dropdown: `پروفایل من`, `خروج`, and if admin `مدیریت وبسایت` → `https://business.ayoubi.jewelry`
- Session: `src/lib/auth.ts` + `src/lib/authUser.ts` via `GET /auth/me`
## Shopping cart (mini-cart only)
- Header cart icon + quantity badge + popup (`CartButton` + `CartProvider` + `guestCart.ts`)
- Persist `meshkee-guest-cart` in localStorage + cookie on `.ayoubi.jewelry`
- Add-to-cart only when `GET .../store-items/by-product/{productId}` returns in-stock variants
- Line `id` = `storeItemVariantId`; price = `discountedPrice ?? price`
- Continue: logged in → `customer.../checkout/cart?guestCart=…`; else login with that redirect
- Never call `/businesses/{id}/cart*` from this site
## Pages
| Route | Purpose |
| --- | --- |
| `/` | Video hero, category studio, local/CMS gallery, follow, carousel, parallax, visit |
| `/products` | Catalog from Meshkee products API + jewelry category filters + pagination |
| `/products/[id]/[nameFaSlug]` | Product detail (canonical); redirect if slug drifts |
| `/products/category/[id]/[nameFaSlug]` | Category product list |
| `/portfolio` | Portfolio list (API; empty until CMS content) |
| `/portfolio/[slug]` | Portfolio detail: lightbox gallery, zoom, similar row |
| `/blog` | Blog list (API; empty until CMS content) |
| `/blog/[slug]` | Blog detail |
| `/about` | درباره گالری |
| `/contact` | Contact facts + form → `POST /api/contact` → Meshkee contact-submissions |
## Product detail requirements
- Media gallery with hover zoom (desktop) + lightbox
- Tabs: توضیحات، مشخصات فنی (via `.../technical-info` join), دیدگاه‌ها
- Comments: form only when authenticated; else login link to customer portal
- Similar products from `relatedProducts`
- Emit `product.schema.jsonLd` when present
## Homepage (visual gallery)
- Local images in `public/assets/images/` / `gallery` in `src/data/site.ts` as fallbacks
- CMS slots: `categories`, `four-banner`, `masonry-image`, `instagram-image`, `last-banner` (see Static image slots)
- Homepage masonry is atmospheric; purchasable catalog is `/products`
## Brand copy (fallback)
- Name: گالری طلا و جواهر ایوبی فخیم / Ayoubi Fakhim Jewelry
- Tagline: این طلا همیشه مده
- Address: قم - سالاریه - اریکه ملل
- Phones: ۰۹۹۹ ۱۲۹ ۶۶۶۶ (`09991296666`), ۰۹۳۷ ۱۴۴ ۸۹۰۵ (`09371448905`)
- Instagram: https://www.instagram.com/ayoubifakhim/
- Logo / favicon fallback: `public/Ayoobi-logo.png`
## Meshkee helpers
- `src/lib/meshkee.ts` — business-info, favicon
- `src/lib/catalog.ts` — products, categories, blogs, portfolios, comments, store-items, `/auth/me`
- `src/lib/slug.ts` — canonical product/category/blog/portfolio hrefs
- Favicon: `GET /website/favicon` → `metadata.icons`, else `/Ayoobi-logo.png`
### Static image slots
Catalog: `GET /meshkee/static-image-slots` from `STATIC_IMAGE_SLOTS` in `src/lib/static-images.ts`.
Fetch per page: `GET /tenants/{domain}/website/static-images?pageKey=…`.
Empty/fail → keep local placeholders. `url` → `<img>`; `linkUrl` → wrap in `<a>`.
Use `titleFa` / `titleEn` / `subtext` to match the original UI labels.
Apply `slot.aspectRatio` from the API (fallback to catalog). **If an on-page frame’s size or aspect ratio changes in development, update the matching `STATIC_IMAGE_SLOTS` entry in the same change.**
| key | kind | itemCount | aspectRatio | width | UI |
| --- | --- | --- | --- | --- | --- |
| `categories` | list | null | `1:1` | 320 | Category row — `titleFa`/`titleEn` beside image (icon fallback) |
| `four-banner` | list | 4 | `3:4` | 1440 | Sticky “از فلز تا پوشیدن” — Fa/En/subtext + image |
| `masonry-image` | list | null | `3:4` | 960 | Masonry gallery (free display height) |
| `instagram-image` | single | 1 | `4:5` | 480 | Follow frame photo + optional Fa/En/subtext |
| `last-banner` | single | 1 | `16:9` | 1600 | Parallax end banner |
| `about-portrait` | single | 1 | `3:4` | 900 | About portrait |
Helpers: `src/lib/home-slots.ts`, `SlotImage`.
### Tags & badges
From `business-info`: `metaTags` as `{ html }` **or** `{ name, content }` → root `<head>` via `CmsMeta`. `trustBadges[].embedHtml` → footer (scripts stripped). Empty → omit; do not hardcode eNamad/Samandehi.
### SEO
- Do not ship local `sitemap.xml` / `robots.txt` / `app/sitemap.ts` / `app/robots.ts`
- Static pages: `GET /meshkee/sitemap-config.json`
- One H1 per page; content images have alt; use `seoMetaTitle` / `seoMetaDescription` when set
- Organization JSON-LD from business-info; product/blog detail emit their own `schema.jsonLd`
## Important paths
- Layout / providers: `src/app/layout.tsx`, `src/components/providers/*`
- Header / footer: `src/components/Header.tsx`, `AccountMenu.tsx`, `CartButton.tsx`, `Footer.tsx`
- Catalog UI: `MediaGallery.tsx`, `ProductTabs.tsx`, `AddToCart.tsx`, `CatalogCard.tsx`, `CommentSection.tsx`
- Contact: `src/components/ContactForm.tsx` + toast, `src/app/api/contact/route.ts`