ユニーク商品CSV インポート

概要

ユニーク商品CSVインポート機能は、ユニークな識別コードを含む商品データのCSVファイルをアップロードし、バッチ処理と追跡を可能にします。このシステムは、CSVデータから単一の一時ウィッシュリストを作成し、複数のECプラットフォーム(Amazon、楽天)からの商品インポートをサポートしながら、高度な分析と追跡機能のためのユニーク商品グループ化を維持します。

ユニーク商品インポートシステムの主要特徴:

  • 単一ウィッシュリスト作成: 最初の行に基づいてCSVファイルごとに1つの一時ウィッシュリストを作成
  • 包括的なバリデーションを含む一括CSVインポート
  • ユニークコードベースの商品追跡とグループ化
  • マルチプラットフォーム対応(Amazon ASIN、楽天ID、JANコード)
  • 重複検出とエラーハンドリング
  • サマリーユニーク商品作成による一時ウィッシュリスト統合
  • 監査とデバッグのためのインポート履歴とエラー追跡

注意: この機能は、ユニーク追跡コードを持つ商品を一時ウィッシュリストにインポートします。標準的な一時ウィッシュリストCSVインポートについては、CSV インポート/エクスポートを参照してください。

最新機能

強化されたユニーク商品追跡 (2025-07-07)

  • サマリーユニーク商品: ユニークコード追跡のためのtemp_summary_unique_productsテーブルを追加
  • 関係マッピング: temp_summary_unique_product_idによる商品とユニークコードのリンク
  • バッチ処理: ユニークコードグループ化による大規模データセットの効率的な処理
  • エラー管理: 詳細なバリデーションメッセージによる包括的なエラー追跡

アクティビティ図

---
config:
  theme: base
  layout: dagre
  flowchart:
    curve: linear
    htmlLabels: true
  themeVariables:
    edgeLabelBackground: "transparent"
---
flowchart TB
    %% Main components
    UserRequest[ユーザーCSVアップロード]
    CSVFile[CSVファイル]
    TempDatabase[(一時データベース)]
    
    subgraph Controllers["コントローラー"]
        UniqueProductController[UniqueProductWishlistController]
    end
    
    subgraph Services["サービス"]
        UniqueProductImportService(UniqueProductImportService)
        TempSummaryService(TempSummaryUniqueProductService)
    end
    
    subgraph Models["モデル"]
        TempWishlist[[TempWishlistToGroup]]
        TempWishlistProduct[[TempWishlistProduct]]
        TempSummaryUniqueProduct[[TempSummaryUniqueProduct]]
        ImportHistory[[ImportHistory]]
        ImportError[[ImportError]]
    end
    
    subgraph Middleware["ミドルウェア"]
        AuthMiddleware{AuthMiddleware}
        GroupMiddleware{GroupMiddleware}
    end
    
    UserRequest --- Step1[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>1</span>
            <p style='margin-top: 8px'>認証とグループ検証</p>
        </div>
    ]
    Step1 --> AuthMiddleware
    AuthMiddleware --> GroupMiddleware

    UniqueProductController --- Step2[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>2</span>
            <p style='margin-top: 8px'>ファイルアップロードと検証</p>
        </div>
    ]
    Step2 --> CSVFile

    UniqueProductImportService --- Step3[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3</span>
            <p style='margin-top: 8px'>CSV処理とデータ検証</p>
        </div>
    ]
    Step3 --> CSVFile

    UniqueProductImportService --- Step4[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>4</span>
            <p style='margin-top: 8px'>単一ウィッシュリスト作成とユニークコード処理</p>
        </div>
    ]
    Step4 --> TempSummaryService

    TempSummaryService --- Step5[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #cc66cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>5</span>
            <p style='margin-top: 8px'>データベース保存</p>
        </div>
    ]
    Step5 --> TempDatabase

    %% Service to Model relationships
    UniqueProductImportService -.-> TempWishlist
    UniqueProductImportService -.-> TempWishlistProduct
    UniqueProductImportService -.-> ImportHistory
    UniqueProductImportService -.-> ImportError
    TempSummaryService -.-> TempSummaryUniqueProduct
    
    %% Model to Database relationships
    TempWishlist -.-> TempDatabase
    TempWishlistProduct -.-> TempDatabase
    TempSummaryUniqueProduct -.-> TempDatabase
    ImportHistory -.-> TempDatabase
    ImportError -.-> TempDatabase
    
    %% Styling
    style TempDatabase fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
    style CSVFile fill:#fcd9d9,stroke:#cc3333,stroke-width:2px
    style Controllers fill:#e6f3ff
    style Services fill:#f0f8e6
    style Models fill:#fff0f5
    style Middleware fill:#f5f0ff
    style Step1 fill:transparent,stroke:transparent,stroke-width:1px
    style Step2 fill:transparent,stroke:transparent,stroke-width:1px
    style Step3 fill:transparent,stroke:transparent,stroke-width:1px
    style Step4 fill:transparent,stroke:transparent,stroke-width:1px
    style Step5 fill:transparent,stroke:transparent,stroke-width:1px

APIエンドポイント

1. ユニーク商品CSVインポート

API: ユニーク商品CSV インポート

  • エンドポイント: POST /api/v1/general/unique-product-upload/import
  • 目的: ユニーク商品CSVファイルのアップロードと処理
  • リクエスト: multipart/form-datacsv_file フィールド
  • レスポンス: 成功/エラー詳細を含むインポート概要
  • 認証: 必須(ユーザー認証 + グループアクセス)

2. インポート履歴リスト

API: インポート履歴リスト取得

  • エンドポイント: GET /api/v1/general/temp-wishlist-to-group/import-history/list
  • 目的: インポート履歴のページ分割リスト取得(ユニーク商品用にtype=2でフィルタ)
  • パラメータ: per_page, page, type (ImportHistoryType::UniqueProduct = 2)
  • レスポンス: ページ分割されたインポート履歴レコード
  • 認証: 必須

3. インポート履歴詳細

API: インポート履歴詳細取得

  • エンドポイント: GET /api/v1/general/temp-wishlist-to-group/import-history/{id}
  • 目的: 特定のインポート履歴詳細の取得
  • レスポンス: メタデータを含む詳細なインポート履歴レコード
  • 認証: 必須

4. エラーCSVダウンロード

API: エラーCSVダウンロード

  • エンドポイント: GET /api/v1/general/temp-wishlist-to-group/import-history/{id}/download-errors
  • 目的: 特定の履歴のインポートエラーを含むCSVファイルのダウンロード
  • レスポンス: エラー詳細を含むCSVファイル
  • 認証: 必須

5. インポートエラーリスト

API: インポートエラーリスト取得

  • エンドポイント: GET /api/v1/general/temp-wishlist-to-group/import-history/{id}/import-error/list
  • 目的: 特定の履歴のインポートエラーのページ分割リスト取得
  • パラメータ: per_page, page
  • レスポンス: ページ分割されたインポートエラーレコード
  • 認証: 必須

注意: インポート履歴とエラー管理APIは標準の一時ウィッシュリストインポートと共有され、ImportHistoryType列挙型(1=標準、2=ユニーク商品)で区別されます。

データベーススキーマ

データベース関連テーブルとフィールド

データベース: gb_console

erDiagram
    temp_wishlist_to_groups {
        bigint id PK
        bigint user_id "一時ウィッシュリストを作成したユーザー"
        bigint group_id "アクセス制御のためのグループ所有権"
        string name "CSVヘッダーからの一時ウィッシュリスト名"
        string slug "自動生成されたユニーク識別子"
    }
    
    temp_summary_unique_products {
        bigint id PK
        bigint temp_wishlist_to_group_id FK "temp_wishlist_to_groupsへの参照"
        string code "商品グループ化のためのユニーク識別子コード"
    }
    
    temp_wishlist_products {
        bigint id PK
        bigint temp_wishlist_to_group_id FK "temp_wishlist_to_groupsへの参照"
        bigint temp_summary_unique_product_id FK "temp_summary_unique_productsへの参照"
        string input "商品識別子(ASIN、楽天ID、またはJAN)"
        string input_type "タイプ: 'asin', 'rakuten_id', 'jan'"
        string product_url "自動生成された商品URL"
        bigint mall_id "モール識別子(AmazonまたはRakuten)"
        string pair_id "CSVからの行識別子(row_1, row_2など)"
        string unique_code "グループ化のためのCSVからのユニークコード"
    }
    
    import_histories {
        bigint id PK
        bigint user_id "インポートを実行したユーザー"
        bigint group_id "インポートのグループコンテキスト"
        string file_name "元のCSVファイル名"
        integer type "1=標準、2=ユニーク商品(ImportHistoryType列挙型)"
        integer status "インポートステータス: 成功、失敗、部分"
    }
    
    import_errors {
        bigint id PK
        bigint import_history_id FK "import_historiesへの参照"
        integer error_line "エラーが発生したCSV行番号"
        string header "エラーの原因となったフィールドヘッダー"
        string value "エラーの原因となったフィールド値"
        text error_messages "エラーメッセージのJSON配列"
    }

    temp_wishlist_to_groups ||--o{ temp_summary_unique_products : has
    temp_summary_unique_products ||--o{ temp_wishlist_products : has
    temp_wishlist_to_groups ||--o{ temp_wishlist_products : has
    import_histories ||--o{ import_errors : has

CSV形式仕様

必須ヘッダー

CSVファイルには、以下のヘッダーを正確な順序で含める必要があります:

ヘッダー(翻訳キー) 日本語ヘッダー 説明 バリデーション
データセット名 (general.csv_import.headers.temp_wishlist_name) データセット名 一時ウィッシュリストの名前 "スマートフォン分析" 必須、最大50文字、絵文字なし
楽天ID (general.csv_import.headers.rakuten_id) 楽天ID 楽天商品識別子 "abc123def456" オプション、楽天ID形式
JANコード (general.csv_import.headers.jan) JANコード JAN(日本商品番号) "4901234567890" オプション、JAN形式
ASIN (general.csv_import.headers.asin) ASIN Amazon標準識別番号 "B08N5WRWNW" オプション、Amazon ASIN形式
独自ID (general.csv_import.headers.unique_id) 独自ID 商品グループ化のためのユニーク識別子 "GROUP_001" 必須、文字列形式

サンプルCSV形式

データセット名,独自ID,楽天ID,JANコード,ASIN
テストウィッシュリスト1,PROD001,netbaby:404201,4901234567890,
,PROD002,biccamera:4961310162719,4901234567892,B08N5WRWNX
,PROD003,,,B08N5WRWNY

バリデーションルール

ファイルレベルバリデーション

  • ファイルタイプ: .csv 形式である必要があります
  • ファイルサイズ: 最大ファイルサイズ制限(設定可能)
  • 文字エンコーディング: UTF-8エンコーディングサポート

行レベルバリデーション

  • データセット名 (temp_wishlist_name): 最初の行のみ必須(単一ウィッシュリスト作成に使用)、最大50文字、絵文字文字なし
  • 商品ID: 行ごとに少なくとも1つの商品ID(楽天ID、JANコード、またはASIN)を提供する必要があります
  • 独自ID (unique_id): すべての行で必須、商品グループ化と追跡に使用
  • 重複検出: 同じ一時ウィッシュリスト内の同じ商品IDは重複としてフラグが付けられます

重要: 最初の行のみからのデータセット名が単一の一時ウィッシュリストの作成に使用されます。その後のすべての行は、この単一のウィッシュリストに追加される商品です。

ケース文書

ケース1: 成功したCSVインポート

API: ユニーク商品CSV インポート

説明

ユーザーがユニーク商品データを含む適切にフォーマットされたCSVファイルをアップロードし、システムがすべての行を正常に処理して一時ウィッシュリスト商品とサマリーユニーク商品を作成します。

シーケンス図

sequenceDiagram
    participant Client as クライアント
    participant Controller as UniqueProductWishlistController
    participant Service as UniqueProductImportService
    participant SummaryService as TempSummaryUniqueProductService
    participant TempDB as 一時データベース
    participant FileSystem as ファイルシステム
    
    Note over Client,FileSystem: POST /api/v1/general/unique-product-upload/import
    
    rect rgb(200, 255, 200)
    Note right of Client: ハッピーケース - CSVインポート
    
    Client->>Controller: POST /import (csv_fileを含むmultipart/form-data)
    
    rect rgb(200, 230, 255)
    Note right of Controller: ファイル処理
    Controller->>Service: handle(request)
    Service->>FileSystem: アップロードされたCSVファイルを読み取り
    FileSystem-->>Service: CSVデータ行
    Service->>Service: validateFirstRow(firstRow)
    end
    
    rect rgb(200, 255, 255)
    Note right of Service: データ処理と検証
    Service->>Service: インポート履歴レコードを作成
    
    loop 各CSV行に対して
        Service->>Service: validateCSVRowWithErrors(row, rowNumber)
        Service->>Service: 商品IDとユニークコードを抽出
        Service->>Service: 重複をチェック
    end
    end
    
    rect rgb(255, 230, 200)
    Note right of Service: データベース操作
    Service->>Service: transactionBegin()
    Service->>TempDB: temp_wishlist_to_groupsを作成または更新
    
    Service->>SummaryService: createSummaryRecordsFromCodes(tempWishlistId, uniqueCodes)
    SummaryService->>TempDB: temp_summary_unique_productsに挿入
    
    Service->>TempDB: 関係を持つtemp_wishlist_productsを一括挿入
    Service->>Service: transactionCommit()
    end
    
    Service-->>Controller: インポート概要を含む成功結果
    Controller-->>Client: 成功メッセージを含む200 OK
    end
    
    rect rgb(255, 200, 200)
    Note right of Client: エラーハンドリング
    
    alt バリデーションエラー
        rect rgb(255, 230, 230)
        Service->>TempDB: import_errorsに挿入
        Service-->>Controller: エラー詳細を含む部分成功
        Controller-->>Client: 警告を含む200 OK
        end
    else ファイル処理エラー
        rect rgb(255, 230, 230)
        Service-->>Controller: エラー結果
        Controller-->>Client: 400 Bad Request
        end
    else データベースエラー
        rect rgb(255, 230, 230)
        Service->>Service: transactionRollback()
        Service-->>Controller: エラー結果
        Controller-->>Client: 500 Internal Server Error
        end
    end
    end

ステップ

ステップ1: ファイルアップロードと初期検証

  • 説明: ユーザーがマルチパートフォームデータを介してCSVファイルをアップロード
  • リクエスト: POST /api/v1/general/unique-product-upload/import
  • 検証: ファイルタイプ(.csv)、ファイルサイズ制限、アクセス可能性
  • 認証: ユーザーは認証され、グループアクセスが必要

ステップ2: CSV構造検証

  • 説明: CSVヘッダーと最初の行データを検証
  • アクション: 必須ヘッダーの存在と最初の行の内容をチェック
  • 検証ルール:
    • データセット名: 必須、最大50文字、絵文字なし
    • ヘッダーは期待される日本語形式と正確に一致する必要があります
  • エラーハンドリング: 構造が無効な場合、検証エラーを返す

ステップ3: 行ごとのデータ処理

  • 説明: 包括的な検証を含む各CSV行の処理
  • アクション: 商品IDを抽出し、データ形式を検証し、重複をチェック
  • 処理ロジック:
    • 行ごとに少なくとも1つの商品ID(楽天ID、JANコード、ASIN)が必要
    • ユニークコードの抽出と検証
    • データセット内の重複検出
  • エラー追跡: 各問題のある行の詳細なエラーを記録

ステップ4: 単一一時ウィッシュリスト作成

  • 説明: CSV最初の行のみから1つの一時ウィッシュリストを作成
  • アクション: 最初の行のみからのデータセット名を使用して単一のtemp_wishlist_to_groupsレコードを作成
  • キーフィールド: user_id、group_id、名前(最初の行のみから)、自動生成されたslug
  • 動作: すべてのCSV行からのすべての商品がこの単一のウィッシュリストに追加される

ステップ5: サマリーユニーク商品作成

  • 説明: ユニークコードのサマリーレコードを作成
  • アクション: TempSummaryUniqueProductService::createSummaryRecordsFromCodes()を呼び出し
  • 処理: ユニークコードを抽出し、重複をフィルタし、一括挿入
  • 結果: リンクのためのtemp_summary_unique_productsレコードを作成

ステップ6: 商品データ保存

  • 説明: 単一のウィッシュリストとの関係を持つ個別の商品レコードを保存
  • アクション: 適切な関係を持つtemp_wishlist_productsを一括挿入
  • キー関係:
    • temp_wishlist_to_group_idを介して単一のtemp_wishlist_to_groupsにリンク
    • temp_summary_unique_product_idを介してtemp_summary_unique_productsにリンク
  • データマッピング: 商品IDを適切なinput_typeとmall_idに変換
  • 結果: すべてのCSV行からのすべての商品が1つの一時ウィッシュリストの下に保存される

ステップ7: インポート履歴とエラー記録

  • 説明: インポート操作の詳細とエラーがある場合はそれを記録
  • アクション: import_historyレコードを作成し、エラーがある場合はエラー詳細を挿入
  • インポート概要: 処理された総行数、成功したインポート、エラー数
  • エラー詳細: 行番号、フィールド名、特定のエラーメッセージ

エラーハンドリング

  • ログ: インポートエラーはアプリケーションログとimport_errorsテーブルに記録されます
  • エラー詳細:
ステータスコード エラーメッセージ 説明
400 "無効なファイル形式です。CSVファイルをアップロードしてください。" ファイルタイプ検証失敗
400 "CSVファイルが空か、必須ヘッダーが不足しています。" 構造検証失敗
422 "行X のバリデーションが失敗しました: field_name は必須です。" データ検証エラー
500 "インポート処理中にデータベースエラーが発生しました。" データベース操作失敗

ケース2: バリデーションエラーを含む部分成功

API: ユニーク商品CSV インポート

説明

CSVインポートが一部の行が正常に処理されながら他の行にバリデーションエラーが含まれている状態で完了します。システムは有効な行を処理しながら詳細なエラー情報を記録します。

キー動作

  • 部分処理: 有効な行が処理され保存されます
  • エラー記録: 無効な行が詳細なエラーメッセージでログされます
  • トランザクション安全性: 重要な失敗時のみデータベースロールバックが発生
  • ユーザーフィードバック: 成功対失敗行の明確な表示

重要な機能

1. ユニークコード追跡システムを持つ単一ウィッシュリスト

目的: ユニーク識別コードによる高度な分析と追跡により、ユニーク商品グループ化を持つ1つの一時ウィッシュリストを作成。

実装:

  • 単一ウィッシュリスト: 1つのCSVファイルが正確に1つの一時ウィッシュリストを作成(最初の行のデータセット名から)
  • CSV内の各商品行は、その単一ウィッシュリスト内でのグループ化のためのunique_idを含む必要があります
  • temp_summary_unique_productsテーブルは単一の一時ウィッシュリストのユニークコードを保存
  • temp_wishlist_productsはtemp_summary_unique_product_idを介してサマリーレコードにリンク
  • 単一ウィッシュリスト内の異なるプラットフォーム間での商品グループの分析と追跡をサポート

2. マルチプラットフォーム商品サポート

サポートされるプラットフォーム:

  • Amazon: ASIN形式検証とURL生成
  • 楽天: 適切なモール関連付けによる楽天ID形式ハンドリング
  • JANコード: 両プラットフォームの日本商品番号サポート

データマッピング:

$productIdMap = [
    '楽天ID' => [
        'input_type' => InputType::RakutenId->value, // 'rakuten_id'
        'mall_id' => $rakutenMall->id
    ],
    'JANコード' => [
        'input_type' => InputType::Jan->value, // 'jan'
        'mall_id' => $rakutenMall->id
    ],
    'ASIN' => [
        'input_type' => InputType::Asin->value, // 'asin'
        'mall_id' => $amazonMall->id
    ],
];

3. 包括的エラー管理

エラー追跡機能:

  • 特定フィールド識別による行レベルエラー記録
  • ユーザーフィードバックのための詳細エラーメッセージ
  • 監査証跡のためのインポート履歴保持
  • 詳細レポートによる部分成功ハンドリング

エラーカテゴリ:

  • バリデーションエラー: データ形式、必須フィールド、文字制限
  • 重複検出: 一時ウィッシュリスト内の同じ商品ID
  • ビジネスロジックエラー: 無効な商品ID、モール関連付け
  • システムエラー: データベース失敗、ファイル処理問題

4. 効率的なバッチ処理

パフォーマンス最適化:

  • 効率的なCSV読み取りのためのFastExcelライブラリ
  • 大規模データセットのバッチ挿入
  • データ一貫性のためのトランザクション管理
  • 大きなファイルのメモリ効率的な処理

処理フロー:

  1. ファイル全体をメモリに読み込むことなくCSVデータをストリーム
  2. バッチでデータを検証し収集
  3. 一括データベース操作を実行
  4. バッチクエリを使用して関係を効率的にリンク

追加注意事項

ファイル処理の考慮事項

  • メモリ管理: 大きなCSVファイルのストリーミングアプローチを使用
  • 文字エンコーディング: 国際文字のUTF-8エンコーディングサポート
  • ファイルクリーンアップ: 処理後に一時ファイルがクリーンアップされます
  • エラー回復: 不正なCSV構造の優雅なハンドリング

データ整合性機能

  • 一意制約: 一時ウィッシュリスト内の重複ユニークコードを防止
  • 外部キー関係: テーブル間の参照整合性を維持
  • トランザクション安全性: 重要な操作のための全か無かアプローチ
  • 監査証跡: エラー詳細を含む完全なインポート履歴

一時ウィッシュリストシステムとの統合

  • シームレス統合: 既存の一時ウィッシュリストインフラストラクチャと連携
  • 変換準備: データ構造は本番ウィッシュリストへの変換をサポート
  • グループ権限: ユーザーグループ権限とアクセス制御を尊重
  • クォータ管理: サブスクリプションとクォータシステムと統合

パフォーマンスとスケーラビリティ

  • バッチ操作: 大規模データセットの効率的なハンドリング
  • インデックス最適化: 高速ルックアップ操作のためのデータベースインデックス
  • メモリ効率: 大きなファイルを処理するためのストリーミング処理
  • エラー制限: メモリ問題を防ぐための合理的なエラー記録制限

CSVインポート仕様概要

⚠️ 重要な動作:

  • 1つのCSVファイル = 1つの一時ウィッシュリスト
  • 最初の行のみからのデータセット名がウィッシュリスト名を決定
  • すべての商品がすべてのCSV行からこの単一の一時ウィッシュリストにインポートされる
  • 複数のCSVインポートは複数の個別の一時ウィッシュリストを作成
  • ユニークコードは各個別の一時ウィッシュリストでの商品グループ化を追跡