Files
dashboards/docs/PROJECT_CONTEXT.md
T
Alireza HassaniandCursor 8f4af7a16c Add super-admin invoices: settings templates and per-business issue flow.
Platform invoice templates live under Settings; each business can list and issue invoices with optional name and a meshkee.com public link.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-24 20:59:34 +03:30

18 KiB
Raw Blame History

MeshkeeApp — Project Context

For AI agents: Read this file at the start of a new chat before making changes.
Update this document when a major feature is completed or architecture changes.

Last updated: July 24, 2026


Repository layout

Primary workspace: open MeshkeeApp (this monorepo) as the Cursor workspace root.

MeshkeeApp/
  apps/
    super-admin/     # @meshkee/super-admin — port 5174 — meshkee.app
    business/        # @meshkee/business-dashboard — port 5173 — business.{domain}
    customer/        # @meshkee/customer-dashboard — port 5175 — customer.{domain}
  packages/
    dashboard-core/  # @meshkee/dashboard-core — API client, auth types, utils, tokens
    dashboard-ui/    # @meshkee/dashboard-ui — shared React components
  docs/              # This file + agent context

Backend (separate repo): sibling folder MeshkeeApp Backend — NestJS + Prisma + PostgreSQL. Not inside this monorepo.

Stale workspace: MeshkeeApp Gen2 is empty/outdated — do not use it.


Apps overview

App Package Port Local URL Domain guard
Super Admin @meshkee/super-admin 5174 https://meshkee.app:5174 AdminDomainGuard
Business @meshkee/business-dashboard 5173 http://business.sanihome.ir:5173 BusinessDomainGuard
Customer @meshkee/customer-dashboard 5175 http://customer.sanihome.ir:5175 CustomerDomainGuard

Shared packages migration

App @meshkee/dashboard-core @meshkee/dashboard-ui
Customer wired wired
Super Admin pending pending
Business pending pending

When migrating an app to shared packages, prefer importing from @meshkee/dashboard-core / @meshkee/dashboard-ui instead of duplicating code.


Tech stack

All dashboard apps

  • React 19, TypeScript, Vite, React Router
  • CSS Modules + design tokens (src/index.css; customer also imports @meshkee/dashboard-core/styles/tokens.css)
  • Auth via JWT (src/context/AuthContext.tsx, src/services/authService.ts)
  • API client: src/lib/api.ts — base URL from VITE_API_BASE_URL

Backend

  • NestJS, Prisma, PostgreSQL, Redis
  • S3-compatible storage (Parmin) for media
  • API prefix: /api/v1
  • BigInt IDs serialized as strings in JSON

Local development

1. Monorepo setup

cd MeshkeeApp
npm install

2. Backend (sibling folder)

cd "../MeshkeeApp Backend"
cp .env.example .env   # fill DATABASE_URL, JWT secrets, S3 keys, GROQ_API_KEY (or OPENAI_API_KEY)
npm install
# Run SQL migrations in database/migrations/ (in order)
npx prisma generate
npm run start:dev      # default http://localhost:3000

3. Dashboard dev servers

From the monorepo root:

npm run dev:super-admin   # https://meshkee.app:5174
npm run dev:business      # http://business.sanihome.ir:5173
npm run dev:customer      # http://customer.sanihome.ir:5175

Or from an app directory:

cd apps/business && npm run dev

Copy each app's .env.example.env before first run.

Super Admin HTTPS: generate local certs with mkcert (see apps/super-admin/.env.example).

4. Hosts file

Add to /etc/hosts (one line per tenant):

127.0.0.1 meshkee.app
127.0.0.1 business.sanihome.ir
127.0.0.1 customer.sanihome.ir
127.0.0.1 business.safeteb.com
127.0.0.1 customer.safeteb.com
127.0.0.1 safeteb.com

Multi-tenant: leave VITE_BUSINESS_DOMAIN unset in business/customer .env. Each dashboard build resolves the tenant from window.location.hostname (business.safeteb.comsafeteb.com). One dev server and one production deploy serve all businesses; the backend maps domain → business in the DB.

5. Test accounts

App Phone Password Notes
Business +989122222222 password sanihome.ir → business_id 4
Customer (same user) password customer.sanihome.ir tenant
Super Admin (platform admin) see backend seed / team records

App routes

Super Admin (apps/super-admin)

Path Page
/login Login
/ Home
/businesses Businesses list
/businesses/:businessId/invoices Business invoices (list + issue)
/users Users
/websites Websites / domains
/settings Platform settings (invoice item templates)
/profile Profile

Customer (apps/customer)

Path Page
/login Login
/checkout Shopping cart checkout (standalone layout — login → cart → delivery → payment)
/checkout/login Checkout sign-in step
/checkout/cart Cart review
/checkout/delivery Address or pickup
/checkout/payment Discount code + payment
/checkout/success Order confirmation
/ Home
/profile Profile
/addresses Addresses
/orders Orders
/favorites Favorites

Business (apps/business)

Path Page Backend connected?
/login Login Yes
/ Home Partial
/products Products hub
/products/categories Category tree + variations Yes
/products/brands Product brands (linear list) Yes
/products/list My Products grid Yes
/products/new Add product Yes
/products/edit/:id Edit product Yes
/products/detail/:id Product details + gallery Yes
/products/settings Product moderation settings Yes
/store Store hub Partial
/store/items Store items (product variants) Yes
/store/settings Online sell + order process steps Yes
/customers Business customers list Yes
/store/orders Orders list + filters Yes
/blog Blog hub Yes
/blog/list My Blogs grid Yes
/blog/new, /blog/edit/:id Add/edit blog Yes
/blog/categories Blog category tree Yes
/blog/settings Comment moderation Yes
/portfolios Portfolios hub Yes
/portfolios/list My Portfolios grid Yes
/portfolios/detail/:id Portfolio detail + gallery Yes
/portfolios/new, /portfolios/edit/:id Add/edit portfolio Yes
/portfolios/categories Portfolio category tree Yes
/portfolios/settings Comment moderation Yes
/website Website hub Placeholder
/website/sliders Homepage sliders Yes
/website/special-categories Featured category groups Yes
/website/special-brands Featured brand groups Yes
/website/special-items Special item carousels Yes
/website/contact Contact us submissions list Yes
/website/subscriptions Subscriptions Placeholder
/website/faq FAQ Placeholder
/website/badges Badges Placeholder
/website/e-payment E-payment Placeholder

API surface (business-scoped)

All routes require JWT + business permission. businessId comes from tenant context after login.

Categories

  • GET/POST/PATCH/DELETE /businesses/:businessId/categories
  • POST /businesses/:businessId/categories/ai-generate — AI-generated category tree ({ prompt })
  • GET /businesses/:businessId/categories/color-presets
  • GET/PUT /businesses/:businessId/categories/:categoryId/variations
  • POST /businesses/:businessId/categories/:categoryId/technical-form/ai-suggest

Query: ?entityType=product for product categories.

Brands

  • GET/POST/PATCH/DELETE /businesses/:businessId/brands
  • GET /businesses/:businessId/brands/:brandId

Products accept optional brandId on create/update.

Products

  • GET/POST/PATCH/DELETE /businesses/:businessId/products
  • POST /businesses/:businessId/products/ai-create — AI-generated product draft
  • GET /businesses/:businessId/products/:productId

Contact submissions

  • GET /businesses/:businessId/contact-submissions — paginated list
  • GET /businesses/:businessId/contact-submissions/:submissionId
  • POST /tenants/:host/contact-submissions — public website contact form

Business settings

  • GET/PATCH /businesses/:businessId/settings — includes branding.primaryColor

Portfolios

  • GET/POST/PATCH/DELETE /businesses/:businessId/portfolios
  • GET /businesses/:businessId/portfolios/:portfolioId
  • Portfolio categories: ?entityType=portfolio

Store items (sellable product variants)

  • GET /businesses/:businessId/store-items — paginated list
  • POST /businesses/:businessId/store-items — batch create with price + stock

Store specials

  • GET/POST/PATCH/DELETE /businesses/:businessId/store-specials
  • GET /tenants/:host/store-specials — public API for websites

Website homepage widgets

  • GET/POST/PATCH/DELETE /businesses/:businessId/website/category-groups — groups with categoryIds[]
  • GET/POST/PATCH/DELETE /businesses/:businessId/website/brand-groups — groups with brandIds[]
  • GET /tenants/:host/website/category-groups — public category groups
  • GET/POST/PATCH/DELETE /businesses/:businessId/website/sliders — sliders with slides[] (imageMediaId, title, linkUrl)
  • GET /tenants/:host/website/sliders — public sliders

Customers

  • GET/POST/PATCH/DELETE /businesses/:businessId/customers
  • GET /businesses/:businessId/customers/search — autocomplete for order cart

Orders

  • GET/POST/PATCH/DELETE /businesses/:businessId/orders

Product variants & variation values

  • GET/POST/DELETE /businesses/:businessId/products/:productId/variants
  • GET/PUT /businesses/:businessId/products/:productId/variations

Technical forms

  • GET/PUT /businesses/:businessId/categories/:categoryId/technical-form
  • POST .../technical-form/ai-suggest
  • GET/PUT /businesses/:businessId/products/:productId/technical-info

Media

  • POST /businesses/:businessId/media — upload to S3

Feature status (business app)

Connected to backend

  • Auth, tenant, business context
  • Product categories, variations, products CRUD, media upload
  • Product variation values, store items, draft cart, admin orders
  • Category technical data forms, product technical data
  • Product/store settings, blog, portfolios, contact submissions

Still local / dummy data

  • Product comments modal (apps/business/src/data/productComments.ts)
  • Legacy seeds in apps/business/src/data/

Product variations — business rule

Product Variations modal: user selects which category variation values apply to the product. Saved via PUT .../products/:id/variations.

Store items: sellable variants with one value per variation type + price + stock. Saved via POST .../store-items (batch).


Database migrations (Backend)

Run in order from MeshkeeApp Backend/database/migrations/:

Migration Purpose
009_categories_name_fa.sql name_fa on categories — required or categories 500
010_category_variations.sql variation tables
016_product_variation_values.sql product variation values
036_invoices.sql Platform/business invoices + invoice item templates

After schema changes: npx prisma generate and restart the backend.

Invoices (super-admin)

Platform billing invoices issued to a business. Schema supports a future owner_scope=business mode (business-issued invoices); UI is super-admin only for now.

Endpoint Purpose
GET/POST /invoice-item-templates Platform predefined line items (Settings)
PATCH/DELETE /invoice-item-templates/:id Update/remove template
GET/POST /businesses/:businessId/invoices List / issue invoices for a business
GET/PATCH/DELETE /businesses/:businessId/invoices/:invoiceId Detail, status update, delete

Invoice fields: optional name, notes, status (draft | issued | paid | cancelled), publicUrl.

Line item fields: title, duration, worktime, description, price, discountedPrice (IRT). Create flow can mix predefined templates + custom lines.

Public link (platform invoices): https://meshkee.com/invoices/{id}

  • Backend: INVOICE_PUBLIC_DOMAIN (default meshkee.com) → response field publicUrl
  • Super Admin UI: VITE_INVOICE_PUBLIC_DOMAIN fallback helper in lib/config.ts
  • Public viewer page at that URL is not implemented yet — link is issued/copied only.

Migrations: 036_invoices.sql, 037_invoice_name.sql

Super Admin UI:

  • /settings — Invoices section (CRUD templates)
  • /businesses/:businessId/invoices — list, issue (extra-wide modal), view/copy link, update status, delete
  • Businesses table row → FileText control opens invoices page

Key files by area

Shared packages

Area Path
API client factory packages/dashboard-core/src/api/createApiClient.ts
IRT price utils packages/dashboard-core/src/utils/irtPrice.ts
Design tokens packages/dashboard-core/src/styles/tokens.css
Toast, Breadcrumbs, etc. packages/dashboard-ui/src/

Business app

Area Path
Categories apps/business/src/pages/CategoriesPage.tsx
Products apps/business/src/pages/MyProductsPage.tsx, AddNewProductPage.tsx
Store / orders apps/business/src/pages/StoreItemsPage.tsx, OrdersPage.tsx
Services apps/business/src/services/
ID helper apps/business/src/utils/id.tscreateId() fallback

Backend (sibling repo)

Area Path
Products src/products/products.service.ts
Categories src/categories/categories.service.ts
Invoices src/invoices/
Media / S3 src/media/media.service.ts
Prisma schema prisma/schema.prisma

Super Admin

Area Path
Settings / invoice templates apps/super-admin/src/pages/SettingsPage.tsx
Business invoices apps/super-admin/src/pages/BusinessInvoicesPage.tsx
Invoice API client apps/super-admin/src/services/invoiceService.ts

UI conventions

Match Super Admin compact field sizing across all dashboards — see .cursor/rules/ui-compact-fields.mdc:

--field-height: 38px;
--field-padding-y: 9px;
--field-font-size: 13px;

Global input sizing lives in packages/dashboard-core/src/styles/tokens.css (customer) and each apps index.css (business / super-admin). Change password → shared PasswordResetModal from @meshkee/dashboard-ui.

  • Farsi text: Customer app → Yekan Bakh (src/fonts/yekanbakh.css, --font-fa in index.css); business/super-admin → IranYekan (iranyekan.css, .faText). Input + placeholder must share the same stack — see .cursor/rules/ui-farsi-fonts.mdc
  • Per-business theme: Super Admin sets branding.primaryColor; business app applies via BusinessThemeProvider
  • RTL: Farsi inputs use dir="rtl" and the apps --font-fa
  • IRT prices: comma-separated thousands + IRT suffix — see .cursor/rules/ui-irt-price.mdc
  • Toasts: see .cursor/rules/ui-toasts.mdc
  • Icon controls: see .cursor/rules/ui-control-buttons.mdc, ui-tooltips.mdc

Known issues & fixes

Problem Cause Fix
Categories 500 Missing name_fa column Run migration 009
crypto.randomUUID is not a function Non-secure origin Use createId() from apps/business/src/utils/id.ts
Media upload 400 Bad MIME / empty data URL ensureJpegUploadFile(); backend Sharp validation
Super Admin HTTPS warning Missing mkcert certs Run mkcert per apps/super-admin/.env.example
Workspace approval popups Wrong workspace root Open MeshkeeApp monorepo root in Cursor

Build commands

npm run build:packages    # shared packages only
npm run build:customer
npm run build:business
npm run build:super-admin
npm run build               # everything

Git & handoff checklist

  1. Push MeshkeeApp monorepo and MeshkeeApp Backend to remote
  2. Copy .env files securely (never commit)
  3. Run migrations on the database
  4. Open MeshkeeApp as Cursor workspace root
  5. Start a new agent chat: "Read docs/PROJECT_CONTEXT.md and continue…"

Branding: logo → favicon

When a business logo is uploaded/changed in Business Profile, the backend generates a 48×48 PNG favicon (sharp), stores it as media, and links businesses.favicon_media_id.

Surface How favicon is applied
Business dashboard TenantBrandingProviderapplyDocumentFavicon
Customer dashboard same
Public website (sanihome) generateMetadata().icons from faviconUrl

APIs expose faviconUrl (falls back to logoUrl if favicon missing):

  • GET /businesses/:id/profile
  • GET /tenants/:host
  • GET /tenants/:host/website/business-info

Migration: database/migrations/033_business_favicon.sql


Production deploy (dashboards)

VPS 45.149.76.52
Super Admin https://manage.meshkee.com
Business https://business.<apex> (e.g. business.sanihome.ir)
Customer https://customer.<apex>
API https://api.meshkee.com/api/v1 (host 185.164.72.119)
Docs docs/DEPLOY.md

SSL: Certbot cert meshkee-dashboards + cron ssl-sync.sh every 2h (option A: GET /api/v1/internal/ssl/hosts).


Suggested next work

  • Public invoice page at meshkee.com/invoices/{id} (platform invoices)
  • Business-dashboard invoice templates + issue flow (owner_scope=business)
  • Migrate business and super-admin to @meshkee/dashboard-core / @meshkee/dashboard-ui
  • Connect product comments to backend
  • Wire order status transitions to store orderProcessSteps
  • Enforce onlineSellEnabled on public website checkout
  • Postman collection updates for variants endpoints
  • Add sanihome.ir (and other tenants) in production Super Admin so tenant APIs resolve

Agent instructions

  1. Minimize scope — only change what the task requires
  2. Match existing patterns — services in src/services/, CSS modules, NestJS modules per domain
  3. Do not commit unless the user explicitly asks
  4. Test user: +989122222222 / password; business id 4 for sanihome.ir
  5. Restart backend after Prisma or module changes
  6. Update this file when completing a major feature