1.3 KiB
1.3 KiB
Domain: Catalog
Products, SKUs, categories, brands (modules/product/, category/, brand/).
Shape
products: shop-scoped, bilingual name/description, images JSONB array, status draft → published (publish requires ≥1 active SKU with price > 0), optionalfreight_template_id(must belong to the same shop).skus: per-product purchasable units — code, attributes JSONB,price_minor+currency, guardedstock,weight_grams(freight).categories: tree with subtree CTE for filtering; seeded reference tree.brands: platform-managed ordered registry, whole-list replacement viaPUT /admin/brands.
Public reads
GET /products (published + active shop only; filters: category subtree,
shop, name ILIKE, brand; sort newest/price/sales) and
GET /products/{idOrSlug}. sold_count is computed from paid order items.
Merchant reads/writes go through /shop/products* with own_shop scoping.
Conventions
- Every Product query uses explicit column lists — when adding a product
column, update
PRODUCT_COLSand the literal lists inservice.rs(search:category_id, brand_id, slug). - SKU upsert is keyed on
(product_id, sku_code). - Stock is the only concurrently decremented counter today; always the guarded-decrement pattern.
Key files
See docs/code_index/catalog.md.