Requirements

Documentation for Modules

Product Catalog Module - Requirements Specification

Module ID: product-catalog Library: @libs-modules/product-catalog Location: libs/modules/product-catalog/ Base Path: /catalog Permission Namespace: catalog:*

1. Overview

Generic product catalog module that serves as the foundational item registry for the GoGrab platform. Supports physical products, digital goods, and services through a unified entity model. Designed to be consumed by downstream modules (inventory, POS/sales, e-commerce, work orders) via domain events, public actions, and embeddable components.

This module focuses exclusively on products and variants. Categories, brands, and tax configuration are provided by shared core libraries that other modules can also consume independently.

1.1 Architecture Context

libs/core/ (shared platform infrastructure)
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│  taxonomy    │  │ brand-       │  │  fiscal      │
│              │  │ registry     │  │              │
│ - Categories │  │ - Brands     │  │ - TaxClass   │
│ - Tags       │  │ - Logos      │  │ - TaxRate    │
│ (generic,    │  │ (shared      │  │ - TaxService │
│  any module) │  │  registry)   │  │ (minimal)    │
└──────┬───────┘  └──────┬───────┘  └──────┬───────┘
       │                 │                 │
       └────────┬────────┴────────┬────────┘
                │                 │
         ┌──────┴─────────────────┴──────┐
         │      product-catalog          │
         │      (libs/modules/)          │
         │                               │
         │  - Products (physical/        │
         │    digital/service)           │
         │  - Product Variants           │
         │  - Product Attributes         │
         └───────────────────────────────┘

2. Functional Requirements

2.1 Product Entity (Core)

A single unified entity Product that supports three item types:

Field Type Required Description
id string Yes Unique identifier (UUID)
tenantId string Yes Multi-tenant isolation
name string Yes Product display name
slug string Yes URL-friendly identifier (auto-generated, editable)
description string No Full product description
shortDescription string No Brief description for listings
sku string Yes Stock Keeping Unit (unique per tenant)
barcode string No UPC/EAN barcode
type ProductType Yes 'physical' | 'digital' | 'service'
status ProductStatus Yes 'draft' | 'active' | 'discontinued'
categoryId string No Reference to @libs-core/taxonomy category
brandId string No Reference to @libs-core/brand-registry brand
tags string[] No References to @libs-core/taxonomy tags
unit UnitOfMeasure Yes 'piece' | 'kg' | 'g' | 'liter' | 'ml' | 'meter' | 'hour' | 'session' | 'service' | 'unit'
taxClassId string Yes Reference to @libs-core/fiscal tax class
hasVariants boolean Yes Whether product uses variant system
basePrice number Yes* Base selling price (*required if hasVariants === false)
costPrice number No Cost/purchase price
compareAtPrice number No Original price for showing discounts
currency string Yes ISO 4217 currency code (default from tenant config)
weight number No Weight value (for physical products)
weightUnit WeightUnit No 'kg' | 'g' | 'lb' | 'oz'
dimensions ProductDimensions No { length, width, height, unit }
isOnlineAvailable boolean Yes Available for e-commerce (default: true)
isFeatured boolean Yes Featured/highlighted product (default: false)
sortOrder number No Manual sort position
metaTitle string No SEO meta title
metaDescription string No SEO meta description
metaKeywords string[] No SEO keywords
notes string No Internal notes (not public)
createdAt Date Yes Creation timestamp
updatedAt Date Yes Last update timestamp
createdBy string Yes Creator user ID
updatedBy string Yes Last modifier user ID

2.2 Product Variants

When hasVariants === true, the product acts as a parent with child variant entities:

Product Attribute (defines variation axes):

Field Type Required Description
id string Yes Unique identifier
productId string Yes Parent product reference
name string Yes Attribute name (e.g., "Size", "Color")
values string[] Yes Possible values (e.g., ["S", "M", "L", "XL"])
sortOrder number No Display order

Product Variant (concrete SKU per attribute combination):

Field Type Required Description
id string Yes Unique identifier
productId string Yes Parent product reference
sku string Yes Variant-specific SKU (unique per tenant)
barcode string No Variant-specific barcode
attributeValues Record<string, string> Yes Attribute selections (e.g., { "Size": "M", "Color": "Red" })
price number Yes Variant selling price
costPrice number No Variant cost price
compareAtPrice number No Variant original price
weight number No Variant-specific weight
isActive boolean Yes Whether this variant is available
sortOrder number No Display order
imageId string No Variant-specific image reference

Variant Rules:

2.3 Media Integration

3. Product Lifecycle (Workflow)

3.1 Status Transitions

        ┌──────────┐
        │  Draft   │  (initial state)
        └────┬─────┘
             │ publish
        ┌────┴─────┐
        │  Active  │◀────┐
        └────┬─────┘     │ reactivate
             │           │
  discontinue│     ┌─────┴──────────┐
        ┌────┴─────┴────────────────┘
        │  Discontinued  │
        └────────────────┘
Transition From To Permission Description
publish draft active catalog:publish Make product available
discontinue active discontinued catalog:manage Remove from active catalog
reactivate discontinued active catalog:manage Return to active catalog

3.2 Transition Guards

4. Integration Points

4.1 Domain Events (Product-Catalog Only)

Event Payload Trigger
catalog.product.created { product, createdBy, tenantId } Product created
catalog.product.updated { product, changes, updatedBy, tenantId } Product updated
catalog.product.deleted { productId, tenantId } Product deleted
catalog.product.status-changed { productId, fromStatus, toStatus, tenantId } Status transition
catalog.variant.created { variant, productId, tenantId } Variant created
catalog.variant.updated { variant, productId, changes, tenantId } Variant updated
catalog.variant.deleted { variantId, productId, tenantId } Variant deleted

Category, brand, and tax events are published by their respective core libraries (taxonomy, brand-registry, fiscal).

4.2 Public Actions

Action ID Description Parameters Permission
catalog:get-product Retrieve product by ID { productId } catalog:read
catalog:search-products Search/filter products { query, filters, pagination } catalog:read
catalog:get-variants Get variants for product { productId } catalog:read
catalog:create-product Create new product { product data } catalog:create

Category/brand lookup actions are provided by @libs-core/taxonomy and @libs-core/brand-registry.

4.3 Embeddable Components

Component ID Description Inputs
catalog:product-lookup Product search and selection widget limit, typeFilter, categoryFilter, multiSelect, showPrice, showVariants
catalog:product-card Single product display card productId, showPrice, showImage, compact

Category tree and brand selector embeddables are provided by their respective core libraries.

4.4 Downstream Module Integration Patterns

Inventory Module (future):

Sales/POS Module (future):

E-commerce Module (future):

Work Orders Module (future):

5. Permissions (Product-Catalog Only)

Permission Description
catalog:read View products and variants
catalog:create Create new products
catalog:update Edit existing products
catalog:delete Delete products
catalog:publish Publish draft products to active
catalog:manage Full management (discontinue, reactivate)
catalog:variants:manage Create/edit/delete product variants

Category, brand, and tax permissions are managed by their respective core libraries.

6. User Stories

Products

Variants

Integration

7. Non-Functional Requirements

8. Open Questions

  1. Currency handling: Should the module support multi-currency per tenant, or single currency per tenant with a global setting?
  2. Product duplication: Should there be a "clone product" feature for quickly creating similar products?
  3. Bulk operations: What bulk operations are needed beyond delete? (bulk status change, bulk price update, bulk category assign?)
  4. Import/Export: Is CSV/Excel import/export needed for initial data loading?
  5. Product relations: Should products support "related products" or "frequently bought together" associations?
  6. Audit trail: Beyond createdBy/updatedBy, do we need a full change history log for products?

9. Module Dependencies

@libs-modules/product-catalog
├── @libs-core/taxonomy            (categories, tags) ← NEW
├── @libs-core/brand-registry      (brands) ← NEW
├── @libs-core/fiscal              (tax classes, rates) ← NEW
├── @libs-core/module-base         (contracts, CRUD composables, base components)
├── @libs-core/event-system        (domain events)
├── @libs-core/security            (permissions, guards, tenant context)
├── @libs-core/log-system          (logging)
├── @libs-core/utilities           (string utils, validation, date utils)
├── @libs-core/shared-models       (BaseEntity, pagination, API types)
├── @libs-core/data-access         (repositories, base repository)
├── @libs-core/ui-framework        (UI components, forms, dialogs)
├── @libs-core/workflow-engine     (product status transitions)
├── @libs-core/media               (product images, gallery)
├── @libs-core/action-registry     (public actions)
└── @libs-core/mock-api            (development mock data)