Assist_Design/docs/PRODUCT-CATALOG-ARCHITECTURE.md

25 KiB

Product Catalog & SKU Architecture - Complete Guide

Subscription-Aware Catalog Behavior

The portal surfaces catalog content and checkout actions based on the customer's existing subscriptions. This avoids duplicate Internet orders and automatically exposes SIM family discounts to eligible customers.

  • Internet orders

    • The backend already enforces a duplication guard during order validation (see Orders validation: Internet duplication guard).
    • The portal Internet catalog disables the Configure button if /subscriptions/active contains an active Internet service. The checkout flow also blocks submission client-side with a clear error.
  • SIM family discounts

    • The backend GET /catalog/sim/plans personalizes the plan list per user. If a user has an existing active SIM service (checked via WHMCS), the response includes family discount plans with hasFamilyDiscount: true.
    • The portal SIM catalog automatically renders a Family Discount section and banner when such plans are present.

Implementation notes

  • Portal uses the useActiveSubscriptions() hook which calls GET /subscriptions/active and relies on the shared Subscription type (product/group name and status) to detect Internet/SIM services.
  • No guessing of API response shapes; behavior aligns with the documented BFF controllers in apps/bff/src/subscriptions/subscriptions.controller.ts and catalog services.

This document consolidates the complete SKU-based architecture for the catalog and order system, including implementation patterns, edge cases, and migration strategy.

Core Principles

1. Frontend Responsibility

  • Frontend loads ALL required SKUs from catalog API
  • Frontend determines which SKUs to include based on customer selections
  • Frontend passes explicit SKU list to backend

2. Backend Simplicity

  • Backend processes provided SKU list without guessing
  • No order-type-specific logic for determining products
  • Clean validation and error handling

3. Salesforce as Source of Truth

  • All product relationships defined in Salesforce
  • Catalog API exposes all necessary product types
  • Clear product classification via Item_Class__c

Product Classification

Item_Class__c Values

'Service'      -- Main customer-selectable products (Internet plans, SIM plans, VPN)
'Activation'   -- Required one-time activation fees
'Installation' -- Installation options (one-time or monthly)
'Add-on'       -- Optional additional services

Portal Visibility Logic

Portal_Catalog__c = true     -- Visible in main catalog (customer selects)
Portal_Accessible__c = true  -- Can be used in orders (includes hidden fees/add-ons)

SKU Naming Strategy

Detailed SKU Format

Use explicit product variants with all relevant attributes:

Internet SKUs:

  • INTERNET-SILVER-HOME-1G
  • INTERNET-GOLD-APT-1G
  • INTERNET-PLATINUM-APT-100M
  • INTERNET-INSTALL-SINGLE
  • INTERNET-INSTALL-WEEKEND
  • INTERNET-ADDON-HIKARI-DENWA-INSTALL

SIM SKUs:

  • SIM-DATA-ONLY-5GB
  • SIM-DATA-VOICE-50GB
  • SIM-DATA-VOICE-50GB-FAMILY
  • SIM-ACTIVATION-FEE
  • SIM-ADDON-VOICE-MAIL

VPN SKUs:

  • VPN-REMOTE-ACCESS-USA-SF
  • VPN-REMOTE-ACCESS-UK-LONDON
  • VPN-ACTIVATION-FEE

New Catalog API Structure

Main Catalog Endpoint

GET /catalog
// Returns only customer-selectable products (Portal_Catalog__c = true)
{
  internet: Array<{
    id: string,
    name: string,
    sku: string, // Detailed format: INTERNET-SILVER-APT-1G
    tier: string,
    offeringType: string,
    monthlyPrice: number
  }>,
  sim: Array<{
    id: string,
    name: string,
    sku: string, // Detailed format: SIM-DATA-VOICE-50GB
    dataSize: string,
    planType: string,
    hasFamilyDiscount: boolean
  }>,
  vpn: Array<{
    id: string,
    name: string,
    sku: string // Detailed format: VPN-REMOTE-ACCESS-USA-SF
  }>
}
GET /catalog/sim/activation-fees
// Returns SIM activation products (Item_Class__c = 'Activation')
Array<{id: string, name: string, sku: string, price: number, isDefault: boolean}>

GET /catalog/vpn/activation-fees?region=<region>
// Returns VPN activation products (Item_Class__c = 'Activation')
Array<{id: string, name: string, sku: string, price: number, isDefault: boolean}>

GET /catalog/internet/installations
// Returns Internet installation options (Item_Class__c = 'Installation')
Array<{id: string, name: string, sku: string, billingCycle: string, price: number, installmentType: string}>

GET /catalog/internet/addons
// Returns Internet add-ons (Item_Class__c = 'Add-on')
Array<{id: string, name: string, sku: string, price: number, billingCycle: string, autoAdd: boolean}>

GET /catalog/sim/addons
// Returns SIM add-ons (Item_Class__c = 'Add-on')
Array<{id: string, name: string, sku: string, price: number, billingCycle: string}>

Frontend Implementation Patterns

1. Data Loading Pattern

const ConfigurePage = () => {
  const [serviceProducts, setServiceProducts] = useState([]);
  const [activationFees, setActivationFees] = useState([]);
  const [addons, setAddons] = useState([]);

  useEffect(() => {
    const loadCatalogData = async () => {
      try {
        // Load all required data in parallel
        const [catalog, activation, addonsData] = await Promise.all([
          authenticatedApi.get("/catalog"),
          authenticatedApi.get("/catalog/sim/activation-fees"),
          authenticatedApi.get("/catalog/sim/addons"),
        ]);

        setServiceProducts(catalog.sim);
        setActivationFees(activation);
        setAddons(addonsData);
      } catch (error) {
        console.error("Failed to load catalog data:", error);
        // Handle error - show fallback or redirect
      }
    };

    loadCatalogData();
  }, []);
};

2. SKU Building Pattern

const buildOrderSKUs = () => {
  const skus = [];

  // Always add service SKU (detailed format)
  if (selectedPlan?.sku) {
    skus.push(selectedPlan.sku); // e.g., "SIM-DATA-VOICE-50GB"
  }

  // Add required activation fee
  const defaultActivation = activationFees.find(f => f.isDefault || f.autoAdd);
  if (defaultActivation) {
    skus.push(defaultActivation.sku); // e.g., "SIM-ACTIVATION-FEE"
  }

  // Add selected add-ons
  selectedAddons.forEach(addon => {
    skus.push(addon.sku); // e.g., "SIM-ADDON-VOICE-MAIL"

    // Add dependent products if needed
    if (addon.requiredProducts) {
      skus.push(...addon.requiredProducts);
    }
  });

  return [...new Set(skus)]; // Remove duplicates
};

3. Order Submission Pattern

const submitOrder = () => {
  const skus = buildOrderSKUs();

  const params = new URLSearchParams({
    orderType: "SIM",
    skus: JSON.stringify(skus), // Pass complete SKU array
    simType: selectedSimType,
    // ... other customer selections for order header
  });

  router.push(`/checkout?${params.toString()}`);
};

SIM Configure Page - Complete Implementation

// apps/portal/src/app/catalog/sim/configure/page.tsx
"use client";

import { useEffect, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { authenticatedApi } from "@/lib/api";

interface SimPlan {
  id: string;
  name: string;
  sku: string; // Detailed format: SIM-DATA-VOICE-50GB
  dataSize: string;
  planType: string;
  hasFamilyDiscount: boolean;
  monthlyPrice: number;
}

interface ActivationFee {
  id: string;
  name: string;
  sku: string; // SIM-ACTIVATION-FEE
  price: number;
  isDefault: boolean;
  autoAdd: boolean;
}

interface SimAddon {
  id: string;
  name: string;
  sku: string; // SIM-ADDON-VOICE-MAIL
  price: number;
  billingCycle: string;
  description?: string;
}

export default function SimConfigurePage() {
  const router = useRouter();
  const params = useSearchParams();
  const planSku = params.get("sku"); // Detailed SKU from catalog

  // State
  const [loading, setLoading] = useState(true);
  const [selectedPlan, setSelectedPlan] = useState<SimPlan | null>(null);
  const [activationFees, setActivationFees] = useState<ActivationFee[]>([]);
  const [addons, setAddons] = useState<SimAddon[]>([]);

  // Customer selections
  const [simType, setSimType] = useState<"eSIM" | "Physical SIM" | null>(null);
  const [selectedAddons, setSelectedAddons] = useState<string[]>([]);
  const [eid, setEid] = useState("");

  // Load catalog data
  useEffect(() => {
    let mounted = true;

    const loadCatalogData = async () => {
      if (!planSku) {
        router.push('/catalog/sim');
        return;
      }

      try {
        // Load all required data in parallel
        const [catalog, activation, addonsData] = await Promise.all([
          authenticatedApi.get<{sim: SimPlan[]}>("/catalog"),
          authenticatedApi.get<ActivationFee[]>("/catalog/sim/activation-fees"),
          authenticatedApi.get<SimAddon[]>("/catalog/sim/addons")
        ]);

        if (mounted) {
          const plan = catalog.sim.find(p => p.sku === planSku);
          if (plan) {
            setSelectedPlan(plan);
            setActivationFees(activation);
            setAddons(addonsData);
          } else {
            router.push('/catalog/sim');
          }
        }
      } catch (error) {
        console.error("Failed to load catalog data:", error);
        if (mounted) router.push('/catalog/sim');
      } finally {
        if (mounted) setLoading(false);
      }
    };

    loadCatalogData();
    return () => { mounted = false; };
  }, [planSku, router]);

  // Build complete SKU list based on selections
  const buildOrderSKUs = (): string[] => {
    const skus: string[] = [];

    // Always add service SKU (detailed format)
    if (selectedPlan?.sku) {
      skus.push(selectedPlan.sku); // e.g., "SIM-DATA-VOICE-50GB"
    }

    // Add required activation fee (auto-add or default)
    const requiredActivation = activationFees.find(f => f.autoAdd || f.isDefault);
    if (requiredActivation) {
      skus.push(requiredActivation.sku); // "SIM-ACTIVATION-FEE"
    }

    // Add selected add-ons
    selectedAddons.forEach(addonSku => {
      skus.push(addonSku); // e.g., "SIM-ADDON-VOICE-MAIL"
    });

    // Remove duplicates
    return [...new Set(skus)];
  };

  // Calculate pricing
  const calculatePricing = () => {
    let monthlyTotal = 0;
    let oneTimeTotal = 0;

    // Service plan (monthly)
    if (selectedPlan) {
      monthlyTotal += selectedPlan.monthlyPrice || 0;
    }

    // Activation fee (one-time)
    const requiredActivation = activationFees.find(f => f.autoAdd || f.isDefault);
    if (requiredActivation) {
      oneTimeTotal += requiredActivation.price;
    }

    // Add-ons (monthly)
    selectedAddons.forEach(addonSku => {
      const addon = addons.find(a => a.sku === addonSku);
      if (addon && addon.billingCycle === 'Monthly') {
        monthlyTotal += addon.price;
      }
    });

    return { monthlyTotal, oneTimeTotal };
  };

  // Submit order
  const handleSubmit = () => {
    if (!selectedPlan || !simType) return;

    const skus = buildOrderSKUs();
    const { monthlyTotal, oneTimeTotal } = calculatePricing();

    const params = new URLSearchParams({
      orderType: "SIM", // Always "SIM", not "eSIM"
      skus: JSON.stringify(skus), // Complete SKU array

      // Customer selections (for order header)
      planName: selectedPlan.name,
      simType: simType,
      ...(eid && { eid }),

      // Pricing (for display)
      monthlyPrice: monthlyTotal.toString(),
      oneTimePrice: oneTimeTotal.toString(),
    });

    router.push(`/checkout?${params.toString()}`);
  };

  if (loading) {
    return <div>Loading...</div>;
  }

  if (!selectedPlan) {
    return <div>Plan not found</div>;
  }

  return (
    <div className="max-w-4xl mx-auto p-6">
      <h1 className="text-2xl font-bold mb-6">Configure {selectedPlan.name}</h1>

      {/* SIM Type Selection */}
      <section className="mb-8">
        <h2 className="text-xl font-semibold mb-4">SIM Type</h2>
        <div className="grid grid-cols-2 gap-4">
          <label className="border rounded-lg p-4 cursor-pointer hover:bg-gray-50">
            <input
              type="radio"
              name="simType"
              value="Physical SIM"
              checked={simType === "Physical SIM"}
              onChange={(e) => setSimType(e.target.value as "Physical SIM")}
              className="mr-3"
            />
            <div>
              <div className="font-medium">Physical SIM</div>
              <div className="text-sm text-gray-600">Traditional SIM card</div>
            </div>
          </label>

          <label className="border rounded-lg p-4 cursor-pointer hover:bg-gray-50">
            <input
              type="radio"
              name="simType"
              value="eSIM"
              checked={simType === "eSIM"}
              onChange={(e) => setSimType(e.target.value as "eSIM")}
              className="mr-3"
            />
            <div>
              <div className="font-medium">eSIM</div>
              <div className="text-sm text-gray-600">Digital SIM</div>
            </div>
          </label>
        </div>

        {/* EID input for eSIM */}
        {simType === "eSIM" && (
          <div className="mt-4">
            <label className="block text-sm font-medium mb-2">
              EID (Required for eSIM)
            </label>
            <input
              type="text"
              value={eid}
              onChange={(e) => setEid(e.target.value)}
              className="w-full border rounded-lg px-3 py-2"
              placeholder="Enter your device EID"
            />
          </div>
        )}
      </section>

      {/* Add-ons Selection */}
      <section className="mb-8">
        <h2 className="text-xl font-semibold mb-4">Add-ons (Optional)</h2>
        <div className="space-y-3">
          {addons.map(addon => (
            <label key={addon.id} className="flex items-center border rounded-lg p-4 cursor-pointer hover:bg-gray-50">
              <input
                type="checkbox"
                checked={selectedAddons.includes(addon.sku)}
                onChange={(e) => {
                  if (e.target.checked) {
                    setSelectedAddons([...selectedAddons, addon.sku]);
                  } else {
                    setSelectedAddons(selectedAddons.filter(sku => sku !== addon.sku));
                  }
                }}
                className="mr-3"
              />
              <div className="flex-1">
                <div className="font-medium">{addon.name}</div>
                {addon.description && (
                  <div className="text-sm text-gray-600">{addon.description}</div>
                )}
              </div>
              <div className="text-right">
                <div className="font-medium">¥{addon.price.toLocaleString()}</div>
                <div className="text-sm text-gray-600">{addon.billingCycle}</div>
              </div>
            </label>
          ))}
        </div>
      </section>

      {/* Pricing Summary */}
      <section className="mb-8">
        <div className="bg-gray-50 rounded-lg p-4">
          <h3 className="font-semibold mb-3">Order Summary</h3>

          {/* Service */}
          <div className="flex justify-between mb-2">
            <span>{selectedPlan.name}</span>
            <span>¥{(selectedPlan.monthlyPrice || 0).toLocaleString()}/month</span>
          </div>

          {/* Activation Fee */}
          {activationFees.find(f => f.autoAdd || f.isDefault) && (
            <div className="flex justify-between mb-2">
              <span>Activation Fee</span>
              <span>¥{activationFees.find(f => f.autoAdd || f.isDefault)!.price.toLocaleString()} (one-time)</span>
            </div>
          )}

          {/* Add-ons */}
          {selectedAddons.map(addonSku => {
            const addon = addons.find(a => a.sku === addonSku);
            return addon ? (
              <div key={addonSku} className="flex justify-between mb-2">
                <span>{addon.name}</span>
                <span>¥{addon.price.toLocaleString()}/{addon.billingCycle.toLowerCase()}</span>
              </div>
            ) : null;
          })}

          {/* Totals */}
          <hr className="my-3" />
          <div className="flex justify-between font-semibold">
            <span>Monthly Total</span>
            <span>¥{calculatePricing().monthlyTotal.toLocaleString()}</span>
          </div>
          <div className="flex justify-between font-semibold">
            <span>One-time Total</span>
            <span>¥{calculatePricing().oneTimeTotal.toLocaleString()}</span>
          </div>
        </div>
      </section>

      {/* Submit Button */}
      <button
        onClick={handleSubmit}
        disabled={!selectedPlan || !simType || (simType === "eSIM" && !eid)}
        className="w-full bg-blue-600 text-white font-bold py-3 px-6 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
      >
        Continue to Checkout
      </button>
    </div>
  );
}

Backend Implementation

Enhanced Catalog Controller

@Controller("catalog")
export class CatalogController {
  @Get("sim/activation-fees")
  @ApiOperation({ summary: "Get SIM activation fee options" })
  async getSimActivationFees() {
    return this.catalogService.getSimActivationFees();
  }

  @Get("vpn/activation-fees")
  @ApiOperation({ summary: "Get VPN activation fee options" })
  async getVpnActivationFees(@Query("region") region?: string) {
    return this.catalogService.getVpnActivationFees(region);
  }

  @Get("internet/installations")
  @ApiOperation({ summary: "Get Internet installation options" })
  async getInternetInstallations() {
    return this.catalogService.getInternetInstallations();
  }

  @Get("internet/addons")
  @ApiOperation({ summary: "Get Internet add-on options" })
  async getInternetAddons() {
    return this.catalogService.getInternetAddons();
  }

  @Get("sim/addons")
  @ApiOperation({ summary: "Get SIM add-on options" })
  async getSimAddons() {
    return this.catalogService.getSimAddons();
  }
}

Simplified Order Processing

private async createOrderItems(orderId: string, body: CreateOrderBody): Promise<void> {
  // Parse SKUs from selections (detailed format)
  let skus: string[] = [];

  if (body.selections.skus && typeof body.selections.skus === 'string') {
    try {
      skus = JSON.parse(body.selections.skus);
    } catch (e) {
      this.logger.warn("Failed to parse SKUs JSON, falling back to individual fields");
    }
  }

  // Fallback to individual SKU fields for backward compatibility
  if (skus.length === 0) {
    if (body.selections.skuService) skus.push(body.selections.skuService as string);
    if (body.selections.skuActivation) skus.push(body.selections.skuActivation as string);
    if (body.selections.skuInstall) skus.push(body.selections.skuInstall as string);
    if (body.selections.skuAddons) {
      const addons = Array.isArray(body.selections.skuAddons)
        ? body.selections.skuAddons
        : [body.selections.skuAddons];
      skus.push(...addons.map(String));
    }
  }

  // Remove duplicates and empty values
  skus = [...new Set(skus.filter(Boolean))];

  if (skus.length === 0) {
    throw new BadRequestException("No products specified for order");
  }

  // Create OrderItems for each detailed SKU
  const pricebookId = await this.findPortalPricebookId();

  for (const sku of skus) {
    const meta = await this.getProductMetaBySku(pricebookId, sku);

    if (!meta?.pbeId) {
      this.logger.error({ sku }, "PricebookEntry not found for SKU");
      throw new NotFoundException(`Product not found: ${sku}`);
    }

    await this.sf.sobject("OrderItem").create({
      OrderId: orderId,
      PricebookEntryId: meta.pbeId,
      Quantity: 1,
      UnitPrice: null, // Use pricebook price
    });

    this.logger.log({ orderId, sku, pbeId: meta.pbeId }, "OrderItem created");
  }
}

Edge Case Handling

1. Multiple Activation Fees Found

Solution: Add Is_Default__c field to Product2

-- Product2 fields for disambiguation
Is_Default__c           Checkbox    -- Default choice when multiple options exist
Display_Order__c        Number      -- Ordering for UI selection
Auto_Add__c            Checkbox    -- Automatically add to orders (required fees)

Implementation:

// Catalog service - return default activation fee
const activationFees = records
  .filter(r => r.Item_Class__c === "Activation")
  .map(r => ({
    id: r.Id,
    sku: r.StockKeepingUnit, // Correct field name
    name: r.Name,
    price: r.PricebookEntries?.records?.[0]?.UnitPrice || 0,
    isDefault: r.Is_Default__c === true,
    autoAdd: r.Auto_Add__c === true,
  }))
  .sort((a, b) => (b.isDefault ? 1 : 0) - (a.isDefault ? 1 : 0));

2. Missing Required Products

Solution: Validation in catalog service with fallback

async getSimActivationFees(): Promise<ActivationFee[]> {
  const fees = await this.queryActivationFees('SIM');

  if (fees.length === 0) {
    this.logger.warn("No SIM activation fees found in catalog");
    return [];
  }

  if (!fees.some(f => f.isDefault)) {
    this.logger.warn("No default SIM activation fee, marking first as default");
    fees[0].isDefault = true;
  }

  return fees;
}

3. Product Relationships

Solution: Add relationship fields to Product2

-- Product2 relationship fields
Required_Products__c    Text(1000)  -- JSON array of required SKUs
Dependent_Products__c   Text(1000)  -- JSON array of auto-added SKUs
Mutually_Exclusive__c   Text(1000)  -- JSON array of conflicting SKUs

Example Usage:

-- Hikari Denwa service
Required_Products__c = '["INTERNET-ADDON-HIKARI-DENWA-INSTALL"]'

-- Weekend installation
Mutually_Exclusive__c = '["INTERNET-INSTALL-WEEKDAY"]'

4. Regional/Conditional Products

Solution: Use personalization logic

GET /catalog/personalized
// Already filters by account eligibility
// Extend to include conditional activation fees

GET /catalog/vpn/activation-fees?region=USA-SF
// Filter activation fees by region if needed

Key Changes Summary

1. Field Name Corrections

// OLD: Inconsistent field names
(Portal_Catalog__c, StockKeepingUnit, Product2Categories1__c);

// NEW: Correct Salesforce field names
(Portal_Catalog__c, Portal_Accessible__c, StockKeepingUnit, Product2Categories1__c);

2. SKU Strategy Change

// OLD: Simple SKUs
("SIM-DATA-VOICE-50GB", "INTERNET-SILVER");

// NEW: Detailed SKUs with all attributes
("SIM-DATA-VOICE-50GB-FAMILY", "INTERNET-SILVER-APT-1G");

3. Order Type Normalization

// OLD: Separate eSIM and SIM types
orderType: simType === "eSIM" ? "eSIM" : "SIM"

// NEW: Always use "SIM", differentiate with simType field
orderType: "SIM",
simType: selectedSimType, // "eSIM" or "Physical SIM"

4. Complete SKU Control

// OLD: Incomplete product coverage
const params = new URLSearchParams({
  orderType: "SIM",
  skuService: plan.sku,
  // Missing activation fee!
});

// NEW: Complete SKU coverage
const skus = [
  selectedPlan.sku, // Service: "SIM-DATA-VOICE-50GB"
  activationFees.find(f => f.isDefault).sku, // Activation: "SIM-ACTIVATION-FEE"
  ...selectedAddons, // Add-ons: ["SIM-ADDON-VOICE-MAIL"]
];

const params = new URLSearchParams({
  orderType: "SIM",
  skus: JSON.stringify(skus),
  simType: selectedSimType,
});

Migration Strategy

Phase 1: Backend Infrastructure (Completed)

  • New catalog endpoints
  • Enhanced order processing with backward compatibility
  • Comprehensive validation and error handling

Phase 2: 🔄 Salesforce Configuration (Next)

-- Add edge case handling fields to Product2
ALTER TABLE Product2 ADD COLUMN Is_Default__c BOOLEAN DEFAULT false;
ALTER TABLE Product2 ADD COLUMN Display_Order__c NUMBER(18,0);
ALTER TABLE Product2 ADD COLUMN Auto_Add__c BOOLEAN DEFAULT false;

-- Mark existing activation fees as default
UPDATE Product2
SET Is_Default__c = true, Auto_Add__c = true
WHERE Item_Class__c = 'Activation'
AND StockKeepingUnit IN ('SIM-ACTIVATION-FEE', 'VPN-ACTIVATION-FEE');

Phase 3: 🔄 Frontend Updates (Next)

  • Update SIM configure page to use new endpoints
  • Update VPN page to load activation fees
  • Update Internet page to use installation/addon endpoints
  • Test with both old and new SKU formats

Phase 4: 🔄 Cleanup (Final)

  • Remove legacy individual SKU field support
  • Remove order-type-specific validation
  • Clean up deprecated frontend code

Benefits Achieved

1. Eliminated Guessing Logic

  • No more hint-based product resolution
  • Explicit SKU arrays from frontend
  • Clear validation and error messages

2. Fixed Missing Activation Fees

  • SIM orders were missing activation fees
  • All order types now include required fees
  • Configurable via Salesforce Product2 fields

3. Improved Maintainability

  • Complex order-type-specific logic
  • Generic SKU processing
  • Easy to add new product types

4. Enhanced Flexibility

  • Hard-coded product relationships
  • Configurable product dependencies
  • Regional and conditional products

5. Better Error Handling

  • Cryptic "product not found" errors
  • Specific SKU validation messages
  • Business rule validation

This architecture provides complete SKU control, predictable behavior, and easy debugging while maintaining backward compatibility during the migration period.