Chuyển đến nội dung chính

レッスン 8: 製品カタログと SKU アーキテクチャ — バリアント管理と設計と製品のバインディング

POD の製品カタログ アーキテクチャ、SKU 管理戦略、基本製品 + デザイン = 販売可能な製品、バリエーション マトリックス (サイズ × カラー × デザイン)、在庫なしモデル、製品データ モデル、マルチチャネル製品同期。

🏗️ アーキテクチャ — レッスン 8 レッスン 8: 製品カタログと SKU アーキテクチャ — バリアント管理と設計 - 製品 バインディング

ファッション デザインとプリント オン デマンド システム アーキテクチャ — ドメイン分析から生産まで

パート 3: 製品と電子商取引プラットフォーム

xdev.asia

1. POD 製品データモデル

POD では、製品は在庫に存在せず (在庫レス)、注文があった場合にのみ生産されます。製品型番は、 ベース商品×デザイン=売れる商品。

Product Composition Model
┌────────────────────┐     ┌────────────────────┐
│   Base Product     │     │      Design        │
│ (from Supplier)    │     │  (from Designer)   │
│                    │     │                    │
│ - T-shirt          │     │ - Image file       │
│ - Hoodie           │  ×  │ - Print area       │
│ - Mug              │     │ - Color variants   │
│ - Phone case       │     │ - Placement config │
│                    │     │                    │
│ Variants:          │     │                    │
│ - Size (S,M,L,XL)  │     │                    │
│ - Color (20+)      │     │                    │
│ - Material         │     │                    │
└────────┬───────────┘     └────────┬───────────┘
         │                          │
         └──────────┬───────────────┘
                    ▼
         ┌────────────────────┐
         │  Sellable Product  │
         │  (Published SKU)   │
         │                    │
         │ SKU: TS-BLK-L-D42  │
         │ = T-shirt Black L  │
         │ + Design #42       │
         │                    │
         │ Variants: N × M    │
         │ (base × design)    │
         └────────────────────┘

2. ドメインデータモデル

// Base Product: Template sản phẩm từ supplier (chưa có design)
interface BaseProduct {
  id: string;
  supplierId: string;
  name: string;                          // "Unisex Jersey T-Shirt"
  category: ProductCategory;
  
  // Print specifications
  printAreas: PrintArea[];               // Front, Back, Sleeve, etc.
  printMethods: PrintMethod[];           // DTG, DTF, Sublimation
  
  // Variants matrix
  availableSizes: Size[];                // S, M, L, XL, 2XL
  availableColors: ProductColor[];       // 20+ colors
  
  // Supplier info
  baseCost: Money;                       // Cost per unit from supplier
  productionTime: Duration;             // 2-5 business days
  
  // Constraints
  maxPrintDPI: number;                   // 300
  minOrderQuantity: number;              // 1 (POD) or bulk
  weight: Weight;                        // For shipping calculation
  
  status: 'active' | 'discontinued' | 'out_of_stock';
}

interface PrintArea {
  id: string;
  name: string;                          // "Front", "Back", "Left Sleeve"
  position: AreaPosition;
  maxWidth: number;                      // inches
  maxHeight: number;
  supportedMethods: PrintMethod[];
}

// Design: Tác phẩm thiết kế của designer
interface Design {
  id: string;
  designerId: string;
  title: string;
  description: string;
  
  // File assets
  files: {
    printFile: string;                   // High-res file URL (300+ DPI)
    preview: string;                     // Web preview
    thumbnail: string;
  };
  
  // Design metadata
  dimensions: { width: number; height: number; dpi: number };
  colorProfile: 'srgb' | 'adobe_rgb' | 'cmyk';
  hasTransparency: boolean;
  colorCount: number;
  
  // Placement configs per product type
  placements: DesignPlacement[];
  
  // AI-generated metadata
  aiTags: string[];
  aiCategory: string;
  aiColorPalette: string[];
  
  status: 'draft' | 'review' | 'approved' | 'published' | 'rejected';
}

// Sellable Product: Base Product + Design = SKU
interface SellableProduct {
  id: string;
  baseProductId: string;
  designId: string;
  
  // Published info
  title: string;                         // "Mountain Sunset Tee"
  description: string;
  slug: string;                          // "mountain-sunset-tee"
  
  // Pricing
  price: Money;                          // Retail price
  compareAtPrice?: Money;                // Original price (for discount display)
  
  // Generated SKU variants
  variants: ProductVariant[];
  
  // Visual assets (auto-generated mockups)
  images: ProductImage[];
  
  // Sales channels
  channels: SalesChannel[];
  
  // SEO
  seoTitle: string;
  seoDescription: string;
  tags: string[];
  
  status: 'draft' | 'active' | 'archived';
  publishedAt?: Date;
}

3. SKU 生成戦略

// SKU Format: {ProductType}-{Color}-{Size}-{DesignID}
// Example: TS-BLK-L-D0042 = T-shirt, Black, Large, Design #42

interface SKUGenerator {
  generate(baseProduct: BaseProduct, design: Design): ProductVariant[];
}

function generateSKUVariants(
  baseProduct: BaseProduct,
  design: Design,
): ProductVariant[] {
  const variants: ProductVariant[] = [];
  const productCode = PRODUCT_CODES[baseProduct.category]; // 'TS', 'HD', 'MG'
  const designCode = `D${design.id.slice(-4).toUpperCase()}`;

  for (const color of baseProduct.availableColors) {
    // Check if design works on this color
    const compatibility = checkDesignColorCompatibility(design, color);
    if (!compatibility.compatible) continue;

    for (const size of baseProduct.availableSizes) {
      const sku = `${productCode}-${color.code}-${size.code}-${designCode}`;
      
      variants.push({
        id: generateVariantId(),
        sku,
        baseProductId: baseProduct.id,
        designId: design.id,
        color: color,
        size: size,
        
        // Pricing
        cost: calculateVariantCost(baseProduct, color, size),
        price: calculateRetailPrice(baseProduct, design, color, size),
        
        // No physical inventory — POD
        inventoryPolicy: 'continue_selling',   // Always available
        requiresShipping: true,
        
        // Weight for shipping
        weight: baseProduct.weight,
        
        // Auto-generated mockup for this specific variant
        mockupUrl: `/mockups/${sku}.webp`,
      });
    }
  }

  return variants;
}

// Variant matrix example for a single design on T-shirt:
// 6 sizes × 20 colors = 120 SKU variants per design
// 100 designs × 120 variants = 12,000 SKUs cho 1 product type
// Scale: 10 product types × 1,000 designs = 1.2M SKUs

4. バリアントマトリックスと在庫なしモデル

// POD Inventory: "Virtual" — không stock, chỉ track availability từ supplier
interface PODInventory {
  // Check if supplier can fulfill
  checkAvailability(variant: ProductVariant): Promise<AvailabilityResult>;
  
  // Sync supplier stock status
  syncSupplierStock(supplierId: string): Promise<void>;
  
  // Handle out-of-stock from supplier
  handleStockout(variantSku: string): Promise<void>;
}

interface AvailabilityResult {
  available: boolean;
  estimatedProductionTime: Duration;
  supplierStock: 'in_stock' | 'low_stock' | 'out_of_stock';
  
  // If primary supplier out of stock → fallback
  alternativeSuppliers: Array<{
    supplierId: string;
    cost: Money;
    productionTime: Duration;
  }>;
}

// Supplier catalog sync: Định kỳ sync danh sách base products từ suppliers
interface SupplierCatalogSync {
  syncInterval: Duration;               // Every 6 hours
  
  // API integration với các POD suppliers
  suppliers: Array<{
    id: string;
    name: string;                        // 'Printful', 'Printify', 'Gooten'
    apiType: 'rest' | 'graphql' | 'webhook';
    catalogEndpoint: string;
    
    // Product mapping (supplier product ID → our base product ID)
    productMapping: Map<string, string>;
  }>;
}
// Elasticsearch/Meilisearch product index
interface ProductSearchIndex {
  id: string;
  title: string;
  description: string;
  designerName: string;
  
  // Facets
  category: string;
  tags: string[];
  colors: string[];
  sizes: string[];
  priceRange: { min: number; max: number };
  
  // AI-generated fields
  aiTags: string[];
  style: string;               // 'minimalist', 'streetwear', 'vintage'
  mood: string[];               // 'fun', 'dark', 'colorful'
  
  // Ranking signals
  salesCount: number;
  viewCount: number;
  favoriteCount: number;
  averageRating: number;
  
  // Vector embedding for semantic search
  designEmbedding: number[];    // CLIP embedding of design image
  textEmbedding: number[];      // Text embedding of title + description
}

// Hybrid search: keyword + semantic
async function searchProducts(query: string, filters: SearchFilters): Promise<SearchResult> {
  const results = await searchEngine.search({
    q: query,
    
    // Keyword matching
    attributesToSearchOn: ['title', 'description', 'tags', 'aiTags'],
    
    // Semantic vector search (if enabled)
    vector: await embedText(query),
    
    // Filters
    filter: [
      filters.category && `category = "${filters.category}"`,
      filters.minPrice && `priceRange.min >= ${filters.minPrice}`,
      filters.maxPrice && `priceRange.max <= ${filters.maxPrice}`,
      filters.colors?.length && `colors IN [${filters.colors.map(c => `"${c}"`).join(',')}]`,
    ].filter(Boolean),
    
    // Ranking
    rankingRules: [
      'words',             // Keyword relevance
      'typo',
      'proximity',
      'attribute',
      'sort',
      'exactness',
      'salesCount:desc',   // Popular products first
    ],
    
    // Facets for filter UI
    facets: ['category', 'tags', 'colors', 'sizes', 'priceRange', 'style'],
    
    limit: 24,
    offset: filters.page * 24,
  });

  return results;
}

6. まとめ

コンセプトPOD アプローチ従来の電子商取引
製品づくり基本製品 × デザイン = SKU倉庫からの固定 SKU
在庫バーチャル(在庫レス)物理的な在庫数
SKU 数潜在的に数百万(組み合わせ)数百から数千
製品画像自動生成されたモックアップマニュアル撮影
価格設定基本コスト + バリアントごとのマージンSKUごとの固定価格
可用性いつでも利用可能 (サプライヤーが許可)在庫切れの可能性あり
検索AI タグ + セマンティック + キーワード手動による分類