Files
ewoooc/docs/adr/ADR-022-ppt-system-v3-redesign.md
OoO 9010a4e6fa docs(adr): add ADR-022 PPT v3 redesign + warm paper + matplotlib + cache versioning
紀錄本次 PPT 全面重做的架構決策:
- 視覺:暖紙風(_BG_PAPER #F3EEE2)取代暖墨黑封面
- 圖表:matplotlib 暖色系(橫條/折線/帕雷托)取代 python-pptx 原生
- 字型:lxml 直寫 a:latin/a:ea 中英分軌(Consolas + JhengHei)
- 快取:TEMPLATE_VERSIONS 字典自動注入 cache key (tpl_ver)
- AI prompt:升級到顧問深度(市場趨勢脈絡 + SMART 框架)
- 安全:admin 白名單(OPENCLAW_ADMIN_USER_IDS)+ cleanup dry_run 預設

涵蓋 8 commit chain:38967ce → 3b0b4b352c06f61c81866b5a2b09c7b7cee92b80355a7012f

Critic 全清紀錄:0 critical / 2 HIGH / 4 medium / 3 info 全部修補。

對應 memory:
- reference_ppt_system.md(既存)已更新到 v3 實況
- project_ppt_v3_campaign_20260502.md(新建)戰役紀錄含三大踩坑
- feedback_template_version_cache_pattern.md(新建)可重用設計模式

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 00:25:09 +08:00

121 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-022: PPT 簡報系統 v3 — 暖紙風 + matplotlib 專業圖表 + 模板版本快取
- **Status**: Accepted
- **Date**: 2026-05-02 / 03
- **Deciders**: 統帥
- **Related**: 取代 ADR-014 中的 PPT 視覺/結構描述V2 → V3不影響 V2 既有「6 種報告 vs 9 種報告」校正growth/vendor/bcg 仍未落地)
- **Affects**: `services/ppt_generator.py``routes/openclaw_bot_routes.py``Dockerfile``scripts/ppt_cleanup.sh`
- **Commit chain**: `38967ce``3b0b4b3``52c06f6``1c81866``b5a2b09``c7b7cee``92b8035``5a7012f`
## Context
2026-05-02 統帥檢視月報V2後指出五項視覺品質缺陷
1. 圖表醜python-pptx 原生柱狀圖無資料標註、無顏色分級)
2. 熱銷商品只 10 品(用戶要求 50 品)
3. 專案 RAG 情報內容太陽春(單一 textbox 顯示靜態節日字串)
4. 排版亂封面大面積暖墨黑、AI 頁深色 + 白字過於濃重)
5. 字體未對齊設計系統(中英混排撞 Courier New
並要求對齊「市場上專業日報/週報/月報」的標準McKinsey/BCG 等級顧問報告)。
第一輪重做後又抓出三類延伸需求:
- 同份 PPT 可秒回cache但模板升版時舊 cache 必須自動失效
- AI 分析內容要詳盡且專業,能直接幫銷售/行銷做決策參考
- 容器 CJK 字型必須真正能渲染中文
## Decision
### A. 視覺重做 — 暖紙風(取代暖墨黑)
**封面**`_BG_PAPER (#F3EEE2)` 米紙底取代 `_BG_DARK (#2A2520)`,焦糖橘左寬條 + 暖墨色標題。
**KPI 卡v2**value 大字含右下角 △% 徽章(綠↑紅↓),含 `delta_label="vs 上月"` / inverse 反轉模式(用於成本類指標)。
**字型分軌**:透過 lxml 直寫 `<a:latin>`+`<a:ea>` (`_set_run_fonts`),數字/英文走 Consolas點陣等寬感中文走 Microsoft JhengHei。`_insert_rpr_child` 依 ECMA-376 §21.1.2.3 順序插入子元素(避免 LibreOffice/Keynote 拒絕讀取)。
### B. 圖表升級 — matplotlib 暖色系(取代 python-pptx 原生)
| Helper | 用於 | 特色 |
|---|---|---|
| `_mpl_horiz_bar_png` | 月報品類橫條 | TOP3 焦糖橘 / 4-6 蜂蜜金 / 7+ 焦土,條右標 NT$X.X萬+佔比% |
| `_mpl_line_chart_png` | 日/週/月趨勢 | 本月實線+上月虛線+日均水平線+高低點標註N≤2 sparse 防呆 |
| `_mpl_pareto_chart_png` | 月報品類雙視圖 | 業績條80% 主力焦糖橘)+ 累計%曲線+80% 主力線 |
容器 CJK fallback`fonts-noto-cjk` 套件 ttc 檔在 matplotlib `font_manager.ttflist` 只認 `Noto Sans CJK JP` 變體,但 ttc 內漢字字型表共用,可正常渲染中文。`_mpl_setup` fallback 列表必須包含 `Noto Sans CJK JP`
### C. 模板版本快取template_version cache invalidation
```python
# services/ppt_generator.py
TEMPLATE_VERSIONS = {
'monthly': 'v3.1.3',
'daily': 'v3.0.2',
...
}
# routes/openclaw_bot_routes.py
def _normalize_ppt_parameters(parameters):
"""自動把 tpl_ver 注入 cache key"""
params['tpl_ver'] = get_template_version(report_type)
return json.dumps(params, sort_keys=True)
```
**Bump 規則**major 設計改版 +0.1(如 v3.0 → v3.1);補丁修正 +0.01v3.1.1 → v3.1.2。bump 即觸發舊快取自動 miss。
**緊急清空**`_invalidate_ppt_cache(report_type=None)` Python helper / `/cache flush` Telegram 指令admin only
**磁碟清理**`cleanup_expired_ppt_cache(days_old=7, dry_run=True)` — 安全預設 dry_run=True呼叫方明確傳 False 才實刪。launchd plist 排程每日 03:15 跑macOS 開發機)。
### D. AI prompt 升級到顧問深度
**月報 prompt 升級**`_ppt_ai_analysis`
- 角色BCG/麥肯錫策略顧問 + momo 行銷主管 + 品類採購(三合一)
- 必含「市場趨勢脈絡」段:當期檔期 + 2026 熱門賽道(永續美妝/母嬰高端/敏弱肌/銀髮保健等)+ 平台競爭(蝦皮/PChome/酷澎)
- 行動建議走 SMART 框架Specific/Measurable/Achievable/Relevant/Time-bound分本週/本月/下月三層
- 禁用「可能/也許/建議考慮」等模糊用詞
- 字數 900-1200max_tokens 2400
**AI 段落 parser**`_parse_ai_sections`):丟掉空 body 段(避免顯示「本段無內容」);上限 6→10 容納 SMART 9 段。
### E. 安全機制 — admin 白名單 + dry_run 預設
- **`OPENCLAW_ADMIN_USER_IDS` 環境變數**`/cache flush``/cache cleanup confirm` 限管理員執行;未設時退回 ALLOWED_USERS向後兼容 fail-closed
- **`_CURRENT_USER_ID_CTX` ContextVar**webhook 入口msg + callbacksethandle_cmd 讀取,避免改 30+ 處呼叫端簽名
- **cleanup days<1 強制乾跑**(防呆)
## Consequences
### Positive
1. **視覺對齊市場專業標準**:與 McKinsey/BCG 月度報告一致的暖紙風+圖表標註+帕雷托雙視圖
2. **模板升版零阻力**bump TEMPLATE_VERSIONS 即生效,無需手動清快取
3. **記憶體穩定**matplotlib helpers 全部 try/finally 包好,渲染失敗不洩漏 figure
4. **AI 內容可實戰**:每段含具體商品名+量化目標+期限BU 主管可直接做決策
5. **容器化部署**Dockerfile 加 `fonts-noto-cjk`CI/CD 自動帶字型
### Negative
1. **月報 cache miss 路徑變慢**cache miss 時連續查 current/prev_month/prev_year 三次12 SQL延遲 3×。命中後正常同份秒回
2. **PPT 檔變大**matplotlib PNG 取代原生 chart月報 130KB → 326KB含 3 張高品質圖)
3. **`fonts-noto-cjk-extra` 增加 ~100MB image 大小**:可瘦身但 trade-off 字型完整度
### Risks Mitigated
- **figure 洩漏 → OOM**try/finally 修復critic HIGH-1
- **靜默實刪災難**cleanup 預設 dry_run=Truecritic HIGH-2
- **群組成員誤觸破壞性指令**admin 白名單critic Medium-3
- **未來改讀模板 .pptx schema 違反**`_insert_rpr_child` 維護順序critic Medium-1
## Alternatives Considered
1. **保留 python-pptx 原生 chart**:拒絕 — 原生不支援資料標註、顏色分級無法做到 BCG 級觀感
2. **用 hash(ppt_generator.py 內容)[:8] 自動 cache key**:拒絕 — 改個 typo 也 invalidate 全部,過度敏感
3. **改 handle_cmd 簽名加 user_id**:拒絕 — 30+ 處呼叫端要動,風險大;用 ContextVar 更乾淨
## References
- Critic 完整審查報告:見 commit `38967ce` 之後的 critic agent run
- 實戰驗證:在 188 prod 容器內生成 monthly v3.1.3AI 內容 3 頁全 SMART 行動建議
- 原 ADR-014V2 PPT未廢止但視覺/結構/cache 部分由本 ADR 取代