コンテンツにスキップ

キャンペーン/価格ルール編集 UI の簡素化設計

項目 内容
ステータス ドラフト(合意待ち)
種別 追加合意・補足仕様(React Dashboard UX 改善)
対象画面 React Dashboard /commercial-rules/$id(キャンペーン詳細 / 価格ルール詳細)
関連 2026-03-dashboard-commercial-rule-price-flow.md / 2026-05-campaign-target-product-selection.md / キャンペーン-価格制御責務分離.md / 要件 §3.6.1(6 タイプ)
作成 2026-06-08

1. 背景・目的

/commercial-rules/$id のルール編集画面が「運用者が読み切れないほど複雑」という課題がある。本書は 何が複雑さの原因か を特定し、既存ルールエンジン・既存ルール・検品 fixture を壊さずに 認知負荷を下げる UI 改善方針を定義する。実装着手はこの設計合意後とする。

非目標: ルールエンジン(packages/domain/rulespackages/plugins/src/rule-engine/commercial)のデータモデル変更。本書はあくまで Dashboard の入力 UX 層 の改善に限定する。

2. 現状の構造

汎用ルールエンジンの内部構造(conditions ツリー + tiers[] + 6 種 action + ネストしたギフトグループ)を、フォームへ 1:1 でフラットに展開 している。

主要ファイル:

役割 ファイル
フォーム束ね packages/plugins/src/standard-extensions/admin-extensions/dashboard/campaigns/CampaignForm.tsx
基本情報 CampaignBasicSettingsSection.tsx
対象商品・よりどり CampaignTargetingSection.tsx
適用条件 CampaignConditionBuilderSection.tsx
ティア/アクション CampaignTierBuilderSection.tsx(約 1,200 行)
非対応警告 CampaignEditorNotice.tsx
state ⇔ JSON 変換・複雑度判定 campaign-form-mapper.ts

3. 問題点(診断)

3.1 「条件」を入力する場所が 3 つに分散

数量・金額の達成条件を入れる場所が 3 系統あり、運用者は使い分けを理解しないと設定できない。

  1. よりどり条件selection.totalQuantity / selectionGroups)— CampaignTargetingSection.tsx:92
  2. 適用条件matched-quantity / cart-quantity / matched-subtotal / cart-subtotal など)— CampaignConditionBuilderSection.tsx
  3. ティア発動条件(対象商品数量・カート数量・対象商品小計・カート小計の上下限 = 8 入力)— CampaignTierBuilderSection.tsx:908

「適用条件の対象商品数量」と「ティア発動条件の対象商品数量」が別物として両方存在し、これが最大の混乱源。

3.2 エンジン内部語の露出

運用者が知る必要のない実装概念がラベルに出ている。

  • セレクションID / グループID / アイテムID / ダミー商品番号
  • 「storefront 選択データと照合します」「保存時に conditions.targets へ自動反映します」
  • 「JSON 編集は使わず」(CampaignEditorNotice.tsx:18

3.3 すべてのルールに最大構成を見せている

単純な掛率・単価固定ルールでも、6 種アクション・ネストしたギフトグループ・8 入力のしきい値が常時展開される。例として現在問題提起の発端となった verif-type5-multicategory-gift検品用 fixture(最も複雑なタイプ 5) であり、日常運用のルールではない。

3.4 要件のタイプ体系(型 1〜6)が UI に存在しない

要件 §3.6.1 には明確な 6 archetype がある。

名称 要旨
1 金額ベース選択ギフト 規定金額達成で複数候補から選択
2 数量ベース価格割引 規定個数で段階割引(10 個 10% 等)
3 数量ベース無償ギフト 規定個数で無償ギフト(変動 + 固定)
4 複合キャンペーン 価格割引 + 無償ギフト同時
5 マルチカテゴリ選択 カテゴリ横断(A・B・C 各 1 個)で特典
6 ハイブリッド 1〜5 の段階的組合せ

実運用のキャンペーンはほぼこの 6 型に収まるのに、UI は型を意識せず汎用エディタで毎回手組みさせている。ここがテンプレ化の最大レバー。

3.5 非対応エスケープハッチの二分化

hasUnsupportedConfigcampaign-form-mapper.ts:235-253)は、保存後 JSON と builder 再構築 JSON の不一致で「UI で扱えない」を検出し、保存をブロックする。複雑なルールは seed/JSON でしか作れず、UI が実質読み取り専用になる。この二分化自体が複雑さの症状。

4. 改善方針

4.1 採用案: テンプレ層追加(案 B)+ 既存エディタ整理(案 A)の段階適用

内容 評価
A 既存エディタの整理(条件集約・用語統一・折りたたみ・内部 ID 自動採番) 低リスク・効果中。第 1 段で実施
B 型 1〜6 のテンプレ/ウィザード層を上に追加。内部で既存 JSON 生成、エンジン無改修 効果大・後方互換。第 2 段の主軸
C データモデル再設計(3 条件系統合・型をエンティティ化) 影響大・受託コスト過大。今回非採用

方針: 汎用エディタは残したまま、その上に型選択 → 必要欄だけの簡易フォームという「テンプレ層」を被せる。汎用エディタは「上級者向け」「テンプレ非対応ルールの編集」として温存し、hasUnsupportedConfig の逃げ道も維持する。

5. UI 設計

5.1 作成フロー(テンプレ層)

[キャンペーン作成]
   ↓ 型を選ぶ(カード選択: 型1〜6 + 「価格ルール(掛率/単価)」 + 「汎用(上級者)」)
   ↓
[型ごとの簡易フォーム]  ← 必要な欄だけ表示
   ↓ 保存
内部で conditions/tiers JSON を生成 → 既存 createCommercialRule mutation

型ごとに見せる入力欄(最小セット)の指針:

主な入力欄 生成される内部構造(概略)
1 金額選択ギフト 対象範囲 / 最低購入金額 / 選択候補・最大選択数 cart-subtotal>=X + tier に select_gift_items
2 数量価格割引 対象商品 / 数量しきい値の段階 / 割引率 複数 tier(matched-quantity>=N)+ multiply_unit_price
3 数量無償ギフト 対象商品 / 数量しきい値 / ギフト商品・数量 tier(matched-quantity>=N)+ add_gift_items
4 複合 型 2 + 型 3 の合成(割引 tier と ギフト tier) 複数 tier・複数 action
5 マルチカテゴリ カテゴリ別グループ(各必要数量)/ 特典 selection.groups + tier action
6 ハイブリッド 段階定義(数量 → 割引、数量 → ギフト、カテゴリ条件) 多段 tier・cumulative tierMode

5.2 既存エディタの整理(案 A 詳細)

  • 条件入力の集約: 「適用条件」と「ティア発動条件」の重複を解消。原則 ルール全体の前提条件 を 1 か所に集約し、段階のしきい値 は tier に一本化する(運用ガイドで使い分けを明文化)。
  • 用語の言い換え: セレクションID→自動採番で非表示、対象商品小計→「対象商品の金額(税抜)」等、業務語へ統一。「JSON」「storefront 照合」等の実装語は補足ツールチップへ退避。
  • 内部 ID 自動採番: selectionId / groupId / itemId は UI から隠し、保存時に自動生成。
  • 折りたたみ: 未使用セクション(よりどり・選択式ギフト等)はデフォルト折りたたみ。

5.3 価格ルール(kind=pricing)の扱い

掛率・単価固定など kind=pricing は本来ティア/ギフト機構の大半が不要。テンプレ層で「価格ルール」を独立カードにし、tiers の単一 tier に price action だけを持つ最小フォームを出す。

6. 後方互換・移行

  • データ無改修: 既存 commercial_rule_entityconditions/tiers JSON はそのまま。テンプレ層は読み込み時に「どの型に当てはまるか」を推定し、当てはまればテンプレ簡易表示、当てはまらなければ従来の汎用エディタへフォールバック。
  • 検品 fixture: verif-type5-* 等は汎用エディタで従来どおり編集可能。hasUnsupportedConfig 判定ロジック(campaign-form-mapper.ts)は変更しない。
  • 段階リリース:
  • 第 1 段(案 A): 既存エディタの用語・集約・折りたたみ・ID 自動採番。挙動互換、見た目のみ改善。
  • 第 2 段(案 B): 作成フローに型選択カード + 型 1〜3 の簡易フォーム(最頻出)。
  • 第 3 段: 型 4〜6 簡易フォーム + 読み込み時の型推定によるテンプレ表示。

7. 検証方針

  • 各型の簡易フォーム → 生成 JSON が、対応する既存 seed/fixture の JSON と意味的に一致することを単体テストで固定(campaign-form-mapper 周辺)。
  • 既存ルールの読み込み → 保存で JSON が変化しないこと(round-trip)を回帰テスト化。
  • Dashboard コンポーネントの見た目は Playwright CT で locator 単位に固定(AGENTS.md の CT 正本ルールに従う)。

8. 未決事項

  1. 第 1 段の「条件集約」で、適用条件ティア発動条件 を統合する際の既存ルール挙動を完全互換に保てるか(要 round-trip 検証)。一本化が互換を崩す場合は、第 1 段では用語・折りたたみのみに留め、統合は別途検討。
  2. 型推定(読み込み時にどの archetype か判定)の精度と、推定外れ時の UX(汎用エディタへ素直に落とす)。
  3. テンプレ層を作成フローのみに置くか、編集画面でも型ビューを出すか。
  4. kind=pricing をテンプレ層の独立カードにするか、価格ルールは別画面に分離するか。

合意後、第 1 段から着手する。