diff --git a/engage-box/roi_reporting/agent/Dashboard Viz/agent.yml b/engage-box/roi_reporting/agent/Dashboard Viz/agent.yml
index 50187075..24061d65 100644
--- a/engage-box/roi_reporting/agent/Dashboard Viz/agent.yml
+++ b/engage-box/roi_reporting/agent/Dashboard Viz/agent.yml
@@ -2,6 +2,7 @@ name: Dashboard Viz
model: claude-4.5-sonnet
temperature: 0
max_tool_iterations: 4
+prompt_file: prompt.md
outputs:
- name: renderReactApp
diff --git a/engage-box/roi_reporting/agent/README.md b/engage-box/roi_reporting/agent/README.md
index 9781339a..ce3c31ae 100644
--- a/engage-box/roi_reporting/agent/README.md
+++ b/engage-box/roi_reporting/agent/README.md
@@ -217,9 +217,43 @@ Create dashboard with following conditions:
- **Total Revenue** is shown when BOTH direct and contributed revenue exist
- Otherwise, only Direct and/or Contributed Revenue are shown separately
-## Advanced: Manual Configuration
+## Advanced: Manual Configuration via UI
-If you prefer manual setup via UI or LLM API instead of `tdx agent push`, use the legacy setup flow described by your internal Treasure Data setup guidance or contact your Treasure Data account team.
+If you prefer to set up via the Agent Foundry UI instead of `tdx agent push`, follow these steps using the files in this repository as reference:
+
+### 1. Create Project
+
+Navigate to Agent Foundry in the TD Console and create a new project named "ROI Reporting Agent".
+
+### 2. Create Knowledge Bases
+
+**Database KB:**
+- Type: Database
+- Name: `engage_roi_reporting`
+- Database: `engage_roi_reporting`
+- Reference: `knowledge_bases/engage_roi_reporting.yml`
+
+**Text KBs** (create two):
+- Type: Text
+- Name: `OverallSummary_Spec` — copy content from `knowledge_bases/OverallSummary_Spec.md`
+- Name: `CampaignDetails_Spec` — copy content from `knowledge_bases/CampaignDetails_Spec.md`
+
+### 3. Create Agent
+
+- Name: `Dashboard Viz`
+- Model: `claude-4.5-sonnet`
+- Temperature: `0`
+- Max Tool Iterations: `4`
+- System Prompt: copy content from `Dashboard Viz/prompt.md`
+- Tools and Outputs: configure as defined in `Dashboard Viz/agent.yml`
+
+### 4. Create Form Interfaces
+
+Create two form interfaces using the definitions in:
+- `form_interfaces/Overall Summary.yml`
+- `form_interfaces/Campaign Details.yml`
+
+Each file contains `form_schema` (JSON Schema) and `ui_schema` (UI rendering hints) to copy into the respective UI fields.
## License
diff --git a/engage-box/roi_reporting/agent/README_JA.md b/engage-box/roi_reporting/agent/README_JA.md
index e81e186c..33e189d5 100644
--- a/engage-box/roi_reporting/agent/README_JA.md
+++ b/engage-box/roi_reporting/agent/README_JA.md
@@ -217,9 +217,43 @@ Create dashboard with following conditions:
- **Total Revenue**は、DirectとContributed Revenueの両方が存在する場合に表示
- それ以外の場合は、DirectまたはContributed Revenueのみが個別に表示
-## 上級: 手動設定
+## 上級: UIによる手動設定
-UIやLLM API経由での手動セットアップを希望する場合は、英語版READMEの該当セクションを参照してください。
+`tdx agent push` の代わりに Agent Foundry UIでセットアップしたい場合は、このリポジトリのファイルをリファレンスとして以下の手順に従ってください:
+
+### 1. プロジェクト作成
+
+TD ConsoleのAgent Foundryで「ROI Reporting Agent」という名前の新しいプロジェクトを作成します。
+
+### 2. ナレッジベースの作成
+
+**Database KB:**
+- タイプ: Database
+- 名前: `engage_roi_reporting`
+- データベース: `engage_roi_reporting`
+- リファレンス: `knowledge_bases/engage_roi_reporting.yml`
+
+**Text KB** (2つ作成):
+- タイプ: Text
+- 名前: `OverallSummary_Spec` — `knowledge_bases/OverallSummary_Spec.md` の内容をコピー
+- 名前: `CampaignDetails_Spec` — `knowledge_bases/CampaignDetails_Spec.md` の内容をコピー
+
+### 3. エージェントの作成
+
+- 名前: `Dashboard Viz`
+- モデル: `claude-4.5-sonnet`
+- Temperature: `0`
+- Max Tool Iterations: `4`
+- システムプロンプト: `Dashboard Viz/prompt.md` の内容をコピー
+- ツールと出力: `Dashboard Viz/agent.yml` に定義された内容を設定
+
+### 4. フォームインターフェースの作成
+
+以下の定義ファイルを使用してフォームインターフェースを2つ作成:
+- `form_interfaces/Overall Summary.yml`
+- `form_interfaces/Campaign Details.yml`
+
+各ファイルには `form_schema`(JSON Schema)と `ui_schema`(UI表示ヒント)が含まれているので、それぞれUIのフィールドにコピーしてください。
## ライセンス
diff --git a/engage-box/roi_reporting/agent/agent.yml b/engage-box/roi_reporting/agent/agent.yml
deleted file mode 100644
index af571c32..00000000
--- a/engage-box/roi_reporting/agent/agent.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-llm_project: "ROI Reporting Agent"
-name: "Dashboard Viz"
-model: claude-4.5-sonnet
-max_tool_iterations: 4
-temperature: 0
-system_prompt_file: system_prompt.md
-knowledge_bases:
- - name: OverallSummary_Spec
- type: text
- file: knowledge_base_overall_summary.md
- - name: CampaignDetails_Spec
- type: text
- file: knowledge_base_campaign_details.md
- - name: engage_roi_reporting
- type: database
- database: engage_roi_reporting
-tools_file: tools.yml
diff --git a/engage-box/roi_reporting/agent/form_interfaces/td_managed_campaign_details.yml b/engage-box/roi_reporting/agent/form_interfaces/td_managed_campaign_details.yml
deleted file mode 100644
index ba1a98ec..00000000
--- a/engage-box/roi_reporting/agent/form_interfaces/td_managed_campaign_details.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-name: "Campaign Details"
-agent: "@ref(type: \"agent\", name: \"Dashboard Viz\")"
-prompt_template: |
- Create dashboard with following conditions:
- - Report_id: 2. Campaign Summary
- - Campaign_id: {{Campaign_id}},
- - Journey_id: {{Journey_id}},
- - Language: {{Language}},
- - Currency: {{Currency}}
-form_json_schema: '{"type":"object","properties":{"Campaign_id":{"title":"Campaign ID","type":"string","placeholder":"Enter either \"Campaign ID\" or \"Journey ID\""},"Journey_id":{"title":"Journey ID","type":"string","placeholder":"Enter either \"Campaign ID\" or \"Journey ID\""},"Language":{"title":"Language","type":"string","enum":["English","Japanese"],"enumNames":["English","Japanese"]},"Currency":{"title":"Currency","type":"string","enum":["USD","JPY"],"enumNames":["USD","JPY"]}},"required":["Language","Currency"]}'
-form_ui_schema: '{"Campaign_id":{"ui:en:title":"Campaign ID","ui:en:placeholder":"Enter either \"Campaign ID\" or \"Journey ID\"","ui:ja:placeholder":"キャンペーンIDまたは、ジャーニーIDを入力してください","ui:ja:title":"キャンペーンID"},"Journey_id":{"ui:en:title":"Journey ID","ui:en:placeholder":"Enter either \"Campaign ID\" or \"Journey ID\"","ui:ja:title":"ジャーニーID","ui:ja:placeholder":"キャンペーンIDまたは、ジャーニーIDを入力してください"},"Language":{"ui:widget":"radio","ui:en:title":"Language","ui:ja:title":"言語","ui:enumNames":["English","Japanese"],"ui:en:enumNames":["English","Japanese"],"ui:ja:enumNames":["英語","日本語"]},"Currency":{"ui:widget":"radio","ui:en:title":"Currency","ui:ja:title":"通貨","ui:enumNames":["USD","JPY"],"ui:en:enumNames":["USD","JPY"],"ui:ja:enumNames":["米ドル","円"]}}'
-use_text_resource: false
diff --git a/engage-box/roi_reporting/agent/form_interfaces/td_managed_overall_summary.yml b/engage-box/roi_reporting/agent/form_interfaces/td_managed_overall_summary.yml
deleted file mode 100644
index 3fb0ab44..00000000
--- a/engage-box/roi_reporting/agent/form_interfaces/td_managed_overall_summary.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-name: "Overall Summary"
-agent: "@ref(type: \"agent\", name: \"Dashboard Viz\")"
-prompt_template: |
- Create dashboard with following conditions:
- - Report_id: 1.Overall Summary
- - Start Date: {{Start_date}},
- - End Date: {{End_date}},
- - Timezone: {{Timezone}},
- - Language: {{Language}},
- - Currency: {{Currency}}
-form_json_schema: '{"type":"object","properties":{"Start_date":{"title":"Start Date","type":"string","format":"date"},"End_date":{"title":"End Date","type":"string","format":"date"},"Language":{"title":"Language","type":"string","enum":["English","Japanese"],"enumNames":["English","Japanese"]},"Currency":{"title":"Currency","type":"string","enum":["USD","JPY"],"readOnly":false,"enumNames":["USD","JPY"]}},"required":["Start_date","Language","End_date","Currency"]}'
-form_ui_schema: '{"Start_date":{"ui:en:title":"Start Date"},"End_date":{"ui:en:title":"End Date"},"Language":{"ui:widget":"radio","ui:en:title":"Language","ui:enumNames":["English","Japanese"],"ui:en:enumNames":["English","Japanese"],"ui:ja:enumNames":["英語","日本語"],"ui:ja:title":"言語"},"Currency":{"ui:widget":"radio","ui:en:title":"Currency","ui:ja:title":"通貨","ui:enumNames":["USD","JPY"],"ui:en:enumNames":["USD","JPY"],"ui:ja:enumNames":["米ドル","円"]}}'
-use_text_resource: false
diff --git a/engage-box/roi_reporting/agent/knowledge_base_campaign_details.md b/engage-box/roi_reporting/agent/knowledge_base_campaign_details.md
deleted file mode 100644
index 15cd2cae..00000000
--- a/engage-box/roi_reporting/agent/knowledge_base_campaign_details.md
+++ /dev/null
@@ -1,166 +0,0 @@
-# Report Specification: Campaign Details
-
-## 1. Report Overview
-- purpose: "To provide comprehensive performance analysis for a single campaign or journey, including KPIs, trends, and email title breakdown."
-- source_tables:
- - "email_events"
- - "revenue"
-
-## 2. Filters
-- filter:
- - id: "campaign_id"
- type: "string"
- required: true
- exclusive_with: "journey_id"
-- filter:
- - id: "journey_id"
- type: "string"
- required: true
- exclusive_with: "campaign_id"
-- filter_notes: "A campaign_id or journey_id is required. When one of these IDs is provided, a date range is NOT required. The report should run on all available data for that ID."
-- notes: "Timestamp columns (event_timestamp, conversion_timestamp) are varchar strings. They MUST be parsed using date_parse(column, '%Y-%m-%d %H:%i:%s.%f')."
-
-## 3. Important Notes on Metrics
-
-### Unique Count vs Total Count
-- **Unique counts** (primary metrics): Use `COUNT(DISTINCT message_id)` to count each message only once, regardless of how many times it was opened/clicked.
-- **Total counts** (supplementary information): Use `COUNT(*)` to count all events, including multiple opens/clicks of the same message.
-- **Rate calculations**: All rates MUST use unique counts to avoid inflated metrics (industry standard).
-
-### Identifier Standard
-- Use `message_id` (Amazon SES unique message ID) for DISTINCT aggregations.
-- This ensures consistency with Email Delivery Reports and industry best practices.
-
-### Time Granularity (for trend components)
-
-**CRITICAL: Timestamp Parsing**
-- event_timestamp and conversion_timestamp are VARCHAR strings, NOT TIMESTAMP types.
-- You MUST use `date_parse(column, '%Y-%m-%d %H:%i:%s.%f')` to parse these columns.
-- DO NOT use `CAST(column AS DATE)` or `CAST(column AS TIMESTAMP)` - these will fail.
-
-The SQL agent must dynamically set the time grain based on the total date range of available data for the specified campaign_id or journey_id:
-- **<=20 days**: daily granularity
-- **21-89 days**: weekly granularity (starting Monday)
-- **>=90 days**: monthly granularity
-
-This ensures optimal visualization density and performance.
-
-## 4. Component Definitions
-
-### Component 1: Engagement KPIs
-- component:
- - component_id: "kpi_summary_engagement"
- - component_type: "kpi_card_group"
- - title: "Engagement KPIs for {name} ({id})"
- - source_tables: ["email_events"]
- - metrics:
- - { metric_id: "sends", display_name: "Sends", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Send'", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Delivery'", format: "integer" }
- - { metric_id: "unique_opens", display_name: "Unique Opens", calculation: "COUNT(DISTINCT message_id) FROM email_events WHERE event_type = 'Open'", format: "integer", visual_priority: "primary" }
- - { metric_id: "total_opens", display_name: "Total Opens", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Open'", format: "integer", visual_priority: "tertiary", display_note: "Supplementary information" }
- - { metric_id: "unique_open_rate", display_name: "Unique Open Rate", calculation: "(COUNT(DISTINCT message_id) WHERE event_type = 'Open') / (COUNT(*) WHERE event_type = 'Delivery')", format: "percentage", visual_priority: "primary" }
- - { metric_id: "unique_clicks", display_name: "Unique Clicks", calculation: "COUNT(DISTINCT message_id) FROM email_events WHERE event_type = 'Click'", format: "integer", visual_priority: "primary" }
- - { metric_id: "total_clicks", display_name: "Total Clicks", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Click'", format: "integer", visual_priority: "tertiary", display_note: "Supplementary information" }
- - { metric_id: "unique_click_rate", display_name: "Unique Click Rate (CTR)", calculation: "(COUNT(DISTINCT message_id) WHERE event_type = 'Click') / (COUNT(*) WHERE event_type = 'Delivery')", format: "percentage", visual_priority: "primary" }
- - { metric_id: "bounces", display_name: "Bounces", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Bounce'", format: "integer" }
- - { metric_id: "bounce_rate", display_name: "Bounce Rate", calculation: "(COUNT(*) WHERE event_type = 'Bounce') / (COUNT(*) WHERE event_type = 'Send')", format: "percentage" }
- - { metric_id: "unsubscribes", display_name: "Unsubscribes", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Complaint'", format: "integer" }
- - notes: |
- - Visual priority guidance:
- * "primary": Display prominently (e.g., 32px bold for count, 24px bold for rate)
- * "tertiary": Display as supplementary info (e.g., 13px regular, "Total Opens: {value}")
- - All rate calculations MUST use unique counts (COUNT DISTINCT message_id) to avoid inflated rates.
-
-### Component 2: Revenue KPIs
-- component:
- - component_id: "kpi_summary_revenue"
- - component_type: "kpi_card_group"
- - title: "Revenue KPIs for {name} ({id})"
- - source_tables: ["revenue", "email_events"]
- - display_condition: "Only show this component if filtering by campaign_id."
- - query_hints:
- - "To get revenue for a journey, you MUST JOIN the 'revenue' and 'email_events' tables on 'campaign_id'."
- - metrics:
- - { metric_id: "total_revenue", display_name: "Total Revenue", calculation: "SUM(total_revenue) from revenue table where attribution_type is 'direct' or 'contributed'", format: "currency", display_condition: "Only show if both direct and contributed revenue exist." }
- - { metric_id: "direct_revenue", display_name: "Direct Revenue", calculation: "SUM(total_revenue) from revenue table where attribution_type = 'direct'", format: "currency" }
- - { metric_id: "contributed_revenue", display_name: "Contributed Revenue", calculation: "SUM(total_revenue) from revenue table where attribution_type = 'contributed'", format: "currency" }
-
-### Component 3: Performance by Email Title
-- component:
- - component_id: "email_title_performance"
- - component_type: "table"
- - title: "Performance by Email Title"
- - source_tables: ["email_events"]
- - dimensions:
- - { id: "email_title", display_name: "Email Title" }
- - metrics:
- - { metric_id: "sends", display_name: "Sends", calculation: "COUNT(*) WHERE event_type = 'Send'", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "COUNT(*) WHERE event_type = 'Delivery'", format: "integer" }
- - { metric_id: "open_rate", display_name: "Open Rate", calculation: "(COUNT(*) WHERE event_type = 'Open') / (COUNT(*) WHERE event_type = 'Delivery')", format: "percentage" }
- - { metric_id: "ctr", display_name: "CTR (Click-Through Rate)", calculation: "(COUNT(*) WHERE event_type = 'Click') / (COUNT(*) WHERE event_type = 'Delivery')", format: "percentage" }
- - { metric_id: "bounces", display_name: "Bounces", calculation: "COUNT(*) WHERE event_type = 'Bounce'", format: "integer" }
- - { metric_id: "bounce_rate", display_name: "Bounce Rate", calculation: "(COUNT(*) WHERE event_type = 'Bounce') / (COUNT(*) WHERE event_type = 'Send')", format: "percentage" }
- - { metric_id: "unsubscribes", display_name: "Unsubscribes", calculation: "COUNT(*) WHERE event_type = 'Complaint'", format: "integer" }
- - sort_order: "sends DESC, email_title ASC"
- - notes: |
- - Query Construction:
- 1. GROUP BY email_title directly from email_events table
- 2. Filter by campaign_id or journey_id
- 3. No need for event_master table join
- - SQL agent should query with a LIMIT of 51.
- - If 51 rows are returned, the VIZ agent should display a note: 'Showing top 50 titles only. There may be additional titles not displayed.'
- - Display the first 50 rows only.
-
-### Component 4: Engagement Count Trend
-- component:
- - component_id: "engagement_count_trend"
- - component_type: "line_chart"
- - title: "Engagement Trend (Counts)"
- - source_tables: ["email_events"]
- - y_axis_shared: true
- - visualization_hint: "mode: 'lines+markers'"
- - metrics:
- - { metric_id: "sends", display_name: "Sends", calculation: "COUNT(CASE WHEN event_type='Send' THEN 1 END)", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "COUNT(CASE WHEN event_type='Delivery' THEN 1 END)", format: "integer" }
- - { metric_id: "unique_opens", display_name: "Unique Opens", calculation: "COUNT(DISTINCT CASE WHEN event_type='Open' THEN message_id END)", format: "integer", visual_priority: "primary" }
- - { metric_id: "unique_clicks", display_name: "Unique Clicks", calculation: "COUNT(DISTINCT CASE WHEN event_type='Click' THEN message_id END)", format: "integer", visual_priority: "primary" }
- - { metric_id: "bounce_count", display_name: "Bounces", calculation: "COUNT(CASE WHEN event_type='Bounce' THEN 1 END)", format: "integer" }
- - { metric_id: "complaint_count", display_name: "Complaints", calculation: "COUNT(CASE WHEN event_type='Complaint' THEN 1 END)", format: "integer" }
- - notes: |
- - This component is based on the 'event_timestamp' column.
- - Zero-padding is NOT required.
- - Time granularity is determined by the total date range of the campaign/journey data (see Section 3).
- - All metrics use COUNT DISTINCT message_id for opens and clicks to avoid inflated counts.
-
-### Component 5: Conversions and Revenue Trend
-- component:
- - component_id: "conversions_trend"
- - component_type: "line_chart"
- - title: "Conversions & Revenue Trend"
- - source_tables: ["revenue", "email_events"]
- - y_axis_shared: false
- - visualization_hint: "mode: 'lines+markers', dual y-axis (left: count, right: currency)"
- - display_condition: "Only show if filtering by campaign_id."
- - metrics:
- - { metric_id: "conversions", display_name: "Conversions", calculation: "COUNT(DISTINCT conversion_id) FROM revenue", format: "integer", y_axis: "left" }
- - { metric_id: "direct_revenue", display_name: "Direct Revenue", calculation: "SUM(total_revenue) FROM revenue WHERE attribution_type = 'direct'", format: "currency", y_axis: "right" }
- - { metric_id: "contributed_revenue", display_name: "Contributed Revenue", calculation: "SUM(total_revenue) FROM revenue WHERE attribution_type = 'contributed'", format: "currency", y_axis: "right" }
- - { metric_id: "total_revenue", display_name: "Total Revenue", calculation: "SUM(total_revenue) FROM revenue WHERE attribution_type IN ('direct', 'contributed')", format: "currency", y_axis: "right" }
- - notes: |
- - This component is based on the 'conversion_timestamp' column.
- - Zero-padding is NOT required.
- - Time granularity is determined by the total date range of the campaign/journey data (see Section 3).
- - Use dual y-axis: left for count metrics (conversions), right for currency metrics (revenue).
- - This component helps identify day-of-week patterns and campaign timing effects.
-
-## 5. Component Rendering Order
-
-The final output should render components in the following order:
-
-1. Title
-2. Summary (data-driven insights)
-3. kpi_summary_engagement
-4. kpi_summary_revenue (if campaign_id and data exists)
-5. engagement_count_trend
-6. conversions_trend (if campaign_id and data exists)
-7. email_title_performance
diff --git a/engage-box/roi_reporting/agent/knowledge_base_campaign_details_JA.md b/engage-box/roi_reporting/agent/knowledge_base_campaign_details_JA.md
deleted file mode 100644
index 90f2f66e..00000000
--- a/engage-box/roi_reporting/agent/knowledge_base_campaign_details_JA.md
+++ /dev/null
@@ -1,168 +0,0 @@
-# Report Specification: Campaign Details(日本語版)
-
-> **注意**: このドキュメントは参考資料です。正式なレポート仕様は英語版([knowledge_base_campaign_details.md](./knowledge_base_campaign_details.md))を参照してください。
-
-## 1. レポート概要
-- purpose: "単一のキャンペーンまたはジャーニーの包括的なパフォーマンス分析を提供し、KPI、トレンド、メール件名別の内訳を含む。"
-- source_tables:
- - "email_events"
- - "revenue"
-
-## 2. フィルタ
-- filter:
- - id: "campaign_id"
- type: "string"
- required: true
- exclusive_with: "journey_id"
-- filter:
- - id: "journey_id"
- type: "string"
- required: true
- exclusive_with: "campaign_id"
-- filter_notes: "campaign_idまたはjourney_idが必要です。これらのIDの一つが提供された場合、日付範囲は不要です。レポートはそのIDの利用可能なすべてのデータで実行されるべきです。"
-- notes: "タイムスタンプカラム(event_timestamp, conversion_timestamp)はvarchar文字列です。date_parse(column, '%Y-%m-%d %H:%i:%s.%f')を使用して解析する必要があります。"
-
-## 3. メトリクスに関する重要な注意事項
-
-### ユニークカウント vs 総カウント
-- **ユニークカウント**(主要メトリクス): `COUNT(DISTINCT message_id)`を使用して、開封/クリックされた回数に関わらず各メッセージを1回のみカウントします。
-- **総カウント**(補足情報): `COUNT(*)`を使用して、同じメッセージの複数回の開封/クリックを含むすべてのイベントをカウントします。
-- **率計算**: すべての率はユニークカウントを使用する必要があります(業界標準)。
-
-### 識別子標準
-- DISTINCT集計には`message_id`(Amazon SESユニークメッセージID)を使用します。
-- これによりEmail Delivery Reportsおよび業界ベストプラクティスとの一貫性が保証されます。
-
-### 時間粒度(トレンドコンポーネント用)
-
-**重要: タイムスタンプ解析**
-- event_timestampとconversion_timestampはVARCHAR文字列であり、TIMESTAMPタイプではありません。
-- これらのカラムを解析するには`date_parse(column, '%Y-%m-%d %H:%i:%s.%f')`を使用する必要があります。
-- `CAST(column AS DATE)`または`CAST(column AS TIMESTAMP)`は使用しないでください - これらは失敗します。
-
-SQLエージェントは、指定されたcampaign_idまたはjourney_idの利用可能なデータの総日付範囲に基づいて時間粒度を動的に設定する必要があります:
-- **<=20日**: 日次粒度
-- **21-89日**: 週次粒度(月曜日開始)
-- **>=90日**: 月次粒度
-
-これにより最適な可視化密度とパフォーマンスが保証されます。
-
-## 4. コンポーネント定義
-
-### コンポーネント1: エンゲージメントKPI
-- component:
- - component_id: "kpi_summary_engagement"
- - component_type: "kpi_card_group"
- - title: "Engagement KPIs for {name} ({id})"
- - source_tables: ["email_events"]
- - metrics:
- - { metric_id: "sends", display_name: "Sends", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Send'", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Delivery'", format: "integer" }
- - { metric_id: "unique_opens", display_name: "Unique Opens", calculation: "COUNT(DISTINCT message_id) FROM email_events WHERE event_type = 'Open'", format: "integer", visual_priority: "primary" }
- - { metric_id: "total_opens", display_name: "Total Opens", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Open'", format: "integer", visual_priority: "tertiary", display_note: "補足情報" }
- - { metric_id: "unique_open_rate", display_name: "Unique Open Rate", calculation: "(COUNT(DISTINCT message_id) WHERE event_type = 'Open') / (COUNT(*) WHERE event_type = 'Delivery')", format: "percentage", visual_priority: "primary" }
- - { metric_id: "unique_clicks", display_name: "Unique Clicks", calculation: "COUNT(DISTINCT message_id) FROM email_events WHERE event_type = 'Click'", format: "integer", visual_priority: "primary" }
- - { metric_id: "total_clicks", display_name: "Total Clicks", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Click'", format: "integer", visual_priority: "tertiary", display_note: "補足情報" }
- - { metric_id: "unique_click_rate", display_name: "Unique Click Rate (CTR)", calculation: "(COUNT(DISTINCT message_id) WHERE event_type = 'Click') / (COUNT(*) WHERE event_type = 'Delivery')", format: "percentage", visual_priority: "primary" }
- - { metric_id: "bounces", display_name: "Bounces", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Bounce'", format: "integer" }
- - { metric_id: "bounce_rate", display_name: "Bounce Rate", calculation: "(COUNT(*) WHERE event_type = 'Bounce') / (COUNT(*) WHERE event_type = 'Send')", format: "percentage" }
- - { metric_id: "unsubscribes", display_name: "Unsubscribes", calculation: "COUNT(*) FROM email_events WHERE event_type = 'Complaint'", format: "integer" }
- - notes: |
- - ビジュアル優先度ガイダンス:
- * "primary": 目立つように表示(例: カウントは32pxボールド、率は24pxボールド)
- * "tertiary": 補足情報として表示(例: 13px通常、"Total Opens: {value}")
- - すべての率計算はユニークカウント(COUNT DISTINCT message_id)を使用して、膨張したメトリクスを避ける必要があります。
-
-### コンポーネント2: 収益KPI
-- component:
- - component_id: "kpi_summary_revenue"
- - component_type: "kpi_card_group"
- - title: "Revenue KPIs for {name} ({id})"
- - source_tables: ["revenue", "email_events"]
- - display_condition: "campaign_idでフィルタリングしている場合のみこのコンポーネントを表示。"
- - query_hints:
- - "ジャーニーの収益を取得するには、'revenue'と'email_events'テーブルを'campaign_id'でJOINする必要があります。"
- - metrics:
- - { metric_id: "total_revenue", display_name: "Total Revenue", calculation: "SUM(total_revenue) from revenue table where attribution_type is 'direct' or 'contributed'", format: "currency", display_condition: "直接収益と貢献収益の両方が存在する場合のみ表示。" }
- - { metric_id: "direct_revenue", display_name: "Direct Revenue", calculation: "SUM(total_revenue) from revenue table where attribution_type = 'direct'", format: "currency" }
- - { metric_id: "contributed_revenue", display_name: "Contributed Revenue", calculation: "SUM(total_revenue) from revenue table where attribution_type = 'contributed'", format: "currency" }
-
-### コンポーネント3: メール件名別パフォーマンス
-- component:
- - component_id: "email_title_performance"
- - component_type: "table"
- - title: "Performance by Email Title"
- - source_tables: ["email_events"]
- - dimensions:
- - { id: "email_title", display_name: "Email Title" }
- - metrics:
- - { metric_id: "sends", display_name: "Sends", calculation: "COUNT(*) WHERE event_type = 'Send'", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "COUNT(*) WHERE event_type = 'Delivery'", format: "integer" }
- - { metric_id: "open_rate", display_name: "Open Rate", calculation: "(COUNT(*) WHERE event_type = 'Open') / (COUNT(*) WHERE event_type = 'Delivery')", format: "percentage" }
- - { metric_id: "ctr", display_name: "CTR (Click-Through Rate)", calculation: "(COUNT(*) WHERE event_type = 'Click') / (COUNT(*) WHERE event_type = 'Delivery')", format: "percentage" }
- - { metric_id: "bounces", display_name: "Bounces", calculation: "COUNT(*) WHERE event_type = 'Bounce'", format: "integer" }
- - { metric_id: "bounce_rate", display_name: "Bounce Rate", calculation: "(COUNT(*) WHERE event_type = 'Bounce') / (COUNT(*) WHERE event_type = 'Send')", format: "percentage" }
- - { metric_id: "unsubscribes", display_name: "Unsubscribes", calculation: "COUNT(*) WHERE event_type = 'Complaint'", format: "integer" }
- - sort_order: "sends DESC, email_title ASC"
- - notes: |
- - クエリ構築:
- 1. email_eventsテーブルから直接email_titleでGROUP BY
- 2. campaign_idまたはjourney_idでフィルタ
- 3. event_masterテーブルとのJOINは不要
- - SQLエージェントはLIMIT 51でクエリする必要があります。
- - 51行が返された場合、VIZエージェントは注記を表示する必要があります: '上位50件のみ表示しています。追加の件名が表示されていない可能性があります。'
- - 最初の50行のみを表示します。
-
-### コンポーネント4: エンゲージメント数トレンド
-- component:
- - component_id: "engagement_count_trend"
- - component_type: "line_chart"
- - title: "Engagement Trend (Counts)"
- - source_tables: ["email_events"]
- - y_axis_shared: true
- - visualization_hint: "mode: 'lines+markers'"
- - metrics:
- - { metric_id: "sends", display_name: "Sends", calculation: "COUNT(CASE WHEN event_type='Send' THEN 1 END)", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "COUNT(CASE WHEN event_type='Delivery' THEN 1 END)", format: "integer" }
- - { metric_id: "unique_opens", display_name: "Unique Opens", calculation: "COUNT(DISTINCT CASE WHEN event_type='Open' THEN message_id END)", format: "integer", visual_priority: "primary" }
- - { metric_id: "unique_clicks", display_name: "Unique Clicks", calculation: "COUNT(DISTINCT CASE WHEN event_type='Click' THEN message_id END)", format: "integer", visual_priority: "primary" }
- - { metric_id: "bounce_count", display_name: "Bounces", calculation: "COUNT(CASE WHEN event_type='Bounce' THEN 1 END)", format: "integer" }
- - { metric_id: "complaint_count", display_name: "Complaints", calculation: "COUNT(CASE WHEN event_type='Complaint' THEN 1 END)", format: "integer" }
- - notes: |
- - このコンポーネントは'event_timestamp'カラムに基づいています。
- - ゼロパディングは不要です。
- - 時間粒度はキャンペーン/ジャーニーデータの総日付範囲によって決定されます(セクション3参照)。
- - すべてのメトリクスは開封とクリックにCOUNT DISTINCT message_idを使用して、膨張したカウントを避けます。
-
-### コンポーネント5: コンバージョン・収益トレンド
-- component:
- - component_id: "conversions_trend"
- - component_type: "line_chart"
- - title: "Conversions & Revenue Trend"
- - source_tables: ["revenue", "email_events"]
- - y_axis_shared: false
- - visualization_hint: "mode: 'lines+markers', dual y-axis (left: count, right: currency)"
- - display_condition: "campaign_idでフィルタリングしている場合のみ表示。"
- - metrics:
- - { metric_id: "conversions", display_name: "Conversions", calculation: "COUNT(DISTINCT conversion_id) FROM revenue", format: "integer", y_axis: "left" }
- - { metric_id: "direct_revenue", display_name: "Direct Revenue", calculation: "SUM(total_revenue) FROM revenue WHERE attribution_type = 'direct'", format: "currency", y_axis: "right" }
- - { metric_id: "contributed_revenue", display_name: "Contributed Revenue", calculation: "SUM(total_revenue) FROM revenue WHERE attribution_type = 'contributed'", format: "currency", y_axis: "right" }
- - { metric_id: "total_revenue", display_name: "Total Revenue", calculation: "SUM(total_revenue) FROM revenue WHERE attribution_type IN ('direct', 'contributed')", format: "currency", y_axis: "right" }
- - notes: |
- - このコンポーネントは'conversion_timestamp'カラムに基づいています。
- - ゼロパディングは不要です。
- - 時間粒度はキャンペーン/ジャーニーデータの総日付範囲によって決定されます(セクション3参照)。
- - デュアルy軸を使用: カウントメトリクス(コンバージョン)は左、通貨メトリクス(収益)は右。
- - このコンポーネントは曜日パターンやキャンペーンタイミング効果の特定に役立ちます。
-
-## 5. コンポーネントレンダリング順序
-
-最終出力は以下の順序でコンポーネントをレンダリングする必要があります:
-
-1. Title
-2. Summary(データドリブンなインサイト)
-3. kpi_summary_engagement
-4. kpi_summary_revenue(campaign_idでデータが存在する場合)
-5. engagement_count_trend
-6. conversions_trend(campaign_idでデータが存在する場合)
-7. email_title_performance
diff --git a/engage-box/roi_reporting/agent/knowledge_base_overall_summary.md b/engage-box/roi_reporting/agent/knowledge_base_overall_summary.md
deleted file mode 100644
index 44fdacc9..00000000
--- a/engage-box/roi_reporting/agent/knowledge_base_overall_summary.md
+++ /dev/null
@@ -1,140 +0,0 @@
-# Report Specification: OverallSummary
-
-## 1. Report Overview
-- purpose: "To visualize key performance indicators (KPIs), trends, and top-performing campaigns/journeys over a specified period."
-- source_tables:
- - "daily_summary"
- - "event_master" # Used for name lookups in rankings
-
-## 2. Filters
-- filter:
- - id: "date_range"
- - type: "date"
- - required: true
- - notes: |
- - A date range (start_date, end_date) is mandatory.
- - If no range is provided, the SQL agent should return the min/max available dates and an error.
- - The SQL agent will validate the range. If it exceeds 365 days, the agent will reject the request and return a message suggesting a valid 365-day range.
-
-## 3. Important Notes on Metrics
-
-**Note:** This section describes the calculation methodology. A user-facing disclaimer must be displayed at the end of the report (see Component: data_methodology_disclaimer).
-
-## 4. Component Definitions
-- component:
- - component_id: "kpi_summary"
- - component_type: "kpi_card_group"
- - title: "Overall Performance Summary"
- - metrics:
- - { metric_id: "sends", display_name: "Sends", calculation: "SUM(total_sends)", format: "integer" }
- - { metric_id: "total_revenue", display_name: "Total Revenue", calculation: "SUM(total_revenue_direct + total_revenue_contributed)", format: "currency", display_condition: "Show only if SUM(total_revenue_direct) > 0 AND SUM(total_revenue_contributed) > 0" }
- - { metric_id: "direct_revenue", display_name: "Direct Revenue", calculation: "SUM(total_revenue_direct)", format: "currency" }
- - { metric_id: "contributed_revenue", display_name: "Contributed Revenue", calculation: "SUM(total_revenue_contributed)", format: "currency" }
- - { metric_id: "conversions", display_name: "Conversions", calculation: "SUM(total_conversions)", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "SUM(total_deliveries)", format: "integer" }
- - { metric_id: "opens", display_name: "Opens", calculation: "SUM(total_opens)", format: "integer" }
- - { metric_id: "open_rate", display_name: "Open Rate", calculation: "SUM(total_opens) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "clicks", display_name: "Clicks", calculation: "SUM(total_clicks)", format: "integer" }
- - { metric_id: "click_rate", display_name: "Click Rate", calculation: "SUM(total_clicks) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "bounces", display_name: "Bounces", calculation: "SUM(total_hard_bounces + total_soft_bounces)", format: "integer" }
- - { metric_id: "bounce_rate", display_name: "Bounce Rate", calculation: "SUM(total_hard_bounces + total_soft_bounces) / SUM(total_sends)", format: "percentage" }
- - { metric_id: "unsubscribes", display_name: "Unsubscribes", calculation: "SUM(total_unsubscribes)", format: "integer" }
-
-- component:
- - component_id: "campaign_performance_ranking"
- - component_type: "table"
- - title: "Top 5 Campaigns"
- - source_tables: ["daily_summary", "event_master"]
- - dimensions:
- - { id: "campaign_name", display_name: "Campaign Name" }
- - { id: "campaign_id", display_name: "Campaign ID" }
- - metrics:
- - { metric_id: "revenue", display_name: "Revenue", format: "currency" }
- - { metric_id: "conversions", display_name: "Conversions", calculation: "SUM(total_conversions)", format: "integer" }
- - { metric_id: "sends", display_name: "Sends", calculation: "SUM(total_sends)", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "SUM(total_deliveries)", format: "integer" }
- - { metric_id: "open_rate", display_name: "Open Rate", calculation: "SUM(total_opens) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "click_rate", display_name: "Click Rate", calculation: "SUM(total_clicks) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "bounce_rate", display_name: "Bounce Rate", calculation: "SUM(total_hard_bounces + total_soft_bounces) / SUM(total_sends)", format: "percentage" }
- - orderby_clause_template: "ORDER BY SUM(total_revenue_direct + total_revenue_contributed) DESC, SUM(total_conversions) DESC, SUM(total_clicks) DESC, campaign_id DESC"
- - notes: |
- - This component ranks campaigns. The final sort order MUST use the provided 'orderby_clause_template'.
- - Date filtering MUST use the 'summary_date' column (varchar) with string-based comparison (e.g., WHERE summary_date BETWEEN 'YYYY-MM-DD' AND 'YYYY-MM-DD').
- - The 'Revenue' column to be displayed is dynamic. The agent must construct a CASE statement to show Total, Direct, or Contributed Revenue based on the rules previously discussed.
-
-- component:
- - component_id: "journey_performance_ranking"
- - component_type: "table"
- - title: "Top 5 Journeys"
- - source_tables: ["daily_summary", "event_master"]
- - dimensions:
- - { id: "journey_name", display_name: "Journey Name" }
- - { id: "journey_id", display_name: "Journey ID" }
- - metrics:
- - { metric_id: "revenue", display_name: "Revenue", format: "currency" }
- - { metric_id: "conversions", display_name: "Conversions", calculation: "SUM(total_conversions)", format: "integer" }
- - { metric_id: "sends", display_name: "Sends", calculation: "SUM(total_sends)", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "SUM(total_deliveries)", format: "integer" }
- - { metric_id: "open_rate", display_name: "Open Rate", calculation: "SUM(total_opens) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "click_rate", display_name: "Click Rate", calculation: "SUM(total_clicks) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "bounce_rate", display_name: "Bounce Rate", calculation: "SUM(total_hard_bounces + total_soft_bounces) / SUM(total_sends)", format: "percentage" }
- - orderby_clause_template: "ORDER BY SUM(total_revenue_direct + total_revenue_contributed) DESC, SUM(total_conversions) DESC, SUM(total_clicks) DESC, journey_id DESC"
- - notes: |
- - This component ranks journeys. The final sort order MUST use the provided 'orderby_clause_template'.
- - Date filtering MUST use the 'summary_date' column (varchar) with string-based comparison (e.g., WHERE summary_date BETWEEN 'YYYY-MM-DD' AND 'YYYY-MM-DD').
- - The 'Revenue' column to be displayed is dynamic. The agent must construct a CASE statement to show Total, Direct, or Contributed Revenue based on the rules previously discussed.
-
-- component:
- - component_id: "performance_trend"
- - component_type: "trend_chart"
- - title: "Performance Trend"
- - tabs:
- - tab_name: "Engagement"
- metrics:
- - { metric_id: "sends", display_name: "Sends", calculation: "SUM(total_sends)" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "SUM(total_deliveries)" }
- - { metric_id: "clicks", display_name: "Clicks", calculation: "SUM(total_clicks)" }
- - tab_name: "Revenue"
- metrics:
- - { metric_id: "revenue", display_name: "Revenue", calculation: "SUM(total_revenue_direct + total_revenue_contributed)" }
- display_condition: "Show tab only if total revenue for the period > 0"
- - notes: |
- - This component uses the 'summary_date' (varchar) column. For date functions like date_trunc, it MUST be converted using CAST(summary_date AS DATE).
- - The SQL agent must dynamically set the time grain based on the length of the date range:
- * <=20 days: daily
- * 21-89 days: weekly (starting Monday)
- * >=90 days: monthly
- - The agent must perform zero-padding to ensure a continuous time series.
-
-- component:
- - component_id: "data_methodology_disclaimer"
- - component_type: "text_note"
- - title: "Data Aggregation Methodology"
- - content: |
- Note: The open rate and click rate in this report are calculated based on total event counts from the daily_summary table.
- When the same email is opened or clicked multiple times, each event is counted separately.
- This may result in rates appearing higher than unique open/click rates.
-
- For more detailed analysis with unique count-based metrics, please refer to the Campaign Details report.
- - display_condition: "ALWAYS - This component MUST be displayed at the end of every report."
- - notes: |
- - CRITICAL: This disclaimer MUST always be rendered at the very end of the report, after all other components.
- - This is not optional - it must appear in every OverallSummary report regardless of data or filters.
- - Rendering style: Plain text only, no borders, no background color, no box shadow, no bold text.
- - Use regular font weight (not bold), normal font size (14-16px).
- - Background color: transparent or same as page background (white/light gray).
- - No visual highlighting or emphasis - this should blend into the page as simple footer text.
-
-## 5. Component Rendering Order
-
-The final output MUST render components in the following order:
-
-1. Report Title
-2. Summary (data-driven insights)
-3. kpi_summary
-4. campaign_performance_ranking
-5. journey_performance_ranking
-6. performance_trend
-7. **data_methodology_disclaimer** ← MUST BE LAST
-
-**IMPORTANT:** The data_methodology_disclaimer component MUST always appear at the very end of the report, regardless of other component rendering or data availability.
diff --git a/engage-box/roi_reporting/agent/knowledge_base_overall_summary_JA.md b/engage-box/roi_reporting/agent/knowledge_base_overall_summary_JA.md
deleted file mode 100644
index d9f3226b..00000000
--- a/engage-box/roi_reporting/agent/knowledge_base_overall_summary_JA.md
+++ /dev/null
@@ -1,142 +0,0 @@
-# Report Specification: OverallSummary(日本語版)
-
-> **注意**: このドキュメントは参考資料です。正式なレポート仕様は英語版([knowledge_base_overall_summary.md](./knowledge_base_overall_summary.md))を参照してください。
-
-## 1. レポート概要
-- purpose: "指定された期間における主要パフォーマンス指標(KPI)、トレンド、上位キャンペーン/ジャーニーを可視化する。"
-- source_tables:
- - "daily_summary"
- - "event_master" # ランキングでの名前検索に使用
-
-## 2. フィルタ
-- filter:
- - id: "date_range"
- - type: "date"
- - required: true
- - notes: |
- - 日付範囲(start_date, end_date)は必須です。
- - 範囲が指定されない場合、SQLエージェントは利用可能な最小/最大日付とエラーを返してください。
- - SQLエージェントは範囲を検証します。365日を超える場合、リクエストを拒否し、有効な365日範囲を提案するメッセージを返します。
-
-## 3. メトリクスに関する重要な注意事項
-
-**注意:** このセクションは計算方法論を説明します。レポートの最後にユーザー向け免責事項を表示する必要があります(Component: data_methodology_disclaimerを参照)。
-
-## 4. コンポーネント定義
-- component:
- - component_id: "kpi_summary"
- - component_type: "kpi_card_group"
- - title: "Overall Performance Summary"
- - metrics:
- - { metric_id: "sends", display_name: "Sends", calculation: "SUM(total_sends)", format: "integer" }
- - { metric_id: "total_revenue", display_name: "Total Revenue", calculation: "SUM(total_revenue_direct + total_revenue_contributed)", format: "currency", display_condition: "SUM(total_revenue_direct) > 0 AND SUM(total_revenue_contributed) > 0の場合のみ表示" }
- - { metric_id: "direct_revenue", display_name: "Direct Revenue", calculation: "SUM(total_revenue_direct)", format: "currency" }
- - { metric_id: "contributed_revenue", display_name: "Contributed Revenue", calculation: "SUM(total_revenue_contributed)", format: "currency" }
- - { metric_id: "conversions", display_name: "Conversions", calculation: "SUM(total_conversions)", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "SUM(total_deliveries)", format: "integer" }
- - { metric_id: "opens", display_name: "Opens", calculation: "SUM(total_opens)", format: "integer" }
- - { metric_id: "open_rate", display_name: "Open Rate", calculation: "SUM(total_opens) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "clicks", display_name: "Clicks", calculation: "SUM(total_clicks)", format: "integer" }
- - { metric_id: "click_rate", display_name: "Click Rate", calculation: "SUM(total_clicks) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "bounces", display_name: "Bounces", calculation: "SUM(total_hard_bounces + total_soft_bounces)", format: "integer" }
- - { metric_id: "bounce_rate", display_name: "Bounce Rate", calculation: "SUM(total_hard_bounces + total_soft_bounces) / SUM(total_sends)", format: "percentage" }
- - { metric_id: "unsubscribes", display_name: "Unsubscribes", calculation: "SUM(total_unsubscribes)", format: "integer" }
-
-- component:
- - component_id: "campaign_performance_ranking"
- - component_type: "table"
- - title: "Top 5 Campaigns"
- - source_tables: ["daily_summary", "event_master"]
- - dimensions:
- - { id: "campaign_name", display_name: "Campaign Name" }
- - { id: "campaign_id", display_name: "Campaign ID" }
- - metrics:
- - { metric_id: "revenue", display_name: "Revenue", format: "currency" }
- - { metric_id: "conversions", display_name: "Conversions", calculation: "SUM(total_conversions)", format: "integer" }
- - { metric_id: "sends", display_name: "Sends", calculation: "SUM(total_sends)", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "SUM(total_deliveries)", format: "integer" }
- - { metric_id: "open_rate", display_name: "Open Rate", calculation: "SUM(total_opens) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "click_rate", display_name: "Click Rate", calculation: "SUM(total_clicks) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "bounce_rate", display_name: "Bounce Rate", calculation: "SUM(total_hard_bounces + total_soft_bounces) / SUM(total_sends)", format: "percentage" }
- - orderby_clause_template: "ORDER BY SUM(total_revenue_direct + total_revenue_contributed) DESC, SUM(total_conversions) DESC, SUM(total_clicks) DESC, campaign_id DESC"
- - notes: |
- - このコンポーネントはキャンペーンをランク付けします。最終ソート順は提供された'orderby_clause_template'を使用する必要があります。
- - 日付フィルタリングは'summary_date'カラム(varchar)を使用し、文字列ベースの比較を行う必要があります(例: WHERE summary_date BETWEEN 'YYYY-MM-DD' AND 'YYYY-MM-DD')。
- - 表示する'Revenue'カラムは動的です。エージェントは以前に議論したルールに基づいてTotal、Direct、またはContributed Revenueを表示するCASE文を構築する必要があります。
-
-- component:
- - component_id: "journey_performance_ranking"
- - component_type: "table"
- - title: "Top 5 Journeys"
- - source_tables: ["daily_summary", "event_master"]
- - dimensions:
- - { id: "journey_name", display_name: "Journey Name" }
- - { id: "journey_id", display_name: "Journey ID" }
- - metrics:
- - { metric_id: "revenue", display_name: "Revenue", format: "currency" }
- - { metric_id: "conversions", display_name: "Conversions", calculation: "SUM(total_conversions)", format: "integer" }
- - { metric_id: "sends", display_name: "Sends", calculation: "SUM(total_sends)", format: "integer" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "SUM(total_deliveries)", format: "integer" }
- - { metric_id: "open_rate", display_name: "Open Rate", calculation: "SUM(total_opens) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "click_rate", display_name: "Click Rate", calculation: "SUM(total_clicks) / SUM(total_deliveries)", format: "percentage" }
- - { metric_id: "bounce_rate", display_name: "Bounce Rate", calculation: "SUM(total_hard_bounces + total_soft_bounces) / SUM(total_sends)", format: "percentage" }
- - orderby_clause_template: "ORDER BY SUM(total_revenue_direct + total_revenue_contributed) DESC, SUM(total_conversions) DESC, SUM(total_clicks) DESC, journey_id DESC"
- - notes: |
- - このコンポーネントはジャーニーをランク付けします。最終ソート順は提供された'orderby_clause_template'を使用する必要があります。
- - 日付フィルタリングは'summary_date'カラム(varchar)を使用し、文字列ベースの比較を行う必要があります。
- - 表示する'Revenue'カラムは動的です。
-
-- component:
- - component_id: "performance_trend"
- - component_type: "trend_chart"
- - title: "Performance Trend"
- - tabs:
- - tab_name: "Engagement"
- metrics:
- - { metric_id: "sends", display_name: "Sends", calculation: "SUM(total_sends)" }
- - { metric_id: "deliveries", display_name: "Deliveries", calculation: "SUM(total_deliveries)" }
- - { metric_id: "clicks", display_name: "Clicks", calculation: "SUM(total_clicks)" }
- - tab_name: "Revenue"
- metrics:
- - { metric_id: "revenue", display_name: "Revenue", calculation: "SUM(total_revenue_direct + total_revenue_contributed)" }
- display_condition: "期間の総収益 > 0の場合のみタブを表示"
- - notes: |
- - このコンポーネントは'summary_date'(varchar)カラムを使用します。date_truncなどの日付関数にはCAST(summary_date AS DATE)を使用する必要があります。
- - SQLエージェントは日付範囲の長さに基づいて時間粒度を動的に設定する必要があります:
- * <=20日: 日次
- * 21-89日: 週次(月曜日開始)
- * >=90日: 月次
- - エージェントは連続した時系列を確保するためにゼロパディングを実行する必要があります。
-
-- component:
- - component_id: "data_methodology_disclaimer"
- - component_type: "text_note"
- - title: "Data Aggregation Methodology"
- - content: |
- 注意: このレポートの開封率とクリック率は、daily_summaryテーブルの総イベントカウントに基づいて計算されています。
- 同じメールが複数回開封またはクリックされた場合、各イベントは個別にカウントされます。
- これにより、ユニーク開封/クリック率よりも高い率が表示される場合があります。
-
- ユニークカウントベースのメトリクスによる詳細な分析については、Campaign Detailsレポートを参照してください。
- - display_condition: "ALWAYS - このコンポーネントはすべてのレポートの最後に必ず表示する必要があります。"
- - notes: |
- - 重要: この免責事項は常にレポートの最後、他のすべてのコンポーネントの後にレンダリングされる必要があります。
- - これはオプションではありません - データやフィルタに関わらず、すべてのOverallSummaryレポートに表示される必要があります。
- - レンダリングスタイル: プレーンテキストのみ、ボーダーなし、背景色なし、ボックスシャドウなし、ボールドテキストなし。
- - 通常のフォントウェイト(ボールドでない)、通常のフォントサイズ(14-16px)を使用。
- - 背景色: transparentまたはページ背景と同じ(白/ライトグレー)。
- - 視覚的なハイライトや強調なし - シンプルなフッターテキストとしてページに溶け込むべきです。
-
-## 5. コンポーネントレンダリング順序
-
-最終出力は以下の順序でコンポーネントをレンダリングする必要があります:
-
-1. Report Title
-2. Summary(データドリブンなインサイト)
-3. kpi_summary
-4. campaign_performance_ranking
-5. journey_performance_ranking
-6. performance_trend
-7. **data_methodology_disclaimer** ← 必ず最後
-
-**重要:** data_methodology_disclaimerコンポーネントは、他のコンポーネントのレンダリングやデータの可用性に関わらず、常にレポートの最後に表示される必要があります。
diff --git a/engage-box/roi_reporting/agent/system_prompt.md b/engage-box/roi_reporting/agent/system_prompt.md
deleted file mode 100644
index b483ef66..00000000
--- a/engage-box/roi_reporting/agent/system_prompt.md
+++ /dev/null
@@ -1,146 +0,0 @@
-## Your Role
-
-You are a unified ROI reporting agent that autonomously generates dashboard reports. Based on specifications and user instructions, you execute SQL queries against Trino, visualize intermediate results, and generate a single self-contained .jsx file.
-
-## Core Principles
-
-- Graceful Degradation: Deliver the best possible report using available data. If components fail, continue with successful ones.
-- Autonomous Execution: Execute end-to-end without waiting for user prompts until final renderReactApp call. Never ask for optional parameters - proceed with available data.
-- Progressive Disclosure: Show intermediate Plotly visualizations for each component.
-- Silent Final Assembly: Last action must be a single renderReactApp call with complete code.
-
-## Execution Flow
-
-1. Planning
- - Read YAML spec, list all components, create build plan
- - Note: Summary executed LAST but rendered FIRST in output
- - Evaluate component-level display_condition, exclude if false
- - Normalize inputs: report_spec_name, component_id, filters
-
-2. Data Retrieval (Per Component)
- - Schema Validation: Verify all required columns exist
- - SQL Generation: Follow YAML spec and Trino SQL Cookbook below
- - Apply filters strictly (no fuzzy matching)
- - Execute query, retry on failure with corrections
- - If zero rows: record error, skip component
- - Show intermediate visualization via render_plotly_chart
-
-3. Summary Generation
- - Execute AFTER all components (step 3), render FIRST in output (step 4)
- - Provide data-driven insights using ONLY retrieved SQL results
- - Describe what data shows, NOT what you generated
- - Mention missing components/metrics if applicable
- - Constraints: No calculations, no new queries, no assumptions
-
-4. Final Build
- - Render order: Title → Summary → Components (spec order)
- - Evaluate metric-level display_condition at render time
- - Generate React components per component_type
- - Call renderReactApp once with complete code
-
-## Display Condition Rules
-
-- Component-level: Evaluated before SQL (planning). If false, skip entire component.
-- Metric-level: Evaluated after SQL (rendering). If false, hide only that metric within component.
-- Never hide entire component due to metric-level condition.
-
-## Trino SQL Cookbook
-
-- Division: CAST(SUM(num) AS DOUBLE) / NULLIF(SUM(denom), 0)
-- Conditional Aggregation: SUM(CASE WHEN cond THEN 1 ELSE 0 END)
-- Date varchar: WHERE col BETWEEN '...' AND '...'. For functions: CAST(col AS DATE)
-- Timestamp varchar: date_parse(col, '%Y-%m-%d %H:%i:%s.%f')
-- Time Series Zero-Filling:
- WITH date_range AS (SELECT CAST(MIN(...) AS DATE) AS s, CAST(MAX(...) AS DATE) AS e FROM ...),
- time_series AS (SELECT t.dt FROM date_range CROSS JOIN UNNEST(SEQUENCE(s, e, INTERVAL '1' DAY)) AS t(dt))
- SELECT ... FROM time_series LEFT JOIN ...
-- Ranking: Use WITH clauses, no ROW_NUMBER()
-- Final SELECT: No GROUP BY or aggregates in final SELECT
-- Ordering: Use spec's orderby_clause_template if available
-- LIMIT: Follow spec's notes exactly
-
-## Filter Rules
-
-- Strict matching only (no modification, no fuzzy matching)
-- Optionally verify filters yield >0 rows
-- Required filters (required: true in spec): Must be provided or call text_in_form
-- Optional filters: If not provided, skip components that require them (use display_condition)
-- NEVER ask user for optional filter values - proceed with available data only
-
-## Error Handling
-
-- Missing arguments: Call text_in_form, stop
-- Missing OPTIONAL arguments: Proceed without them (skip related components if needed) **Important:** Required arguments are explicitly marked as "required: true" in spec filters. All other arguments are optional and should NOT trigger user prompts.
-- Schema mismatch: Record error, continue to next component
-- SQL failure: Analyze, retry. If unresolved, record error, continue
-- Zero data: Record {code: "NO_DATA_FOR_FILTER"}, skip component
-- No successful components: Call text_in_form
-
-## Intermediate Visualization
-
-- After each successful data retrieval
-- Use render_plotly_chart: bar for KPIs, table for tables, line for trends
-- Include component title and brief status
-
-## Final Build: React Generation
-
-- Single .jsx file, no relative imports
-- Imports: import React from 'react'; import Plot from 'react-plotly.js';
-- Prohibited: @mui/material, styled-components, Plotly.newPlot()
-- React Hooks: React.useState(), React.useEffect(), React.useRef()
-- Plotly: Use