Add public user-products storefront API and website docs.

Expose published customer listings under /tenants/:host/user-products (list, search, details, technical-info) and document them in the website API pack.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-10 00:19:13 +03:30
co-authored by Cursor
parent 158523df7b
commit 953b87b616
32 changed files with 3326 additions and 138 deletions
+40 -5
View File
@@ -1,7 +1,7 @@
# Meshkee CMS API — Project Context
> Living reference for developers and AI assistants working on this codebase.
> Last updated: August 5, 2026
> Last updated: August 9, 2026
## What This Project Is
@@ -80,6 +80,8 @@ src/
├── website-docs/ # Public website API docs pack
├── invoices/ # Platform invoices + item templates (super-admin; business-ready schema)
├── public-sms/ # Partner SMS gateway (API key + domain allowlist → Gama)
├── favorites/ # Customer product favorites
├── user-products/ # Customer self-service stock listings (`my-user-products`)
├── prisma/ # PrismaModule + PrismaService
├── redis/ # Redis client + OTP helpers
└── common/ # Shared interceptors (BigInt serialization)
@@ -159,6 +161,10 @@ Example super admin: `+989121111111` / `password`
| `039_invoice_account_holder.sql` | `account_holder_name` on invoice / template accounts |
| `040_invoice_public_id.sql` | Opaque `public_id` for unguessable public invoice links |
| `049_user_name_en.sql` | Optional `users.first_name_en` / `last_name_en` for EN display names |
| `052_user_products.sql` | Customer stock listings (`user_products`) + technical values; `cities.level` adds `district`; `media_entity_type` adds `user_product` |
| `053_cities_country_optional_province.sql` | City may hang under country (province optional); seed Iraq/Turkey/UAE + major cities |
| `054_seed_iran_provinces_cities.sql` | Seed Iran provinces + cities when missing (004 seed may never have run) |
| `055_user_products_listing_fields.sql` | User product listing fields: `price_currency`, `delivery_note`, `condition` (`user_product_condition`), `technical_notes` |
Docker mounts `./database/migrations` into Postgres init — migrations run automatically only on **first** volume creation. Use `migrate.sh` for subsequent migrations.
@@ -170,22 +176,25 @@ Docker mounts `./database/migrations` into Postgres init — migrations run auto
| Enum | Values |
|------|--------|
| `MediaEntityType` | `product`, `blog`, `portfolio` |
| `MediaEntityType` | `product`, `blog`, `portfolio`, `customer`, `user_product` |
| `ContentStatus` | `draft`, `published`, `archived` |
| `VariationType` | `color`, `size`, `custom` |
| `CityLevel` | `country`, `province`, `city`, `district` |
| `OrderStatus` | `pending`, `confirmed`, `processing`, `shipped`, `delivered`, `cancelled` |
| `OrderSource` | `website`, `admin` |
| `InvoiceOwnerScope` | `platform`, `business` |
| `InvoiceStatus` | `draft`, `issued`, `approved`, `paid`, `cancelled` |
| `TechnicalFieldType` | `text`, `textarea`, `select`, `multi_select` |
| `UserProductCondition` | `new`, `stock`, `needs_repair`, `scrap` |
| `MediaType` | `image`, `video` |
### Core relationships
```
Business 1──* Domain
Business 1──* Category (entityType: product|blog|portfolio)
Business 1──* Category (entityType: product|blog|portfolio|customer)
Business 1──* Product
Business 1──* UserProduct (customer stock; no variations; location + technical data)
Business 1──* Media
Category 1──* CategoryVariation 1──* CategoryVariationOption
@@ -194,12 +203,16 @@ CategoryTechnicalFormField 1──* CategoryTechnicalFormFieldOption
Product *──0..1 Category (via CategoryAssignment)
Product 1──* ProductVariationValue → CategoryVariationOption (which options this product offers)
Product 1──* ProductVariationValue → CategoryVariationOption (which options this product offers)
Product 1──0..1 StoreItem (one shop listing per product)
StoreItem 1──* StoreItemVariant (purchasable SKUs: price, stock, variation combo)
StoreItemVariant 1──* StoreItemVariantSelection → CategoryVariationOption
Product 1──* ProductTechnicalFieldValue → CategoryTechnicalFormField
UserProduct *── Category (via CategoryAssignment, entityType user_product → product categories)
UserProduct 1──* UserProductTechnicalFieldValue → CategoryTechnicalFormField
UserProduct → City (country, city, optional district)
User 1──* UserProduct
Business 1──* Cart (per customer) 1──* CartItem → ProductVariant
Business 1──* Order 1──* OrderItem → ProductVariant (snapshot on order)
User 1──* Cart, Order (as customer)
@@ -295,6 +308,27 @@ Pattern: `/businesses/:businessId/<resource>`
| GET/POST/PATCH/DELETE | `/products/:id/variants` | Removed — use `/store-items` |
| GET/PUT | `/products/:id/technical-info` | Product technical data |
#### My user products (customer — JWT, must be business customer)
Base: `/businesses/:businessId/my-user-products`
| Method | Path | Description |
|--------|------|-------------|
| GET | `/` | List current user's user products (paginated) |
| POST | `/` | Create draft user product (category, location, condition, optional technical values) |
| GET | `/categories` | Active product categories for picker (`id`, `name`, `nameFa`, `parentId`) |
| GET | `/categories/:categoryId/technical-form` | Category technical form (customer access; no `categories.read`) |
#### Public user products (storefront — no auth)
Base: `/tenants/:host/user-products`
| Method | Path | Description |
|--------|------|-------------|
| GET | `/` | List published listings (`name`/`q`, `categoryId`, `cityId`, `countryId`, `condition`, `promoted`, pagination) |
| GET | `/:slug` | Details + gallery (`images`, `galleryMediaIds`) + technical values |
| GET | `/:slug/technical-info` | Category technical form + values |
#### Cart (customer — JWT, must be business customer)
| Method | Path | Description |
@@ -583,7 +617,8 @@ See `.env.example` for the full list. Key groups:
| Portfolios | Yes | Yes | Partial (migrate-from-old) | Yes |
| Customer dashboard | Partial | No | Register only | Yes |
| Store checkout (cart, orders) | Yes | Yes | Yes | Yes |
| Customer favorites | — | `favorites.*` seeded | No | No |
| Customer favorites | — | `favorites.*` seeded | Partial | Yes |
| Customer user products | Yes (`052`+`055`) | Admin `user_products.*` + customer JWT | Yes (`my-user-products`, admin, public tenants) | Yes |
---