Skip to content

Product Management Guide

Overview

The Product Management system provides comprehensive catalog management for all product types, from simple physical goods to complex master/variant configurations. Built on Domain-Driven Design principles with CQRS patterns, it offers flexible product modeling, lifecycle management, and rich metadata support.

Table of Contents

Product Types

The system supports seven distinct product types, each with specific characteristics:

Physical Products

Traditional tangible goods requiring inventory tracking and shipping.

php
ProductType::PHYSICAL

// Characteristics:
- requiresShipping(): true
- hasInventory(): true
- isTangible(): true
- canHaveVariants(): true
- taxCategory(): 'physical_goods'

Examples: Laptops, clothing, books, furniture Use Cases: E-commerce stores, retail inventory Features: Full inventory tracking, shipping calculations, variant support

Digital Products

Downloadable or streamable digital content.

php
ProductType::DIGITAL

// Characteristics:
- requiresShipping(): false
- hasInventory(): false
- isDownloadable(): true
- canHaveVariants(): true
- taxCategory(): 'digital_goods'

Examples: Software, e-books, music files, PDF documents Use Cases: Digital marketplaces, content platforms Features: Download links, license management, no inventory tracking

Services

Professional services or consultations.

php
ProductType::SERVICE

// Characteristics:
- requiresShipping(): false
- hasInventory(): false
- requiresFulfillment(): true
- canHaveVariants(): true
- taxCategory(): 'services'

Examples: Consulting hours, maintenance contracts, training sessions Use Cases: Service businesses, professional services Features: Booking management, resource allocation, service-specific pricing

Subscriptions

Recurring products billed periodically.

php
ProductType::SUBSCRIPTION

// Characteristics:
- requiresShipping(): false
- hasInventory(): false
- isRecurring(): true
- canHaveVariants(): true
- taxCategory(): 'subscription_services'

Examples: Monthly memberships, SaaS subscriptions, subscription boxes Use Cases: Membership platforms, subscription businesses Features: Recurring billing, renewal management, tier variations

Bundles

Collections of multiple products sold together.

php
ProductType::BUNDLE

// Characteristics:
- requiresShipping(): false (depends on contents)
- hasInventory(): false
- taxCategory(): 'mixed'

Examples: Starter packs, gift sets, combo deals Use Cases: Product bundles, promotional packages Features: Component tracking, bundle pricing, inventory aggregation

Gift Cards

Prepaid store credit or value cards.

php
ProductType::GIFT_CARD

// Characteristics:
- requiresShipping(): false
- hasInventory(): true (for physical cards)
- taxCategory(): 'gift_cards'

Examples: Store gift cards, prepaid vouchers Use Cases: Gift card programs, promotional credits Features: Balance tracking, redemption codes, expiration dates

Virtual Products

Non-physical, non-downloadable products.

php
ProductType::VIRTUAL

// Characteristics:
- requiresShipping(): false
- hasInventory(): false
- isDownloadable(): true
- taxCategory(): 'virtual_goods'

Examples: Game credits, virtual currencies, in-app purchases Use Cases: Gaming platforms, virtual economies Features: Virtual delivery, account crediting

Product Status Lifecycle

Products transition through different statuses during their lifecycle:

mermaid
stateDiagram-v2
    [*] --> Draft
    Draft --> PendingApproval
    Draft --> Active
    Draft --> Rejected
    PendingApproval --> Active
    PendingApproval --> Rejected
    PendingApproval --> Draft
    Rejected --> Draft
    Active --> Inactive
    Active --> OutOfStock
    Active --> Discontinued
    Inactive --> Active
    Inactive --> Discontinued
    OutOfStock --> Active
    OutOfStock --> Discontinued
    Discontinued --> [*]

Status Descriptions

Draft

Initial status for new products under development.

  • Not visible in public catalog
  • Can be edited freely
  • No inventory tracking
  • Used for product setup and configuration

Allowed Transitions:

  • → Active (publish directly)
  • → Pending Approval (submit for review)
  • → Rejected (mark as rejected)

Use Cases:

  • New product creation
  • Product staging before launch
  • Template products for cloning

Pending Approval

Products awaiting management approval before activation.

  • Requires approval workflow
  • Not yet available for sale
  • Under review by authorized personnel

Allowed Transitions:

  • → Active (approve)
  • → Rejected (decline)
  • → Draft (return for revisions)

Use Cases:

  • Products requiring pricing approval
  • New vendor products needing review
  • Compliance verification workflows

Active

Available for sale and fully operational.

  • Visible in catalog
  • Inventory tracked
  • Can be ordered by customers
  • Full feature availability

Allowed Transitions:

  • → Inactive (temporarily disable)
  • → Out of Stock (inventory depleted)
  • → Discontinued (permanently remove)

Use Cases:

  • Standard products available for purchase
  • Current catalog items
  • Regular inventory items

Inactive

Temporarily disabled products not currently for sale.

  • Not visible in catalog
  • Inventory preserved
  • Can be reactivated
  • Historical data maintained

Allowed Transitions:

  • → Active (re-enable)
  • → Discontinued (permanently remove)

Use Cases:

  • Seasonal products (off-season)
  • Products under review
  • Temporary supply issues

Out of Stock

Inventory depleted but product remains active.

  • Visible in catalog (typically with "out of stock" notice)
  • Cannot be ordered
  • Awaiting replenishment
  • Automatic status (set when inventory hits zero)

Allowed Transitions:

  • → Active (inventory replenished)
  • → Discontinued (permanently remove)

Use Cases:

  • Popular items temporarily unavailable
  • Awaiting supplier delivery
  • Between production runs

Discontinued

Permanently removed from active catalog.

  • Not visible in catalog
  • Cannot be reactivated
  • Historical data preserved
  • Final status (no further transitions)

Allowed Transitions: None (terminal state)

Use Cases:

  • End-of-life products
  • Products no longer manufactured
  • Regulatory discontinued items
  • Legacy products

Rejected

Products that failed approval process.

  • Not approved for sale
  • Requires revision
  • Can be returned to draft for corrections

Allowed Transitions:

  • → Draft (revise and resubmit)

Use Cases:

  • Products failing compliance review
  • Incorrect pricing needing correction
  • Products with missing required information

Product Structure

Core Properties

Every product has these fundamental properties:

php
[
    'id' => 1,                          // Auto-generated ID
    'name' => 'Product Name',           // Display name (3-255 chars)
    'slug' => 'product-name',           // URL-friendly identifier
    'sku' => 'PROD-001',                // Stock Keeping Unit (unique)
    'type' => 'physical',               // Product type enum
    'status' => 'active',               // Status enum
    'is_variant' => false,              // Simple vs variant product
    'parent_product_id' => null,        // Master product ID (for variants)

    // Pricing
    'selling_price' => Money,           // Retail price (Money VO)
    'cost_price' => Money,              // Cost basis (Money VO)
    'currency' => 'USD',                // Currency code

    // Inventory
    'stock_quantity' => 100,            // Current stock level
    'reserved_quantity' => 10,          // Reserved for orders
    'available_quantity' => 90,         // Available = stock - reserved
    'reorder_point' => 20,              // Low stock threshold
    'reorder_quantity' => 50,           // Auto-reorder amount
    'track_inventory' => true,          // Enable inventory tracking

    // Description
    'short_description' => '...',       // Brief summary
    'description' => '...',             // Full description
    'meta_description' => '...',        // SEO description
    'meta_keywords' => '...',           // SEO keywords

    // Dimensions (for physical products)
    'weight' => 2.5,                    // Weight in kg
    'length' => 30.0,                   // Length in cm
    'width' => 20.0,                    // Width in cm
    'height' => 10.0,                   // Height in cm
    'dimensions_unit' => 'cm',          // Unit of measure

    // Relationships
    'category_id' => 5,                 // Product category
    'supplier_id' => 2,                 // Primary supplier
    'brand_id' => 3,                    // Product brand
    'tax_class_id' => 1,                // Tax classification

    // Settings
    'is_featured' => false,             // Featured product flag
    'is_taxable' => true,               // Subject to tax
    'requires_shipping' => true,        // Needs shipping
    'allow_backorders' => false,        // Accept orders when out of stock

    // Metadata
    'created_at' => '2025-01-15 10:00:00',
    'updated_at' => '2025-01-15 14:30:00',
    'deleted_at' => null,               // Soft delete timestamp
]

Money Value Object

All monetary amounts use the Money Value Object to prevent precision errors:

php
use App\Shared\Domain\ValueObjects\Money;

// Creating Money instances
$sellingPrice = Money::fromFloat(19.99, 'USD');
$costPrice = Money::fromCents(1200, 'USD'); // $12.00

// Accessing values
$sellingPrice->toFloat();    // 19.99
$sellingPrice->amount();     // 1999 (cents)
$sellingPrice->currency();   // "USD"
$sellingPrice->format();     // "USD 19.99"

// Arithmetic (returns new Money instance)
$profit = $sellingPrice->subtract($costPrice);
$total = $sellingPrice->multiply(10);

Why Money VO?

  • Prevents floating-point precision errors
  • Stores amounts as integers (cents)
  • Type-safe monetary operations
  • Currency awareness built-in

Simple vs Master Products

Simple Products

Single SKU products with straightforward inventory tracking.

php
[
    'name' => 'Laptop - Dell XPS 13',
    'sku' => 'DELL-XPS13-001',
    'type' => 'physical',
    'is_variant' => false,
    'parent_product_id' => null,
    'selling_price' => Money::fromFloat(999.99),
    'stock_quantity' => 50,
]

Characteristics:

  • One product = one SKU
  • Single inventory record
  • Direct pricing
  • No variations

Best For:

  • Unique items (specific laptop model)
  • Products without variations
  • Services with fixed pricing
  • Digital downloads (single version)

Master Products

Configuration template for generating product variants.

php
[
    'name' => 'T-Shirt - Cotton Basic',
    'type' => 'physical',
    'is_variant' => false,
    'variant_configuration' => [
        'attributes' => [
            'Size' => ['S', 'M', 'L', 'XL'],
            'Color' => ['Red', 'Blue', 'Black', 'White'],
        ],
    ],
]

Characteristics:

  • No direct SKU (variants have SKUs)
  • Template for variant generation
  • Defines variant attributes
  • No direct inventory tracking

Generates: 16 variants (4 sizes × 4 colors)

Variant Products

Individual products generated from master configuration.

php
[
    'name' => 'T-Shirt - Cotton Basic (M, Blue)',
    'sku' => 'TSHIRT-BASIC-M-BLUE',
    'type' => 'physical',
    'is_variant' => true,
    'parent_product_id' => 1,           // Master product ID
    'variant_attributes' => [
        'Size' => 'M',
        'Color' => 'Blue',
    ],
    'selling_price' => Money::fromFloat(19.99),
    'stock_quantity' => 25,
]

Characteristics:

  • Unique SKU per variant
  • Individual inventory tracking
  • Can override master pricing
  • Specific attribute combination

See: Product Variants Guide for detailed variant management.

Creating Products

Using CQRS Commands

The recommended approach using Command pattern:

php
use App\Modules\Operations\Application\Commands\CreateProductCommand;
use App\Modules\Operations\Application\DTOs\Product\CreateProductDTO;
use App\Shared\Application\Bus\CommandBus;

// In controller
public function store(CreateProductRequest $request): JsonResponse
{
    $command = new CreateProductCommand(
        dto: CreateProductDTO::fromArray($request->validated())
    );

    $product = $this->commandBus->dispatch($command);

    return response()->json([
        'message' => 'Product created successfully',
        'data' => new ProductResource($product),
    ], 201);
}

CreateProductDTO

Complete DTO with all available fields:

php
$dto = CreateProductDTO::fromArray([
    // Required
    'name' => 'Laptop - Dell XPS 13',

    // Optional - Basic Info
    'slug' => 'laptop-dell-xps-13',
    'sku' => 'DELL-XPS13-001',        // Auto-generated if not provided
    'type' => 'physical',             // Default: physical
    'short_description' => 'Ultra-portable laptop',
    'description' => 'Full product description...',

    // Pricing
    'selling_price' => 999.99,        // Converted to Money VO
    'cost_price' => 750.00,
    'currency' => 'USD',              // Default: USD

    // Inventory
    'stock_quantity' => 50,           // Default: 0
    'reorder_point' => 10,
    'reorder_quantity' => 25,
    'track_inventory' => true,        // Default: true
    'allow_backorders' => false,

    // Dimensions
    'weight' => 1.2,                  // kg
    'length' => 30.0,                 // cm
    'width' => 20.0,
    'height' => 2.0,
    'dimensions_unit' => 'cm',

    // Relationships
    'category_id' => 5,
    'supplier_id' => 2,
    'brand_id' => 3,
    'tax_class_id' => 1,

    // Settings
    'is_featured' => false,
    'is_taxable' => true,
    'requires_shipping' => true,

    // SEO
    'meta_description' => 'Buy Dell XPS 13...',
    'meta_keywords' => 'laptop, dell, xps',

    // Tags (array of tag IDs)
    'tags' => [1, 2, 3],
]);

API Request Example

Creating a product via API:

bash
curl -X POST https://api.crm.test/api/v1/operations/products \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Laptop - Dell XPS 13",
    "sku": "DELL-XPS13-001",
    "type": "physical",
    "selling_price": 999.99,
    "cost_price": 750.00,
    "stock_quantity": 50,
    "reorder_point": 10,
    "category_id": 5,
    "supplier_id": 2,
    "short_description": "Ultra-portable laptop with stunning display",
    "description": "The Dell XPS 13 features...",
    "weight": 1.2,
    "length": 30,
    "width": 20,
    "height": 2,
    "track_inventory": true
  }'

Response:

json
{
  "message": "Product created successfully",
  "data": {
    "id": 42,
    "name": "Laptop - Dell XPS 13",
    "slug": "laptop-dell-xps-13",
    "sku": "DELL-XPS13-001",
    "type": "physical",
    "status": "draft",
    "selling_price": 999.99,
    "cost_price": 750.00,
    "stock_quantity": 50,
    "available_quantity": 50,
    "category": {
      "id": 5,
      "name": "Electronics"
    },
    "supplier": {
      "id": 2,
      "name": "Tech Supplies Inc"
    },
    "created_at": "2025-01-15T10:30:00Z"
  }
}

Updating Products

Using CQRS Commands

php
use App\Modules\Operations\Application\Commands\UpdateProductCommand;
use App\Modules\Operations\Application\DTOs\Product\UpdateProductDTO;

$command = new UpdateProductCommand(
    productId: 42,
    dto: UpdateProductDTO::fromArray($request->validated())
);

$product = $this->commandBus->dispatch($command);

Partial Updates

UpdateProductDTO supports partial updates - only include fields you want to change:

php
$dto = UpdateProductDTO::fromArray([
    'selling_price' => 899.99,        // New price
    'stock_quantity' => 75,            // Update stock
    // Other fields remain unchanged
]);

API Request Example

bash
curl -X PUT https://api.crm.test/api/v1/operations/products/42 \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "selling_price": 899.99,
    "stock_quantity": 75,
    "short_description": "Updated description"
  }'

Product Lifecycle Operations

Activate Product

Transition from draft to active status:

php
use App\Modules\Operations\Application\Commands\ActivateProductCommand;

$command = new ActivateProductCommand(productId: 42);
$product = $this->commandBus->dispatch($command);

API Request:

bash
curl -X POST https://api.crm.test/api/v1/operations/products/42/activate \
  -H "Authorization: Bearer {token}"

Effect:

  • Status changes to active
  • Product becomes visible in catalog
  • Inventory tracking begins
  • Can be ordered by customers
  • Fires ProductActivated domain event

Deactivate Product

Temporarily disable a product:

php
use App\Modules\Operations\Application\Commands\DeactivateProductCommand;

$command = new DeactivateProductCommand(
    productId: 42,
    reason: 'Seasonal product - off season'
);

$product = $this->commandBus->dispatch($command);

API Request:

bash
curl -X POST https://api.crm.test/api/v1/operations/products/42/deactivate \
  -H "Authorization: Bearer {token}" \
  -d '{
    "reason": "Seasonal product - off season"
  }'

Effect:

  • Status changes to inactive
  • Product hidden from catalog
  • Cannot be ordered
  • Inventory preserved
  • Can be reactivated later

Discontinue Product

Permanently remove from catalog:

php
use App\Modules\Operations\Application\Commands\DiscontinueProductCommand;

$command = new DiscontinueProductCommand(
    productId: 42,
    reason: 'End of life - no longer manufactured'
);

$product = $this->commandBus->dispatch($command);

API Request:

bash
curl -X POST https://api.crm.test/api/v1/operations/products/42/discontinue \
  -H "Authorization: Bearer {token}" \
  -d '{
    "reason": "End of life - no longer manufactured"
  }'

Effect:

  • Status changes to discontinued
  • Product permanently removed from catalog
  • Cannot be reactivated
  • Historical data preserved
  • Final status (terminal)

Product Relationships

Categories

Hierarchical product categorization:

php
// Assign category during creation
'category_id' => 5

// Category relationship
$product->category;  // Returns Category model
$product->category->name;  // "Electronics"
$product->category->parent;  // Parent category (if nested)

Examples: Electronics > Laptops > Gaming Laptops

Suppliers

Primary vendor for product sourcing:

php
'supplier_id' => 2

$product->supplier;  // Returns Supplier model
$product->supplier->name;  // "Tech Supplies Inc"
$product->supplier->email;  // "orders@techsupplies.com"

Use Cases:

  • Purchase order generation
  • Reorder automation
  • Supplier performance tracking

Brands

Product manufacturer or brand:

php
'brand_id' => 3

$product->brand;  // Returns Brand model
$product->brand->name;  // "Dell"
$product->brand->website;  // "https://dell.com"

Use Cases:

  • Brand filtering
  • Brand pages
  • Marketing campaigns

Tags

Flexible multi-tag assignment:

php
// Assign tags (many-to-many)
$product->tags()->attach([1, 2, 3]);

// Tags during creation
'tags' => [1, 2, 3]

// Access tags
$product->tags;  // Collection of Tag models
$product->tags->pluck('name');  // ["Bestseller", "New Arrival", "On Sale"]

Use Cases:

  • Product filtering
  • Marketing segments
  • Custom collections
  • Dynamic product groups

Product Attributes (EAV)

The Entity-Attribute-Value (EAV) system provides flexible custom properties:

Defining Attributes

Attributes are defined globally and can be assigned to products:

php
// Attribute Types
TEXT        // Short text (e.g., "Color Name")
TEXTAREA    // Long text (e.g., "Care Instructions")
NUMBER      // Numeric (e.g., "Megapixels")
BOOLEAN     // Yes/No (e.g., "Waterproof")
DATE        // Date value (e.g., "Release Date")
SELECT      // Single choice (e.g., "Warranty Period")
MULTISELECT // Multiple choices (e.g., "Features")

Assigning Attributes

bash
curl -X POST https://api.crm.test/api/v1/operations/products/42/attributes \
  -H "Authorization: Bearer {token}" \
  -d '{
    "attribute_code": "warranty_period",
    "value": "2 years"
  }'

Querying Attributes

php
$product->attributes;  // Collection of product attributes

// Get specific attribute
$warranty = $product->getAttribute('warranty_period');
$warranty->value;  // "2 years"

// Check if attribute exists
$product->hasAttribute('waterproof');  // true/false

Use Cases

  • Specifications: Technical specs (CPU, RAM, storage)
  • Features: Product features (Bluetooth, GPS, 4K)
  • Certifications: Compliance (CE, FCC, RoHS)
  • Marketing: Custom properties (Eco-friendly, Handmade)

Searching and Filtering

Search across product name, SKU, and description:

bash
curl -X GET "https://api.crm.test/api/v1/operations/products/search?q=laptop" \
  -H "Authorization: Bearer {token}"

Searches:

  • Product name
  • SKU
  • Short description
  • Long description
  • Meta keywords

Filter by Status

bash
curl -X GET "https://api.crm.test/api/v1/operations/products?status=active" \
  -H "Authorization: Bearer {token}"

Available Statuses: draft, active, inactive, discontinued, out_of_stock, pending_approval, rejected

Filter by Category

bash
curl -X GET "https://api.crm.test/api/v1/operations/products?category_id=5" \
  -H "Authorization: Bearer {token}"

Filter by Supplier

bash
curl -X GET "https://api.crm.test/api/v1/operations/products?supplier_id=2" \
  -H "Authorization: Bearer {token}"

Price Range Filter

bash
curl -X GET "https://api.crm.test/api/v1/operations/products?min_price=500&max_price=1500" \
  -H "Authorization: Bearer {token}"

Stock Level Filter

bash
# Low stock products
curl -X GET "https://api.crm.test/api/v1/operations/products?stock_status=low" \
  -H "Authorization: Bearer {token}"

# Out of stock
curl -X GET "https://api.crm.test/api/v1/operations/products?stock_status=out" \
  -H "Authorization: Bearer {token}"

Combined Filters

bash
curl -X GET "https://api.crm.test/api/v1/operations/products?status=active&category_id=5&min_price=500&sort_by=price&sort_direction=desc&per_page=25" \
  -H "Authorization: Bearer {token}"

Bulk Operations

Bulk Status Update

Update status for multiple products:

bash
curl -X POST https://api.crm.test/api/v1/operations/products/bulk-action \
  -H "Authorization: Bearer {token}" \
  -d '{
    "action": "activate",
    "product_ids": [42, 43, 44, 45]
  }'

Available Actions:

  • activate - Activate selected products
  • deactivate - Deactivate selected products
  • discontinue - Discontinue selected products
  • delete - Soft delete selected products

Bulk Export

Export products to CSV or Excel:

bash
curl -X POST https://api.crm.test/api/v1/operations/products/export \
  -H "Authorization: Bearer {token}" \
  -d '{
    "format": "csv",
    "filters": {
      "status": "active",
      "category_id": 5
    }
  }'

Response:

json
{
  "message": "Export queued successfully",
  "data": {
    "job_id": "export-123",
    "download_url": "https://api.crm.test/downloads/products-export-123.csv",
    "status": "processing",
    "estimated_completion": "2025-01-15T10:35:00Z"
  }
}

CQRS Examples

Commands (Write Operations)

All product modifications use commands:

php
// Create
$command = new CreateProductCommand(dto: $dto);
$product = $this->commandBus->dispatch($command);

// Update
$command = new UpdateProductCommand(productId: 42, dto: $dto);
$product = $this->commandBus->dispatch($command);

// Activate
$command = new ActivateProductCommand(productId: 42);
$product = $this->commandBus->dispatch($command);

// Deactivate
$command = new DeactivateProductCommand(productId: 42, reason: '...');
$product = $this->commandBus->dispatch($command);

// Discontinue
$command = new DiscontinueProductCommand(productId: 42, reason: '...');
$product = $this->commandBus->dispatch($command);

// Delete
$command = new DeleteProductCommand(productId: 42);
$this->commandBus->dispatch($command);

Transaction Handling: CommandBus automatically wraps in database transaction.

Queries (Read Operations)

All product retrievals use queries:

php
// Get single product
$query = new GetProductByIdQuery(
    productId: 42,
    includes: ['category', 'supplier', 'brand', 'tags']
);
$product = $this->queryBus->dispatch($query);

// Get products with filters
$query = new GetProductsQuery(
    filterDTO: ProductFilterDTO::fromArray([
        'status' => 'active',
        'category_id' => 5,
        'min_price' => 500,
        'max_price' => 1500,
        'sort_by' => 'price',
        'sort_direction' => 'desc',
        'per_page' => 25,
    ])
);
$products = $this->queryBus->dispatch($query);

// Search products
$query = new SearchProductsQuery(
    searchTerm: 'laptop',
    filters: ['status' => 'active']
);
$results = $this->queryBus->dispatch($query);

// Low stock products
$query = new GetLowStockProductsQuery(
    warehouseId: 1  // Optional: filter by warehouse
);
$lowStockProducts = $this->queryBus->dispatch($query);

No Transactions: Queries are read-only, no transaction wrapping.

Domain Events

Product operations emit domain events:

php
// Events emitted automatically by domain methods

ProductCreated::class
- Fired when: New product created
- Payload: Product ID, name, SKU, status
- Listeners: Sync to search index, notify catalog managers

ProductUpdated::class
- Fired when: Product details changed
- Payload: Product ID, changed fields
- Listeners: Update search index, invalidate cache

ProductActivated::class
- Fired when: Product activated
- Payload: Product ID, activation timestamp
- Listeners: Publish to catalog, notify sales team

ProductDeactivated::class
- Fired when: Product deactivated
- Payload: Product ID, reason
- Listeners: Remove from catalog, notify sales team

ProductDiscontinued::class
- Fired when: Product discontinued
- Payload: Product ID, reason
- Listeners: Archive product, update reporting

ProductDeleted::class
- Fired when: Product deleted
- Payload: Product ID, deletion timestamp
- Listeners: Clean up related data, audit log

Event Listeners: Register in App\Providers\AppServiceProvider

API Endpoints

Product CRUD

MethodEndpointDescription
GET/productsList products with filters/pagination
POST/productsCreate new product
GET/products/{id}Get single product details
PUT/products/{id}Update product
DELETE/products/{id}Delete product (soft delete)

Product Lifecycle

MethodEndpointDescription
POST/products/{id}/activateActivate product
POST/products/{id}/deactivateDeactivate product
POST/products/{id}/discontinueDiscontinue product
MethodEndpointDescription
GET/products/searchFull-text search
GET/products/catalogPublic catalog (active only)
GET/products/low-stockProducts below reorder point
GET/products/out-of-stockOut of stock products

Product Attributes

MethodEndpointDescription
GET/products/{id}/attributesGet product attributes
POST/products/{id}/attributesAssign attribute to product
PUT/products/{id}/attributes/{attribute}Update attribute value
DELETE/products/{id}/attributes/{attribute}Remove attribute from product

Bulk Operations

MethodEndpointDescription
POST/products/bulk-actionBulk status update/delete
POST/products/exportExport products to CSV/Excel
GET/products/statisticsProduct statistics dashboard

See: API Reference for complete documentation.

Next Steps

  1. Create Products - Follow the Creating Products Tutorial
  2. Setup Variants - Read the Product Variants Guide
  3. Manage Inventory - Explore Multi-Warehouse Inventory
  4. Order from Suppliers - Learn Purchase Order Workflow

Documentation for SynthesQ CRM/ERP Platform