一時ウィッシュリスト管理
説明
一時ウィッシュリスト管理システムは、複雑なネストデータ構造を持つ一時ウィッシュリストの包括的なCRUD操作を提供し、ユーザーが公式ウィッシュリストに変換する前に商品コレクション、カテゴリ、検索クエリ、AI生成ビューポイントを作成、整理、管理できるようにします。このシステムはサブスクリプションクォータに影響を与えることなく動作し、ユーザーが異なる商品組み合わせを実験し、グループ内で協力できるようにします。
主要機能には以下が含まれます:
- 複雑なネストデータ管理: 商品、カテゴリ、検索クエリ、ビューポイントを含むウィッシュリストの同時作成
- クォータフリー操作: サブスクリプションリソースを消費することなくウィッシュリストの作成と変更
- グループ協力: 所有権検証を伴うユーザーグループ内でのリアルタイム協力
- 高度な検証: 絵文字制限、入力タイプ列挙、モール互換性を含む包括的検証
- 自動スラッグ生成: 名前変更時の自動更新を伴うURL安全スラッグ生成
- 重複検出: 更新中のアイテムの重複のインテリジェントフィルタリング
- トランザクション安全性: データ整合性のためのデータベーストランザクションでラップされたすべての操作
- CSV統合: CSVインポート/エクスポート機能とのシームレス統合
- インポート履歴追跡: 詳細なエラー報告を伴うすべてのインポート操作の完全な監査証跡
アクティビティ図
---
config:
theme: base
layout: dagre
flowchart:
curve: linear
htmlLabels: true
themeVariables:
edgeLabelBackground: "transparent"
---
flowchart TD
Start([ユーザーがウィッシュリスト操作を開始])
Start --> Step1[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #4CAF50 !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 --> Step2[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #2196F3 !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 --> Decision{操作タイプ}
Decision -->|作成| Step3[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #FF9800 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3</span>
<p style='margin-top: 8px'>ネストデータで作成</p>
</div>
]
Decision -->|読み取り| Step4[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #9C27B0 !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>
]
Decision -->|更新| Step5[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #607D8B !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>
]
Decision -->|表示| Step6[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #795548 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6</span>
<p style='margin-top: 8px'>所有権チェックで表示</p>
</div>
]
Decision -->|インポート履歴| Step7[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #E91E63 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>7</span>
<p style='margin-top: 8px'>インポート操作管理</p>
</div>
]
Step3 --> End([操作完了])
Step4 --> End
Step5 --> End
Step6 --> End
Step7 --> End
%% Styling
style Start fill:#e8f5e8,stroke:#4caf50,stroke-width:2px
style End fill:#ffe8e8,stroke:#f44336,stroke-width:2px
style Decision fill:#fff3e0,stroke:#ff9800,stroke-width:2px
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
style Step6 fill:transparent,stroke:transparent,stroke-width:1px
style Step7 fill:transparent,stroke:transparent,stroke-width:1px
データベース関連テーブル・フィールド
データベース: gb_console
erDiagram
users ||--o{ temp_wishlist_to_groups : "作成"
groups ||--o{ temp_wishlist_to_groups : "所属"
temp_wishlist_to_groups ||--o{ temp_wishlist_products : "持つ"
temp_wishlist_to_groups ||--o{ temp_wishlist_categories : "持つ"
temp_wishlist_to_groups ||--o{ temp_wishlist_search_queries : "持つ"
temp_wishlist_to_groups ||--o{ temp_wl_cat_vps : "持つ"
users ||--o{ temp_wl_cat_vps : "作成"
groups ||--o{ temp_wl_cat_vps : "所属"
temp_wl_cat_vps ||--o{ temp_wl_cat_vp_details : "持つ"
temp_wl_cat_vp_details ||--o{ temp_wl_spec_vps : "持つ"
users ||--o{ import_histories : "作成"
import_histories ||--o{ import_errors : "持つ"
users {
bigint id PK
}
groups {
bigint id PK
}
temp_wishlist_to_groups {
bigint id PK
bigint user_id FK
bigint group_id FK
string name "ウィッシュリストの名前"
string slug "ウィッシュリストのスラッグ"
tinyint status "1: 一時保存, 2: CSVインポートドラフト"
}
temp_wishlist_products {
bigint id PK
bigint temp_wishlist_to_group_id FK
string input "商品の入力"
string input_type "入力のタイプ: jan, asin, rakuten_id"
string product_url "商品のURL"
bigint mall_id FK
string pair_id "商品ペアの一意識別子"
}
temp_wishlist_categories {
bigint id PK
bigint temp_wishlist_to_group_id FK
string category_id "モール内のカテゴリID"
bigint mall_id FK
string category_url "カテゴリのURL"
}
temp_wishlist_search_queries {
bigint id PK
bigint temp_wishlist_to_group_id FK
string keyword "検索キーワード"
bigint mall_id FK
}
temp_wl_cat_vps {
bigint id PK
bigint temp_wishlist_to_group_id FK "Nullable, ウィッシュリストへのリンク用"
bigint user_id FK
bigint group_id FK
string name "カテゴリビューポイント名(最大200文字)"
string slug "ビューポイントの一意スラッグ"
}
temp_wl_cat_vp_details {
bigint id PK
bigint temp_wl_cat_vp_id FK
text detail "AI生成カテゴリ詳細"
}
temp_wl_spec_vps {
bigint id PK
bigint temp_wl_cat_vp_detail_id FK
string name "特定ビューポイント名(最大100文字)"
text description "ビューポイントの詳細説明"
}
import_histories {
bigint id PK
string file_name "ファイル名"
bigint created_by FK "インポートを作成したユーザー"
string temp_wishlist_id "一時ウィッシュリストのID"
string temp_wishlist_name "一時ウィッシュリストの名前"
string error "エラーメッセージ"
tinyint status "0: 保留中, 1: 成功, 2: エラー"
}
import_errors {
bigint id PK
bigint import_history_id FK
string header "エラーのキー"
string value "エラーの値"
json error_messages "エラーメッセージ"
}
ケースドキュメント
ケース1: ネストデータを含む一時ウィッシュリスト作成
API: 一時ウィッシュリスト作成
シーケンス図
sequenceDiagram
participant Client
participant TempWishlistController
participant TempWishlistService
participant TempWishlistRepository
participant TempProductService
participant TempCategoryService
participant TempSearchQueryService
participant TempViewpointService
participant Database
rect rgb(255, 255, 200)
Note over Client,Database: 認証・グループ検証
Client->>TempWishlistController: POST /api/v1/temp-wishlist-to-group
TempWishlistController->>TempWishlistController: ユーザー認証チェック
TempWishlistController->>TempWishlistController: グループメンバーシップ検証 (isMemberOfGroup)
TempWishlistController->>TempWishlistController: 複雑なネストデータ構造検証
end
rect rgb(200, 230, 255)
Note over TempWishlistController,Database: 複雑な検証フェーズ
TempWishlistController->>TempWishlistController: ウィッシュリスト名検証(最大50文字、絵文字なし)
TempWishlistController->>TempWishlistController: 商品検証(入力、入力タイプ、モール互換性)
TempWishlistController->>TempWishlistController: カテゴリ検証(category_id、モール)
TempWishlistController->>TempWishlistController: 検索クエリ検証(キーワード、モール)
TempWishlistController->>TempWishlistController: ビューポイント検証(category_name、詳細、ビューポイント配列)
end
rect rgb(200, 255, 200)
Note over TempWishlistController,Database: ハッピーケース - トランザクション安全作成
TempWishlistController->>TempWishlistService: create(validated_data)
TempWishlistService->>Database: BEGIN TRANSACTION
TempWishlistService->>TempWishlistService: セッションからユーザーとグループを抽出
TempWishlistService->>TempWishlistRepository: メインウィッシュリストレコード作成
TempWishlistRepository->>Database: INSERT temp_wishlist_to_groups
Database-->>TempWishlistRepository: 自動生成スラッグで作成されたウィッシュリスト
alt 商品がある場合
TempWishlistService->>TempProductService: mapDataFromRequest(products, malls)
TempProductService->>TempWishlistService: マップされた商品データ
TempWishlistService->>TempWishlistService: appendTempWishlistToGroupId(products)
TempWishlistService->>Database: INSERT temp_wishlist_products (一括)
end
alt カテゴリがある場合
TempWishlistService->>TempCategoryService: mapDataFromRequest(categories, malls)
TempCategoryService->>TempWishlistService: マップされたカテゴリデータ
TempWishlistService->>TempWishlistService: appendTempWishlistToGroupId(categories)
TempWishlistService->>Database: INSERT temp_wishlist_categories (一括)
end
alt 検索クエリがある場合
TempWishlistService->>TempSearchQueryService: mapDataFromRequest(queries, malls)
TempSearchQueryService->>TempWishlistService: マップされたクエリデータ
TempWishlistService->>TempWishlistService: appendTempWishlistToGroupId(queries)
TempWishlistService->>Database: INSERT temp_wishlist_search_queries (一括)
end
alt ビューポイントがある場合
TempWishlistService->>TempViewpointService: linkAndUpdateViewpoints(viewpoints, wishlist_id)
TempViewpointService->>TempViewpointService: createOrUpdateTempWishlistCategoryViewpoint(user, category_name)
TempViewpointService->>Database: INSERT/UPDATE temp_wl_cat_vps
TempViewpointService->>TempViewpointService: createOrUpdateTempWishlistCategoryViewpointDetail(viewpoint, detail)
alt 特定ビューポイント配列がある場合
TempViewpointService->>TempViewpointService: ビューポイント配列処理(作成/更新ロジック)
TempViewpointService->>Database: INSERT/UPDATE temp_wl_spec_vps (一括操作)
end
TempViewpointService->>Database: UPDATE temp_wl_cat_vps SET temp_wishlist_to_group_id
end
TempWishlistService->>Database: COMMIT TRANSACTION
TempWishlistService->>TempWishlistRepository: refresh() - 関係を含む再読み込み
TempWishlistService-->>TempWishlistController: 完全なウィッシュリストオブジェクト
TempWishlistController-->>Client: 201 Created with TempWishlistToGroupResource
end
rect rgb(255, 200, 200)
Note over Client,Database: ロールバック付きエラーハンドリング
alt 検証エラー
TempWishlistController-->>Client: 422 Validation Error (詳細フィールドエラー)
else グループアクセス拒否
TempWishlistController-->>Client: 403 Forbidden
else トランザクションエラー
TempWishlistService->>Database: ROLLBACK TRANSACTION
TempWishlistService-->>TempWishlistController: 作成失敗
TempWishlistController-->>Client: 400 Bad Request
end
end
ステップ
ステップ1: 認証・グループ認可
- 説明:
isMemberOfGroup()メソッドを使用してユーザー認証とグループメンバーシップを検証 - 検証: ユーザーセッション、グループアクセス権限、グループメンバー関係
- セキュリティ: ユーザーがグループに属し、ウィッシュリスト作成権限を持つことを確認
ステップ2: 複雑なネストデータ検証
- 説明: 包括的なルールですべてのネストデータ構造を検証
- ルール:
- 名前: 最大50文字、絵文字なし(WithoutEmojiRule)
- 商品: 入力(最大255文字)、入力タイプ(enum: jan/asin/rakuten_id)、モール互換性
- カテゴリ: category_id(最大255文字、絵文字なし)、モール(enum: amazon/rakuten)
- 検索クエリ: キーワード(最大255文字、絵文字なし)、モール(enum)
- ビューポイント: category_name(最大200文字)、category_detail(最大1000文字)、ビューポイント配列
- サニタイゼーション: 入力データをクリーンアップし、データベース挿入用に準備
ステップ3: ネストデータを含むトランザクション安全作成
- 説明: 単一トランザクションでウィッシュリストとすべての関連データを作成
- プロセス:
- データベーストランザクション開始
- 自動生成スラッグでメインウィッシュリストレコード作成
- モールマッピングとpair_id生成で商品を一括挿入
- モール検証でカテゴリを一括挿入
- キーワード処理で検索クエリを一括挿入
- 複雑なビューポイント作成(3層階層):
- 層1: ユーザー/グループコンテキストで
temp_wl_cat_vpsにカテゴリビューポイント作成/更新 - 層2: リッチ説明で
temp_wl_cat_vp_detailsにカテゴリ詳細作成/更新 - 層3: 特定ビューポイント配列処理:
- 既存ビューポイントが空の場合:
temp_wl_spec_vpsに新しいビューポイントを一括挿入 - 既存ビューポイントがある場合: パフォーマンスのためIDベースマッピングを使用したスマート更新
- 既存ビューポイントが空の場合:
- リンク: 関連付けのため
temp_wishlist_to_group_idでカテゴリビューポイント更新
- 層1: ユーザー/グループコンテキストで
- トランザクションコミットまたはエラー時ロールバック
- レスポンス: すべてのネスト関係が読み込まれた完全なウィッシュリストを返却
エラーハンドリング
| ステータスコード | エラーメッセージ | 説明 |
|---|---|---|
| 422 | 検証エラー | 無効な入力データ、絵文字検証、enum違反、長さ制約 |
| 403 | "アクセス拒否" | ユーザーがどのグループのメンバーでもない、または権限不足 |
| 400 | "作成失敗" | データベーストランザクションエラー、サービス層失敗 |
ケース2: ページネーション付き一時ウィッシュリスト取得
API: 一時ウィッシュリスト取得
シーケンス図
sequenceDiagram
participant Client
participant TempWishlistController
participant TempWishlistRepository
participant Database
rect rgb(255, 255, 200)
Note over Client,Database: 認証・クエリパラメータ
Client->>TempWishlistController: GET /api/v1/temp-wishlist-to-group?page=1&per_page=10
TempWishlistController->>TempWishlistController: ユーザー認証チェック
TempWishlistController->>TempWishlistController: ページネーションパラメータ解析(page、per_page)
end
rect rgb(200, 255, 200)
Note over TempWishlistController,Database: ハッピーケース - サーバーサイドページネーション
TempWishlistController->>TempWishlistRepository: serverPaginationFilteringFor(request->all())
TempWishlistRepository->>Database: ユーザー/グループフィルター、ページネーション、順序付きSELECT
Database-->>TempWishlistRepository: メタデータ付きページネーションウィッシュリストレコード
TempWishlistRepository-->>TempWishlistController: ウィッシュリスト付きLengthAwarePaginator
TempWishlistController->>TempWishlistController: TempWishlistToGroupResource::collectionに変換
TempWishlistController-->>Client: ページネーションコレクション + meta + links付き200 OK
end
rect rgb(255, 200, 200)
Note over Client,Database: エラーハンドリング
alt アクセスなし
TempWishlistController-->>Client: 403 Forbidden
else データベースエラー
Database-->>TempWishlistRepository: クエリエラー
TempWishlistRepository-->>TempWishlistController: 例外
TempWishlistController-->>Client: 400 Bad Request
end
end
ステップ
ステップ1: 認証・パラメータ処理
- 説明: ユーザー認証を検証し、クエリパラメータを処理
- パラメータ:
page(整数)、per_page(整数)、追加フィルタリングオプション - 認可: ウィッシュリストアクセスのユーザー権限チェック
ステップ2: フィルタリング付きサーバーサイドページネーション
- 説明: ページネーションとフィルタリングで最適化されたデータベースクエリを実行
- 機能:
- ユーザー固有フィルタリング(ユーザーのウィッシュリストのみ)
- グループベースフィルタリング(グループメンバーシップ)
- ステータスフィルタリング(TemporarySave、CsvImport)
- 作成日順序付け(最新順)
- レスポンス: メタデータ付きページネーションコレクション(current_page、total、per_pageなど)
ステップ3: リソース変換
- 説明: データベースモデルをAPIリソースに変換
- 含む: 基本ウィッシュリスト情報、ステータス名、ユーザー/グループ関係(読み込み時)
- レスポンス: データ、メタ、ページネーションリンクを含む構造化JSON
ケース3: 特定の一時ウィッシュリスト表示
API: 一時ウィッシュリスト表示
シーケンス図
sequenceDiagram
participant Client
participant TempWishlistController
participant TempWishlistRepository
participant Database
rect rgb(255, 255, 200)
Note over Client,Database: 認証・所有権検証
Client->>TempWishlistController: GET /api/v1/temp-wishlist-to-group/{slug}
TempWishlistController->>TempWishlistController: ユーザー認証チェック
TempWishlistController->>TempWishlistRepository: スラッグで検索(ルートモデルバインディング)
TempWishlistRepository->>Database: スラッグでウィッシュリストSELECT
Database-->>TempWishlistRepository: ウィッシュリストレコードまたは404
TempWishlistController->>TempWishlistController: 所有権検証(user_id === logged_in_user.id)
end
rect rgb(200, 255, 200)
Note over TempWishlistController,Database: ハッピーケース - ウィッシュリスト詳細返却
TempWishlistController->>TempWishlistController: 所有権検証済み
TempWishlistController->>TempWishlistController: TempWishlistToGroupResourceに変換
TempWishlistController-->>Client: 詳細ウィッシュリストデータ付き200 OK
end
rect rgb(255, 200, 200)
Note over Client,Database: エラーハンドリング
alt ウィッシュリストが見つからない
TempWishlistRepository-->>TempWishlistController: ルートモデルバインディングから404
TempWishlistController-->>Client: 404 Not Found
else アクセス拒否(間違った所有者)
TempWishlistController->>TempWishlistController: user_id !== logged_in_user.id
TempWishlistController-->>Client: 404 Not Found(セキュリティ: 存在を明かさない)
else データベースエラー
Database-->>TempWishlistRepository: クエリエラー
TempWishlistRepository-->>TempWishlistController: 例外
TempWishlistController-->>Client: 400 Bad Request
end
end
ステップ
ステップ1: ルートモデルバインディング・所有権検証
- 説明: Laravelが自動的にスラッグでウィッシュリストを検索し、ユーザー所有権を検証
- セキュリティ: ウィッシュリスト作成者のみが詳細を表示可能(user_idチェック)
- プライバシー: 未認可ユーザーにウィッシュリストの存在を明かさないため403の代わりに404を返却
ステップ2: リソース変換
- 説明: 関係を含むモデルをAPIリソースに変換
- 含む: すべてのウィッシュリスト詳細、ステータス情報、読み込み時のユーザー/グループデータ
- レスポンス: フォーマットされた日付とステータス名を含む完全なウィッシュリストオブジェクト
ケース4: 重複検出付き一時ウィッシュリスト更新
API: 一時ウィッシュリスト更新
シーケンス図
sequenceDiagram
participant Client
participant TempWishlistController
participant TempWishlistService
participant TempWishlistRepository
participant TempProductService
participant TempCategoryService
participant TempSearchQueryService
participant TempViewpointService
participant Database
rect rgb(255, 255, 200)
Note over Client,Database: 認証・所有権検証
Client->>TempWishlistController: PUT /api/v1/temp-wishlist-to-group/{id}
TempWishlistController->>TempWishlistController: ユーザー認証チェック
TempWishlistController->>TempWishlistRepository: IDで検索(ルートモデルバインディング)
TempWishlistController->>TempWishlistController: 所有権検証(user_idチェック)
TempWishlistController->>TempWishlistController: 更新データ検証(作成と同じルール)
end
rect rgb(200, 230, 255)
Note over TempWishlistController,Database: 重複検出付き複雑更新
TempWishlistController->>TempWishlistService: update(wishlist, validated_data)
TempWishlistService->>Database: BEGIN TRANSACTION
TempWishlistService->>TempWishlistService: カウント追跡初期化(新規/重複)
TempWishlistService->>TempWishlistRepository: メインウィッシュリストレコード更新
TempWishlistService->>TempWishlistRepository: 既存関係読み込み(商品、カテゴリ、クエリ)
alt 新しい商品がある場合
TempWishlistService->>TempProductService: mapDataFromRequest(products, malls)
TempProductService->>TempWishlistService: マップされた商品データ
TempWishlistService->>TempProductService: filterNewItems(mapped, existing)
TempWishlistService->>TempWishlistService: {items: new_items, stats: {new: X, duplicate: Y}}
TempWishlistService->>TempWishlistService: appendTempWishlistToGroupId(new_items)
TempWishlistService->>Database: 新しい商品のみINSERT(一括)
end
alt 新しいカテゴリがある場合
TempWishlistService->>TempCategoryService: mapDataFromRequest + filterNewItems
TempWishlistService->>Database: 新しいカテゴリのみINSERT(一括)
end
alt 新しい検索クエリがある場合
TempWishlistService->>TempSearchQueryService: mapDataFromRequest + filterNewItems
TempWishlistService->>Database: 新しい検索クエリのみINSERT(一括)
end
alt ビューポイントがある場合
TempWishlistService->>TempViewpointService: linkAndUpdateViewpoints(viewpoints, wishlist_id)
TempViewpointService->>TempViewpointService: createOrUpdateTempWishlistCategoryViewpoint(user, category_name)
TempViewpointService->>Database: INSERT/UPDATE temp_wl_cat_vps
TempViewpointService->>TempViewpointService: createOrUpdateTempWishlistCategoryViewpointDetail(viewpoint, detail)
alt 特定ビューポイント配列がある場合
TempViewpointService->>TempViewpointService: ビューポイント配列処理(作成/更新ロジック)
TempViewpointService->>Database: INSERT/UPDATE temp_wl_spec_vps (一括操作)
end
TempViewpointService->>Database: UPDATE temp_wl_cat_vps SET temp_wishlist_to_group_id
end
TempWishlistService->>Database: COMMIT TRANSACTION
TempWishlistService-->>TempWishlistController: {temp_wishlist: updated_object, counts: statistics}
end
rect rgb(200, 255, 200)
Note over TempWishlistController,Database: ハッピーケース - 更新データ返却
TempWishlistController->>TempWishlistController: TempWishlistToGroupResourceに変換
TempWishlistController-->>Client: 更新されたウィッシュリスト + 統計付き200 OK
end
rect rgb(255, 200, 200)
Note over Client,Database: エラーハンドリング
alt ウィッシュリストが見つからない
TempWishlistRepository-->>TempWishlistController: null
TempWishlistController-->>Client: 404 Not Found
else アクセス拒否
TempWishlistController-->>Client: 404 Not Found(セキュリティ)
else 検証エラー
TempWishlistController-->>Client: 422 Validation Error
else トランザクションエラー
TempWishlistService->>Database: ROLLBACK TRANSACTION
TempWishlistService-->>TempWishlistController: 更新失敗
TempWishlistController-->>Client: 400 Bad Request
end
end
ステップ
ステップ1: 所有権検証・データ検証
- 説明: ユーザーがウィッシュリストを所有していることを検証し、すべての更新データを検証
ステップ2: インテリジェント重複検出
- 説明: 重複アイテムを検出・フィルタリングする高度なロジック
- プロセス:
- 既存関係を読み込み(商品、カテゴリ、検索クエリ)
- モール互換性チェックで新しいデータをマップ
- サービス固有ロジックを使用して重複をフィルタリング
- 統計を追跡(新規 vs 重複)
- データベース制約を避けるため新しいアイテムのみ挿入
- 効率性: パフォーマンスのための一括操作、最小限のデータベースクエリ
ステップ3: 統計付きトランザクション安全更新
- 説明: すべてのデータをアトミックに更新し、詳細な統計を返却
- レスポンス: 更新されたウィッシュリストオブジェクト + 新規/重複アイテムのカウント
- ロールバック: データ整合性を維持するためエラー時の自動ロールバック
ケース5: インポート履歴管理
API: インポート履歴取得
シーケンス図
sequenceDiagram
participant Client
participant TempWishlistController
participant ImportHistoryRepository
participant Database
rect rgb(255, 255, 200)
Note over Client,Database: 認証・クエリ処理
Client->>TempWishlistController: GET /api/v1/temp-wishlist-to-group/import-history/list
TempWishlistController->>TempWishlistController: ユーザー認証チェック
TempWishlistController->>TempWishlistController: ページネーションとフィルターパラメータ解析
end
rect rgb(200, 255, 200)
Note over TempWishlistController,Database: ハッピーケース - インポート履歴取得
TempWishlistController->>ImportHistoryRepository: serverPaginationFilteringFor(request->all())
ImportHistoryRepository->>Database: SELECT import_histories WHERE created_by = user_id
Database-->>ImportHistoryRepository: ページネーションインポート履歴レコード
ImportHistoryRepository-->>TempWishlistController: 履歴付きLengthAwarePaginator
TempWishlistController->>TempWishlistController: ImportHistoryResource::collectionに変換
TempWishlistController-->>Client: ページネーションインポート履歴付き200 OK
end
rect rgb(255, 200, 200)
Note over Client,Database: エラーハンドリング
alt データベースエラー
Database-->>ImportHistoryRepository: クエリエラー
ImportHistoryRepository-->>TempWishlistController: 例外
TempWishlistController-->>Client: 400 Bad Request
end
end
ケース6: 特定インポート履歴検索
API: インポート履歴検索
シーケンス図
sequenceDiagram
participant Client
participant TempWishlistController
participant ImportHistoryRepository
participant Database
rect rgb(255, 255, 200)
Note over Client,Database: 認証・履歴検索
Client->>TempWishlistController: GET /api/v1/temp-wishlist-to-group/import-history/{id}
TempWishlistController->>TempWishlistController: ユーザー認証チェック
TempWishlistController->>ImportHistoryRepository: findByIdAndErrorStatus(historyId)
ImportHistoryRepository->>Database: SELECT import_histories WHERE id = ? AND status = ERROR
Database-->>ImportHistoryRepository: インポート履歴レコードまたはnull
end
rect rgb(200, 255, 200)
Note over TempWishlistController,Database: ハッピーケース - 履歴詳細返却
ImportHistoryRepository-->>TempWishlistController: エラー詳細付きインポート履歴
TempWishlistController->>TempWishlistController: ImportHistoryResourceに変換
TempWishlistController-->>Client: 詳細インポート履歴付き200 OK
end
rect rgb(255, 200, 200)
Note over Client,Database: エラーハンドリング
alt 履歴が見つからない
ImportHistoryRepository-->>TempWishlistController: null
TempWishlistController-->>Client: 404 Not Found
else データベースエラー
Database-->>ImportHistoryRepository: クエリエラー
ImportHistoryRepository-->>TempWishlistController: 例外
TempWishlistController-->>Client: 400 Bad Request
end
end
ケース7: インポートエラー取得
API: インポートエラー取得
シーケンス図
sequenceDiagram
participant Client
participant TempWishlistController
participant ImportErrorRepository
participant Database
rect rgb(255, 255, 200)
Note over Client,Database: 認証・エラー取得
Client->>TempWishlistController: GET /api/v1/temp-wishlist-to-group/import-history/{id}/import-error/list
TempWishlistController->>TempWishlistController: ユーザー認証チェック
TempWishlistController->>ImportErrorRepository: getAllByHistoryId(historyId)
ImportErrorRepository->>Database: SELECT import_errors WHERE import_history_id = ?
Database-->>ImportErrorRepository: インポートのすべてのエラーレコード
end
rect rgb(200, 255, 200)
Note over TempWishlistController,Database: ハッピーケース - エラー詳細返却
ImportErrorRepository-->>TempWishlistController: インポートエラーのコレクション
TempWishlistController->>TempWishlistController: ImportErrorResource::collectionに変換
TempWishlistController-->>Client: 詳細エラー情報付き200 OK
end
rect rgb(255, 200, 200)
Note over Client,Database: エラーハンドリング
alt データベースエラー
Database-->>ImportErrorRepository: クエリエラー
ImportErrorRepository-->>TempWishlistController: 例外
TempWishlistController-->>Client: 400 Bad Request
end
end
ビジネスロジック詳細
複雑なネストデータ構造
システムは単一リクエストで洗練されたネストデータ構造を処理します:
{
"name": "私の複雑なウィッシュリスト",
"wishlist_products": [
{
"input": "B08N5WRWNW",
"input_type": "asin",
"pair_id": "unique-pair-123"
}
],
"wishlist_categories": [
{
"category_id": "electronics-smartphones",
"mall": "amazon"
}
],
"wishlist_search_queries": [
{
"keyword": "iPhone 13 Pro",
"mall": "rakuten"
}
],
"wishlist_viewpoints": {
"category_name": "スマートフォン",
"category_detail": "高度な機能を持つハイエンドスマートフォン",
"viewpoints": [
{
"id": "existing-viewpoint-id",
"name": "パフォーマンス",
"description": "処理能力と速度に焦点"
}
]
}
}
高度な検証ルール
- WithoutEmojiRule: テキストフィールドで絵文字文字を防ぐカスタム検証ルール
- Enum検証:
InputType(jan、asin、rakuten_id)とMallSlug(amazon、rakuten)の厳密な検証 - 条件付き検証:
category_nameが提供された場合、category_detailが必須 - 配列検証: 個別ID要件を持つネスト配列の複雑な検証
- 長さ制約: 異なるフィールドタイプの特定文字制限
自動スラッグ生成
- オブザーバーパターン:
TempWishlistToGroupObserverが自動的にスラッグ生成を処理 - 作成:
generate_slug()ヘルパーを使用してモデル作成時にスラッグ生成 - 更新: 名前変更時にスラッグ再生成(ダーティチェック)
- フォーマット: URL安全識別子のための
twtg-{id}-{sanitized-name} - 一意性: スラッグフォーマットでのID包含により保証
インテリジェント重複検出
- サービスレベルロジック: 各サービス(Product、Category、SearchQuery)が
filterNewItems()を実装 - 比較ロジック: ビジネスルールに基づく洗練された比較(input+type、category_id+mall、keyword+mall)
- 統計追跡: 新規 vs 重複アイテムの詳細カウント
- パフォーマンス: データベース操作を最小化する効率的フィルタリング
トランザクション安全性
- データベーストランザクション: すべての作成/更新操作がトランザクションでラップ
- ロールバック戦略: データ整合性を維持するためエラー時の自動ロールバック
- ネスト操作: 複数テーブル挿入を含む複雑な操作をアトミックに処理
- エラー伝播: トランザクションクリーンアップを伴う適切な例外処理
ステータス管理
- TemporarySave (1): 手動作成と更新のデフォルトステータス
- CsvImport (2): CSVインポートウィッシュリストの特別ステータス
- ステータス名: enum
getName()メソッドによるローカライズされたステータス名 - 自動割り当て: 操作タイプに基づくシステム管理ステータス
インポート履歴統合
- 完全監査証跡: 詳細メタデータですべてのインポート操作を追跡
- エラー管理: 包括的エラー収集と報告
- ファイルメタデータ: 元のファイル名と処理詳細を保持
- ユーザー関連付け: 認証ユーザーにリンクされたインポート履歴
- ステータス追跡: リアルタイムステータス更新(保留中、成功、エラー)
セキュリティ機能
- グループメンバーシップ: すべての操作で
isMemberOfGroup()検証 - 所有権検証: アクセス制御のための厳密なユーザーIDチェック
- プライバシー保護: リソース存在を隠すため403の代わりに404レスポンス
- 入力サニタイゼーション: すべての入力の包括的検証とクリーニング
- トランザクション分離: 同時変更に対するデータベースレベル保護
統合ポイント
関連API
- CSVインポート/エクスポート: 一括データ操作とのシームレス統合
- 商品管理: 個別商品CRUD操作
- カテゴリ管理: カテゴリ固有操作とモール処理
- 検索クエリ管理: キーワード管理と検索操作
- AIビューポイント生成: インテリジェントコンテンツのためのOpenAI統合
GET /api/v1/temp-viewpoint/category- ユーザーによるカテゴリビューポイント取得GET /api/v1/temp-viewpoint/category/group- グループによるカテゴリビューポイント取得POST /api/v1/temp-viewpoint/category/generate- AIカテゴリ詳細生成POST /api/v1/temp-viewpoint/specific-viewpoint/generate- 特定ビューポイント生成
- 公式ウィッシュリスト変換: 本番ウィッシュリストへの移行
外部サービス
- グループ管理: ユーザーグループメンバーシップと権限の検証
- ユーザー認証: ユーザーセッションの検証とユーザーコンテキストの抽出
- モール設定: モール互換性とマッピングの検証
- スラッグ生成: 一意性を持つURL安全識別子生成
- データベース: トランザクションサポートを持つプライマリデータストレージ
データフロー
- 作成 → 入力: 単一操作ですべてのネストデータを含むウィッシュリスト作成
- 管理 → 強化: 重複検出でコンテンツ追加/更新
- 検証 → セキュリティ: 包括的検証と認可
- インポート → 統合: CSVインポートが完全監査証跡でウィッシュリスト作成
- 変換 → 本番: 公式ウィッシュリストシステムへのシームレス移行
複雑なビューポイント階層システム
システムはOpenAI統合を持つ洗練された3層ビューポイント階層を実装:
層1: カテゴリビューポイント(temp_wl_cat_vps)
- 目的: AI生成名を持つトップレベルカテゴリ定義
- スコープ: ユーザーとグループ固有、特定の一時ウィッシュリストにリンク可能
- 自動スラッグ:
TempWishlistCategoryViewpointObserverによる自動スラッグ生成 - リンク:
temp_wishlist_to_group_idで一時ウィッシュリストにリンク可能
層2: カテゴリ詳細(temp_wl_cat_vp_details)
- 目的: カテゴリのAI生成詳細説明
- OpenAI統合:
OpenAIService->generateCategoryDetail()で生成 - 関係: カテゴリビューポイントとの一対多(最新詳細を使用)
- コンテンツ: カテゴリコンテキストを説明するリッチテキスト説明
層3: 特定ビューポイント(temp_wl_spec_vps)
- 目的: 特定分析角度のための詳細なAI生成ビューポイント
- OpenAI統合:
OpenAIService->generateSpecificViewpoints()で生成 - 数量:
config('viewpoint.default_quantity')で設定可能 - 構造: 各ビューポイントの名前 + 詳細説明
ビューポイント管理ロジック
// 複雑なビューポイントデータ構造の例
{
"wishlist_viewpoints": {
"category_name": "スマートフォン",
"category_detail": "高度な機能を持つハイエンドスマートフォン",
"viewpoints": [
{
"id": "existing-viewpoint-id", // 更新用
"name": "パフォーマンス",
"description": "処理能力と速度に焦点"
},
{
"name": "カメラ品質",
"description": "写真撮影能力に重点"
}
]
}
}
TempViewpointService統合
linkAndUpdateViewpoints(): 作成/更新中にビューポイントを一時ウィッシュリストにリンク- スマート更新: 既存ビューポイントを検出し、変更されたデータのみ更新
- トランザクション安全性: すべてのビューポイント操作がデータベーストランザクションでラップ
- ユーザーアクションログ: 分析のためのAI生成使用量追跡
- クリーンアップロジック: 孤立したビューポイントデータの自動クリーンアップ
OpenAI統合ワークフロー
- カテゴリ詳細生成:
generateCategoryDetail()→ OpenAI API →temp_wl_cat_vp_detailsに保存 - 特定ビューポイント生成:
generateSpecificViewpoints()→ OpenAI API →temp_wl_spec_vpsに一括挿入 - エラーハンドリング: 包括的再試行メカニズムとエラーログ
- ユーザー追跡:
UserActionLogRepositoryですべてのAI操作をログ