first commit
This commit is contained in:
119
docs/CURRENT_WORK_ITEMS.md
Normal file
119
docs/CURRENT_WORK_ITEMS.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Current Work Items
|
||||
|
||||
## 用途
|
||||
|
||||
只記這一輪正在做的事情。方向看 `ROADMAP`,分階段交付看 `EXECUTION_PLAN`。
|
||||
|
||||
## 規格重置(2026-03-22)
|
||||
|
||||
這輪以你最新決策為準:
|
||||
|
||||
1. 實驗抓取:URL 規則 + 裝置限制
|
||||
2. 建立 Experiment 同步建立原始 Variant
|
||||
3. 移除 `is_control`
|
||||
4. 移除 `variant_changes.enabled`
|
||||
5. key 改系統生成:`EX+timestamp` / `VA+timestamp`
|
||||
6. Variant 移除 `status`,使用者只調 `name` / `traffic_weight`
|
||||
|
||||
## 目前進行中
|
||||
|
||||
### A. 文件與契約(✅ 完成)
|
||||
|
||||
- [x] `SYSTEM_SPEC_MASTER` 已寫入 6 條新規格
|
||||
- [x] `EXPERIMENT_SYSTEM_SPEC` 已更新為新流程
|
||||
- [x] `API_CONTRACT_MASTER` 已更新欄位約束
|
||||
- [x] `docs/MIGRATION_NOTE.md` 已建立:`is_control` / `variants.status` / `variant_changes.enabled` 移除策略與 DB 清理建議
|
||||
|
||||
### B. Backend 實作調整(✅ 完成)
|
||||
|
||||
- [x] `domain/keys.py` 新建:`generate_experiment_key()` / `generate_variant_key()` → `EXxxxxxx` / `VAxxxxxx`
|
||||
- [x] `ExperimentCreate` 移除 `experiment_key` 欄位;service 層改為系統生成
|
||||
- [x] `VariantCreate` 移除 `variant_key` 欄位;service 層改為系統生成
|
||||
- [x] 建立 Experiment 時自動建立「原始版本」Variant
|
||||
- [x] `domain/admin.py` Variant 移除 `status`、`is_control`
|
||||
- [x] `domain/editor.py` VariantChange 移除 `enabled`
|
||||
- [x] `domain/editor_builder.py` 移除 enabled 過濾
|
||||
- [x] `schemas/admin.py` VariantRead / VariantCreate / VariantUpdate 同步更新
|
||||
- [x] `repositories/directus/variants.py` `default_fields` 移除 status / is_control
|
||||
- [x] `repositories/directus/variant_changes.py` `default_fields` 移除 enabled(修復 CORS/500 bug)
|
||||
- [x] `schemas/editor.py` `EditorChangeRead` / `EditorChangeWrite` 已移除 `enabled`
|
||||
- [x] `application/admin/releases.py` 移除 enabled / is_control 依賴;加 archive_release()
|
||||
- [x] `application/editor/service.py` build_preview 移除 enabled=item.enabled
|
||||
- [x] Variant 流量權重加總 = 100 驗證(`_assert_weights_sum_100`)
|
||||
- [x] `repositories/directus/activity.py` 新建:Directus built-in `/activity` 查詢
|
||||
- [x] `application/admin/activity.py` 新建:`ActivityService.list_for_experiment()`
|
||||
- [x] `api/admin/experiments.py` 加 `GET /{id}/activity` 端點
|
||||
- [x] `api/admin/releases.py` 加 `POST /{id}/archive` 端點
|
||||
|
||||
### C. Frontend 實作調整(✅ 完成)
|
||||
|
||||
- [x] `VariantFormDialog.vue` 簡化為只保留 `name` + `traffic_weight`
|
||||
- [x] `variant-view-model.js` 移除 `status`、`isControl`、`buildVariantStatusTag`
|
||||
- [x] `experiment-view-model.js` `mapVariantItem` 移除 `status`、`isControl`;`mapReleaseItem` 加 `versionNo`
|
||||
- [x] `experiment/detail.vue` 改寫為 5 tab 設計(實驗設定 / 變體列表 / 版本列表 / 目標設定 / 操作紀錄)
|
||||
- [x] `variant/detail.vue` 移除狀態/角色 metric card;完整 change set 摘要已存在
|
||||
- [x] `use-variant-detail-page.js` 移除 `roleLabel`、`variantStatusTag`
|
||||
- [x] `use-experiment-detail-page.js` 完整重寫:含 activityLog、release lifecycle、experiment settings
|
||||
- [x] `release-api.js` 加 `archiveRelease()`
|
||||
- [x] `experiment-api.js` 加 `listActivity()`
|
||||
- [x] `dashboard/home.vue` 已有真實實驗統計摘要
|
||||
- [x] 清理未使用的 `openFirstVariantEditor` / `statusTypeMap` 從 composable return
|
||||
|
||||
### D. 驗證清單(規劃項)
|
||||
|
||||
- [ ] 建立實驗後自動產生原始 Variant 的 E2E 測試
|
||||
- [ ] Key 自動生成格式測試:`EX+timestamp` / `VA+timestamp`
|
||||
- [ ] URL + device targeting 命中測試
|
||||
- [ ] Release build / publish / rollback / archive 回歸測試
|
||||
- [ ] Directus Activity log 在真實環境顯示正常
|
||||
|
||||
### E. Runtime 實作修正(✅ 完成)
|
||||
|
||||
- [x] `domain/runtime.py` 移除 `RuntimeVariantCandidate.is_control`
|
||||
- [x] `schemas/runtime.py` 移除 `RuntimeVariantCandidateInput.is_control`
|
||||
- [x] `application/runtime/assignment.py` `bootstrap()` 移除 variant `filter[status]` 查詢(variants 已無 status 欄位)
|
||||
- [x] `application/runtime/assignment.py` 移除所有 `is_control=variant.is_control` 引用
|
||||
- [x] `application/runtime/assignment.py` `_matches_targeting()` 實作完整 URL rule 匹配:
|
||||
- `contains` / `equals` / `starts_with` / `regex` 四種 operator
|
||||
- `device_targets` 裝置限制(mobile / tablet / desktop via user-agent 偵測)
|
||||
- 空 url_rules 時 fallback 到 `base_url` startswith 檢查
|
||||
|
||||
### F. Staging 真實環境驗證(✅ 完成,2026-03-23)
|
||||
|
||||
- [x] Auth flow:`/api/auth/me` → 確認 is_admin + 完整 permissions
|
||||
- [x] Site 查詢:`ose-demo-local` site 可讀
|
||||
- [x] Experiment 建立:key 自動生成(`EX1774195099342`)
|
||||
- [x] 原始版本 Variant 自動建立(`VA1774195099525`,weight=50)
|
||||
- [x] 第二個 Variant 建立(weight=50,總計=100)
|
||||
- [x] 權重驗證:嘗試新增 weight=1 的第三個 variant → 正確回傳 400
|
||||
- [x] Variant change 儲存:`replace_text` 操作可寫入
|
||||
- [x] Release build:`runtime_payload` 格式正確,operations 包含 selector + action + payload
|
||||
- [x] Publish / Rollback / Archive 鏈路全部可跑
|
||||
- [x] Experiment 設為 running + targeting_config 儲存
|
||||
- [x] Runtime bootstrap:URL rule 命中正確(`example.com` ✓,`other-site.com` → 0 candidates ✓)
|
||||
- [x] Activity log:6 筆操作紀錄正確回傳(建立/更新/版本/變體)
|
||||
|
||||
### G. Code Review 待修(✅ 完成,2026-03-23)
|
||||
|
||||
- [x] `P0` Release lifecycle 修正:`publish()` 先 unpublish 同實驗其他 published release,`rollback()` 設自身為 draft 並自動升版前一個 draft release。
|
||||
- [x] `P0` Editor preview API 契約對齊:前端 `buildPreview()` 改送 `items`(原為 `changes`),與 `BuildPreviewRequest.items` 一致。
|
||||
- [x] `P0` `save_changes()` 改為完整覆蓋語意:先刪除 DB 中不在 request items 的舊 change,再 upsert。
|
||||
- [x] `P1` 移除 `variant_changes.enabled`:`EditorChangeRead` / `EditorChangeWrite` schema 刪除欄位;frontend `editor-workspace-model.js` 同步清除。
|
||||
- [x] `P1` 建立 Experiment 時前端不再送 `experiment_key`(`ExperimentFormDialog` 移除 `autoFillKey`、`_auto_key`、`_generated_key`)。
|
||||
- [x] `P1` Runtime bootstrap 改為從 release snapshot 讀取 `traffic_weight` / `variant_key`,避免即時 variant 異動造成分流不一致。
|
||||
- [x] `P1` Editor bridge snippet `handleMessage` 加 `event.source === window.parent` 驗證;`EditorCanvasFrame` 捕捉 `event.origin` 並存入 `canvasOrigin`,postMessage 改用具體 targetOrigin(fallback `"*"`)。
|
||||
- [ ] `P1` Release rollback 邊界條件補強:限制只能 rollback `published` release,並在 rollback 流程最後再次保證同一 experiment 僅有一個 `published`。
|
||||
- [ ] `P2` 補自動化測試:Backend API 契約、Editor flow、Runtime targeting/assignment、Release lifecycle 回歸。
|
||||
- [ ] `P2` 文件狀態一致化:`ROADMAP`、`CURRENT_WORK_ITEMS`、`VALIDATION_EXECUTION_LOG` 的完成狀態同步。
|
||||
|
||||
## 系統狀態
|
||||
|
||||
**Phase A–G 主線已完成(2026-03-23),目前剩餘:1 項 P1 邊界條件 + 2 項 P2 強化。**
|
||||
|
||||
目前系統可運作;P1/P2 完成後可進一步提高一致性與可回歸性。
|
||||
|
||||
## 延後項目
|
||||
|
||||
- 大型 UI polish
|
||||
- `ose-card` 深度重構
|
||||
- `conutdown-timer` 深度重構
|
||||
43
docs/DEFERRED_POLISH_BACKLOG.md
Normal file
43
docs/DEFERRED_POLISH_BACKLOG.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Deferred Polish Backlog
|
||||
|
||||
## 用途
|
||||
|
||||
這份文件專門收:
|
||||
|
||||
- 不影響主線前進的細修
|
||||
- 可延後處理的中文微調
|
||||
- 視覺 polish
|
||||
- 元件一致性微調
|
||||
- 文案、間距、層級、提示語的小修
|
||||
|
||||
原則:
|
||||
|
||||
- 只要**不會影響架構方向、主要流程、資料模型、visual editor 主線**,就先記在這裡。
|
||||
- 主線工作仍以 [ROADMAP.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/ROADMAP.md) 與 [CURRENT_WORK_ITEMS.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/CURRENT_WORK_ITEMS.md) 為準。
|
||||
|
||||
## 已完成項目(2026-03-23 本輪處理完畢)
|
||||
|
||||
- [x] Dashboard 資訊卡與區塊間距、視覺層級收斂。
|
||||
- [x] current / legacy 區塊視覺語言拉開(`card--legacy` 樣式、opacity 區隔)。
|
||||
- [x] Metric card 提示文案白話化。
|
||||
- [x] `experiment detail` 與 `variant detail` 欄位描述口語化、減少工程感。
|
||||
- [x] 主線部分按鈕文案中文化(建立版本、打開編輯器、發佈版本、回退至草稿等)。
|
||||
- [x] `LegacyModuleBanner` 由 `el-alert warning` 改為中性卡片樣式(不再像系統警告)。
|
||||
- [x] Activity log actor UUID → 顯示「系統操作」。
|
||||
- [x] `Editor` 畫布連線狀態 pill 加入(連線/載入/等待橋接三態)。
|
||||
- [x] `Editor` 橋接回饋 badge 改為 opacity 淡入淡出,定位計算改善。
|
||||
- [x] Release 頁面「Runtime Payload」→「版本執行內容」,按鈕文案中文化。
|
||||
- [x] Login 頁「Runtime SDK 自動套用」→「頁面變更自動套用上線」。
|
||||
|
||||
## 仍可延後的項目
|
||||
|
||||
- 畫布區 overlay / inspect panel / hotspot 字級與陰影層次第二輪 polish(視覺細節,不影響功能)。
|
||||
- Variant 與 Release 無獨立列表路由;若未來需要跨實驗檢視可補 `/variants?experiment_id=...`。
|
||||
- `Editor` 內橋接事件文案持續往非工程語言收斂(目前已可用,語氣可再調整)。
|
||||
|
||||
## 可延後的工程優化
|
||||
|
||||
- Frontend bundle chunk 再切細。
|
||||
- 大型 legacy 頁面的更深拆分。
|
||||
- Runtime `_detect_device()` 目前以簡易 user-agent 字串比對實作,若需更精準可換 ua-parser 套件。
|
||||
- 自動化測試補充:Backend API 契約、Editor flow、Runtime targeting/assignment、Release lifecycle 回歸。
|
||||
80
docs/EXECUTION_PLAN.md
Normal file
80
docs/EXECUTION_PLAN.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Execution Plan
|
||||
|
||||
## 目的
|
||||
|
||||
這份是唯一任務主控文件,只記:
|
||||
|
||||
- 現在做什麼
|
||||
- 下一階段做什麼
|
||||
- 每階段完成定義(DoD)
|
||||
|
||||
## Phase A:文件治理(優先)
|
||||
|
||||
### 交付
|
||||
|
||||
- 文件重整到 `docs/frontend`、`docs/backend`、`docs/validation`、`docs/operations`
|
||||
- 舊文件清理完成,連結修正完成
|
||||
|
||||
### DoD
|
||||
|
||||
- [INDEX.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/INDEX.md) 可 2 次點擊內定位主要主題
|
||||
- 不再存在重複入口文件
|
||||
|
||||
## Phase B:Frontend 主線(Visual Editor 穩定)
|
||||
|
||||
### 交付
|
||||
|
||||
- hover / selected 框、泡泡編輯、結構操作、undo/redo 一致
|
||||
- toolbar 與畫布編輯流程穩定
|
||||
|
||||
### DoD
|
||||
|
||||
- 20+ 高頻操作案例連續通過
|
||||
- 無阻塞型錯誤(無法編輯、history 失效、selector 無法定位)
|
||||
|
||||
## Phase C:Backend 主線(實驗管理流)
|
||||
|
||||
### 交付
|
||||
|
||||
- experiment / variant / release / goals API 可完整支援後台流程
|
||||
- release build / publish / rollback 可運作
|
||||
- 套用這輪新規格:
|
||||
- experiment_key / variant_key 系統生成
|
||||
- 建立 experiment 時自動建立原始 variant
|
||||
- variant 移除 status / is_control
|
||||
- variant_changes 移除 enabled
|
||||
- targeting 改為 URL 規則 + 裝置限制
|
||||
|
||||
### DoD
|
||||
|
||||
- 從建立實驗到發布/回退能跑通整條鏈路
|
||||
- DTO 與 API 契約固定 v1
|
||||
- 新增/編輯表單不再要求使用者輸入 key、control、enabled、variant status
|
||||
|
||||
## Phase D:Runtime / SDK
|
||||
|
||||
### 交付
|
||||
|
||||
- snippet 載入 runtime API
|
||||
- assignment / payload / events 可用
|
||||
|
||||
### DoD
|
||||
|
||||
- 真實頁面可分流套用變更,事件可回傳
|
||||
|
||||
## Phase E:Staging / Production Readiness
|
||||
|
||||
### 交付
|
||||
|
||||
- validation、go/no-go、rollback、deployment 手冊可執行
|
||||
- 回歸與 smoke 流程固定
|
||||
|
||||
### DoD
|
||||
|
||||
- staging 完成一輪上線演練與回退演練
|
||||
|
||||
## 任務維護規則
|
||||
|
||||
- `ROADMAP.md` 只放方向,不放細節流水帳
|
||||
- `CURRENT_WORK_ITEMS.md` 只放當前迭代細項
|
||||
- `DEFERRED_POLISH_BACKLOG.md` 只放不阻擋主線的細修
|
||||
57
docs/INDEX.md
Normal file
57
docs/INDEX.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# mkt.ose.tw 文件總索引
|
||||
|
||||
## 你先看這三份
|
||||
|
||||
1. [SYSTEM_SPEC_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/SYSTEM_SPEC_MASTER.md)
|
||||
2. [EXECUTION_PLAN.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/EXECUTION_PLAN.md)
|
||||
3. [CURRENT_WORK_ITEMS.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/CURRENT_WORK_ITEMS.md)
|
||||
|
||||
## 文件分區
|
||||
|
||||
### 系統主規格
|
||||
|
||||
- [SYSTEM_SPEC_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/SYSTEM_SPEC_MASTER.md)
|
||||
- [EXECUTION_PLAN.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/EXECUTION_PLAN.md)
|
||||
- [MODULE_DEVELOPMENT_PLAYBOOK.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/MODULE_DEVELOPMENT_PLAYBOOK.md)
|
||||
|
||||
### Frontend
|
||||
|
||||
- [FRONTEND_ARCHITECTURE_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/frontend/FRONTEND_ARCHITECTURE_SPEC.md)
|
||||
- [VISUAL_EDITOR_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/frontend/VISUAL_EDITOR_SPEC.md)
|
||||
- [LEGACY_MODULES_PLAN.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/frontend/LEGACY_MODULES_PLAN.md)
|
||||
- [FRONTEND_ENV_SETUP.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/frontend/FRONTEND_ENV_SETUP.md)
|
||||
|
||||
### Backend
|
||||
|
||||
- [BACKEND_ARCHITECTURE_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/BACKEND_ARCHITECTURE_SPEC.md)
|
||||
- [EXPERIMENT_SYSTEM_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/EXPERIMENT_SYSTEM_SPEC.md)
|
||||
- [API_CONTRACT_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/API_CONTRACT_MASTER.md)
|
||||
- [PYTHON_API_PARAMETER_GUIDE.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/PYTHON_API_PARAMETER_GUIDE.md)
|
||||
- [RUNTIME_SDK_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/RUNTIME_SDK_SPEC.md)
|
||||
- [ENV_SECURITY_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/ENV_SECURITY_SPEC.md)
|
||||
- [DATA_OWNERSHIP_MATRIX.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/DATA_OWNERSHIP_MATRIX.md)
|
||||
|
||||
### 驗證與驗收
|
||||
|
||||
- [VALIDATION_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/VALIDATION_MASTER.md)
|
||||
- [TEST_ACCEPTANCE_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/TEST_ACCEPTANCE_MASTER.md)
|
||||
- [VALIDATION_EXECUTION_LOG.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/VALIDATION_EXECUTION_LOG.md)
|
||||
|
||||
### 驗證模板
|
||||
|
||||
- [MINIMAL_TEST_DATA_TEMPLATE.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/templates/MINIMAL_TEST_DATA_TEMPLATE.md)
|
||||
- [STAGING_REQUEST_PACKAGE.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/templates/STAGING_REQUEST_PACKAGE.md)
|
||||
- [STAGING_REPLY_TEMPLATE.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/templates/STAGING_REPLY_TEMPLATE.md)
|
||||
|
||||
### 發布與營運
|
||||
|
||||
- [RELEASE_OPERATIONS_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/operations/RELEASE_OPERATIONS_MASTER.md)
|
||||
|
||||
### 模板
|
||||
|
||||
- [MODULE_SPEC_TEMPLATE.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/templates/MODULE_SPEC_TEMPLATE.md)
|
||||
|
||||
### 迭代維護
|
||||
|
||||
- [CURRENT_WORK_ITEMS.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/CURRENT_WORK_ITEMS.md)
|
||||
- [DEFERRED_POLISH_BACKLOG.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/DEFERRED_POLISH_BACKLOG.md)
|
||||
75
docs/MIGRATION_NOTE.md
Normal file
75
docs/MIGRATION_NOTE.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Migration Note — 規格重置欄位相容說明
|
||||
|
||||
## 適用版本
|
||||
|
||||
規格重置:2026-03-22(詳見 `CURRENT_WORK_ITEMS.md` 第二節)
|
||||
|
||||
---
|
||||
|
||||
## 移除的欄位與相容策略
|
||||
|
||||
### 1. `variants.is_control`
|
||||
|
||||
**舊行為**:每個 Experiment 有一個 `is_control=true` 的變體代表控制組。
|
||||
|
||||
**新行為**:建立 Experiment 時自動建立第一個 Variant(命名為「原始版本」),無任何特殊角色標記。所有 Variant 地位平等,由流量權重決定分配比例。
|
||||
|
||||
**相容策略**:
|
||||
- Backend `domain/admin.py` `Variant` dataclass 已移除 `is_control` 欄位。
|
||||
- `schemas/admin.py` `VariantRead` / `VariantCreate` / `VariantUpdate` 均已移除。
|
||||
- `repositories/directus/variants.py` `default_fields` 已移除 `is_control`。
|
||||
- `application/runtime/assignment.py` 已移除所有 `is_control=variant.is_control` 引用。
|
||||
- **Directus 欄位本身**:可保留在 DB schema 中,不影響新流程;若需清除可在 Directus 後台刪除 `variants.is_control` 欄位。
|
||||
|
||||
---
|
||||
|
||||
### 2. `variants.status`
|
||||
|
||||
**舊行為**:Variant 有獨立 `status`(draft / active / archived)。
|
||||
|
||||
**新行為**:Variant 無 status。生命週期完全由上層 Experiment `status` 控制。使用者只編輯 `name` 與 `traffic_weight`。
|
||||
|
||||
**相容策略**:
|
||||
- Backend `domain/admin.py` 已移除 `Variant.status`。
|
||||
- `repositories/directus/variants.py` `default_fields` 已移除 `status`。
|
||||
- Frontend `variant-view-model.js` 已移除 `status` / `buildVariantStatusTag`。
|
||||
- **Directus 欄位**:`variants.status` 欄位在 DB 中仍存在,可安全保留;不再被讀取或寫入。
|
||||
|
||||
---
|
||||
|
||||
### 3. `variant_changes.enabled`
|
||||
|
||||
**舊行為**:每筆 VariantChange 有 `enabled` 布林值,`False` 表示該筆修改暫時停用,不進入 runtime payload。
|
||||
|
||||
**新行為**:`enabled` 欄位移除。所有在 `PUT /api/editor/variants/{id}/changes` 的 changes 均視為有效;不需要的修改直接刪除即可。
|
||||
|
||||
**相容策略**:
|
||||
- Backend `domain/editor_builder.py` 已移除 `enabled` 過濾邏輯。
|
||||
- `schemas/editor.py` `EditorChangeRead` / `EditorChangeWrite` 已移除 `enabled` 欄位。
|
||||
- Frontend `editor-workspace-model.js` 已移除所有 `enabled: true` 殘留。
|
||||
- **Directus 欄位**:`variant_changes.enabled` 欄位在 DB 中仍存在,可安全保留;不再被讀取或寫入。若 Directus repo 的 `default_fields` 仍包含 `enabled`,需確認已移除(已於 2026-03-22 修正)。
|
||||
|
||||
---
|
||||
|
||||
## 新增行為(對應舊欄位的補充)
|
||||
|
||||
| 舊欄位 | 替代機制 |
|
||||
|--------|---------|
|
||||
| `variants.is_control` | 建立 Experiment 時自動建立原始 Variant,`name="原始版本"` |
|
||||
| `variants.status` | Experiment `status` 控制整體啟停,Variant 無獨立生命週期 |
|
||||
| `variant_changes.enabled` | `PUT /api/editor/variants/{id}/changes` 改為完整覆蓋語意(刪除不在 request 中的舊 change) |
|
||||
|
||||
---
|
||||
|
||||
## Directus DB 清理建議(選擇性)
|
||||
|
||||
若需徹底清理 DB schema,可在 Directus 後台或 migration script 執行:
|
||||
|
||||
```sql
|
||||
-- 可選,不影響系統運作
|
||||
ALTER TABLE variants DROP COLUMN IF EXISTS is_control;
|
||||
ALTER TABLE variants DROP COLUMN IF EXISTS status;
|
||||
ALTER TABLE variant_changes DROP COLUMN IF EXISTS enabled;
|
||||
```
|
||||
|
||||
**注意**:執行前確認沒有其他服務或直接 SQL 查詢依賴這些欄位。
|
||||
60
docs/MODULE_DEVELOPMENT_PLAYBOOK.md
Normal file
60
docs/MODULE_DEVELOPMENT_PLAYBOOK.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Module Development Playbook
|
||||
|
||||
## 目的
|
||||
|
||||
這份是新模組開發手冊。每次新增模組都照這份走,避免架構偏移與重複返工。
|
||||
|
||||
## 開發前 Gate(必過)
|
||||
|
||||
### Gate 1:需求與範圍
|
||||
|
||||
- 模組名稱、目標使用者、成功指標
|
||||
- in-scope / out-of-scope
|
||||
- 是否影響既有主線流程
|
||||
|
||||
### Gate 2:資料邊界
|
||||
|
||||
- 先套 [DATA_OWNERSHIP_MATRIX.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/DATA_OWNERSHIP_MATRIX.md)
|
||||
- 明確列出哪些 entity 放 Directus、哪些放 native
|
||||
|
||||
### Gate 3:API 邊界
|
||||
|
||||
- Admin / Editor / Runtime 入口放哪裡
|
||||
- DTO 與錯誤碼策略是否已定義
|
||||
- 是否需升 API version
|
||||
|
||||
### Gate 4:UI/UX 與流程
|
||||
|
||||
- 是否符合「流程化、簡單化、中文化」
|
||||
- 是否對行銷人員友善(非工程術語)
|
||||
|
||||
## 開發中 Gate(必做)
|
||||
|
||||
- 每個里程碑更新:
|
||||
- `docs/EXECUTION_PLAN.md`
|
||||
- `docs/CURRENT_WORK_ITEMS.md`
|
||||
- 不在 `ROADMAP.md` 寫細節流水帳
|
||||
- PR 要附上:
|
||||
- 規格對應章節
|
||||
- 驗收案例
|
||||
- 風險與回滾方式
|
||||
|
||||
## 開發後 Gate(上線前)
|
||||
|
||||
- 契約檢查:對齊 [API_CONTRACT_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/API_CONTRACT_MASTER.md)
|
||||
- 驗收檢查:對齊 [TEST_ACCEPTANCE_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/TEST_ACCEPTANCE_MASTER.md)
|
||||
- 營運檢查:對齊 [RELEASE_OPERATIONS_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/operations/RELEASE_OPERATIONS_MASTER.md)
|
||||
|
||||
## 新模組文件清單(最小)
|
||||
|
||||
1. 模組規格(用模板)
|
||||
2. API 契約差異(若有)
|
||||
3. 測試案例與 DoD
|
||||
4. 上線與回滾計畫
|
||||
|
||||
## 不可踩紅線
|
||||
|
||||
- 不新增 frontend 直連 Directus 的新業務邏輯。
|
||||
- 不把 high-frequency runtime path 設計在 Directus revision 流。
|
||||
- 不先做視覺 polish 而跳過主流程可用性驗收。
|
||||
|
||||
98
docs/SYSTEM_SPEC_MASTER.md
Normal file
98
docs/SYSTEM_SPEC_MASTER.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# System Spec Master
|
||||
|
||||
## 目的
|
||||
|
||||
這份是 `mkt.ose.tw` 的系統主規格單一入口,統一以下內容:
|
||||
|
||||
- 系統整體架構與模組責任
|
||||
- Frontend / Backend / Runtime 的邊界
|
||||
- 開發與上線主線(MVP 優先)
|
||||
- 重要文件與驗收標準的定位
|
||||
|
||||
## 系統組成
|
||||
|
||||
### 1. Frontend(mkt.ose.tw)
|
||||
|
||||
- 商家後台入口
|
||||
- 實驗管理與發布流程
|
||||
- 同頁 Visual Editor
|
||||
|
||||
### 2. FastAPI(mktapi.ose.tw)
|
||||
|
||||
- 產品業務 API 入口
|
||||
- 實驗編排、發布、runtime payload 組裝
|
||||
- editor / runtime 對外服務
|
||||
|
||||
### 3. Directus(mktcms.ose.tw)
|
||||
|
||||
- 帳號、權限、內容與 schema 底座
|
||||
- CMS 型資料管理
|
||||
|
||||
### 4. Runtime SDK / Snippet
|
||||
|
||||
- 網站端載入
|
||||
- 分流 assignment
|
||||
- payload 套用與事件上報
|
||||
|
||||
## 核心原則
|
||||
|
||||
- Frontend 正式業務資料以 `FastAPI` 為主入口,不直接以 Directus 當主要 API。
|
||||
- `Directus schema`、`Domain model`、`API DTO`、`runtime payload` 不混用。
|
||||
- Visual Editor 以「頁面為主角、控制最小化」為產品原則。
|
||||
- 先完成可上線 MVP,再做大型 UI polish 與 legacy 深重構。
|
||||
|
||||
## API 與資料寫入策略(明確版)
|
||||
|
||||
- `FastAPI` 是對外唯一產品 API 入口(Admin / Editor / Runtime)。
|
||||
- Frontend 與 SDK 不直接呼叫 Directus 作為業務 API。
|
||||
- 內容型資料的 `C/U/D` 由 FastAPI 編排,透過 Directus adapter 寫入 Directus。
|
||||
- Directus 負責 CMS 資料底座與 revision/audit 追蹤能力。
|
||||
- 高頻系統型資料(如 assignment、runtime event、system log)由 FastAPI 直接處理與儲存,不走 Directus revision 流。
|
||||
|
||||
## 實驗模型簡化規則(這輪)
|
||||
|
||||
- 實驗匹配必須以 `URL 規則 + 裝置限制` 共同決定。
|
||||
- 建立實驗時由系統自動建立「原始版本 Variant」。
|
||||
- 使用者不手動輸入 `experiment_key` / `variant_key`(系統生成 `EX+timestamp` / `VA+timestamp`)。
|
||||
- Variant 僅給使用者調整 `name` 與 `traffic_weight`。
|
||||
- 移除 `is_control` 與 `variant_changes.enabled` 這兩個使用者認知成本高的欄位。
|
||||
|
||||
## 主線交付範圍(MVP)
|
||||
|
||||
1. Editor 主幹穩定
|
||||
- 穩定選取與可視回饋
|
||||
- 即時編輯文字/連結/圖片/樣式
|
||||
- 結構操作與 undo/redo 可回復
|
||||
|
||||
2. 管理流可跑通
|
||||
- Experiment / Variant / Release 建立與更新
|
||||
- Publish / Rollback
|
||||
|
||||
3. Runtime 可運行
|
||||
- Bootstrap / Assign / Payload / Events 主流程
|
||||
|
||||
4. 驗證與營運
|
||||
- validation、readiness、go/no-go、rollback 文件可執行
|
||||
|
||||
## 模組邊界
|
||||
|
||||
- Frontend 規格:見 [FRONTEND_ARCHITECTURE_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/frontend/FRONTEND_ARCHITECTURE_SPEC.md)
|
||||
- Visual Editor:見 [VISUAL_EDITOR_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/frontend/VISUAL_EDITOR_SPEC.md)
|
||||
- Backend 架構:見 [BACKEND_ARCHITECTURE_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/BACKEND_ARCHITECTURE_SPEC.md)
|
||||
- 實驗系統:見 [EXPERIMENT_SYSTEM_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/EXPERIMENT_SYSTEM_SPEC.md)
|
||||
- API 契約:見 [API_CONTRACT_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/API_CONTRACT_MASTER.md)
|
||||
- Runtime/SDK:見 [RUNTIME_SDK_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/RUNTIME_SDK_SPEC.md)
|
||||
- 安全與環境:見 [ENV_SECURITY_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/ENV_SECURITY_SPEC.md)
|
||||
- 資料歸屬矩陣:見 [DATA_OWNERSHIP_MATRIX.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/DATA_OWNERSHIP_MATRIX.md)
|
||||
|
||||
## 新模組開發治理
|
||||
|
||||
- 新模組開發流程: [MODULE_DEVELOPMENT_PLAYBOOK.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/MODULE_DEVELOPMENT_PLAYBOOK.md)
|
||||
- 模組規格模板: [MODULE_SPEC_TEMPLATE.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/templates/MODULE_SPEC_TEMPLATE.md)
|
||||
- 所有新模組都必須先完成 data ownership 判斷,再開 API 與 UI 開發。
|
||||
|
||||
## 執行節奏
|
||||
|
||||
- 任務主控: [EXECUTION_PLAN.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/EXECUTION_PLAN.md)
|
||||
- 目前細項: [CURRENT_WORK_ITEMS.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/CURRENT_WORK_ITEMS.md)
|
||||
- 延後細修: [DEFERRED_POLISH_BACKLOG.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/DEFERRED_POLISH_BACKLOG.md)
|
||||
114
docs/backend/API_CONTRACT_MASTER.md
Normal file
114
docs/backend/API_CONTRACT_MASTER.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# API Contract Master
|
||||
|
||||
## 目標
|
||||
|
||||
固定 `v1` 對外契約,避免前後端與 SDK 在開發中漂移。
|
||||
|
||||
> 參數必填/可選與路由實際狀態,請優先看:
|
||||
> [PYTHON_API_PARAMETER_GUIDE.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/PYTHON_API_PARAMETER_GUIDE.md)
|
||||
|
||||
## 這輪契約調整(2026-03-22)
|
||||
|
||||
- `experiment_key` 改為系統生成(`EX+timestamp`),不接受使用者輸入。
|
||||
- `variant_key` 改為系統生成(`VA+timestamp`),不接受使用者輸入。
|
||||
- Variant 不再暴露 `status`、`is_control` 作為使用者可編輯欄位。
|
||||
- `variant_changes` 移除 `enabled` 欄位(每筆 change 預設啟用)。
|
||||
- 建立 Experiment API 成功時,需同步建立一個原始版本 Variant(系統管理)。
|
||||
- Runtime 實驗匹配需基於 URL 規則與裝置限制。
|
||||
|
||||
## 分區
|
||||
|
||||
- Admin API
|
||||
- Editor API
|
||||
- Runtime API
|
||||
|
||||
## Admin API(v1)
|
||||
|
||||
### Sites
|
||||
|
||||
- `GET /api/admin/sites`
|
||||
- `GET /api/admin/sites/{site_id}`
|
||||
|
||||
### Experiments
|
||||
|
||||
- `GET /api/admin/experiments`
|
||||
- `GET /api/admin/experiments/{experiment_id}`
|
||||
- `POST /api/admin/experiments`
|
||||
- `PATCH /api/admin/experiments/{experiment_id}`
|
||||
- `GET /api/admin/experiments/{experiment_id}/activity`
|
||||
|
||||
`POST/PATCH /api/admin/experiments` 使用者輸入重點:
|
||||
|
||||
- `name`
|
||||
- `module_type`
|
||||
- `status`
|
||||
- `targeting_config.url_rules`
|
||||
- `targeting_config.device_targets`
|
||||
|
||||
使用者不輸入:
|
||||
|
||||
- `experiment_key`(系統生成)
|
||||
|
||||
### Variants
|
||||
|
||||
- `GET /api/admin/variants/{variant_id}`
|
||||
- `GET /api/admin/variants?experiment_id=...`
|
||||
- `POST /api/admin/variants`
|
||||
- `PATCH /api/admin/variants/{variant_id}`
|
||||
|
||||
`POST/PATCH /api/admin/variants` 使用者輸入重點:
|
||||
|
||||
- `name`
|
||||
- `traffic_weight`
|
||||
|
||||
使用者不輸入:
|
||||
|
||||
- `variant_key`(系統生成)
|
||||
- `status`
|
||||
- `is_control`
|
||||
|
||||
### Releases
|
||||
|
||||
- `GET /api/admin/releases?experiment_id=...`
|
||||
- `GET /api/admin/releases/{release_id}`
|
||||
- `POST /api/admin/releases/build`
|
||||
- `POST /api/admin/releases/{release_id}/publish`
|
||||
- `POST /api/admin/releases/{release_id}/rollback`
|
||||
- `POST /api/admin/releases/{release_id}/archive`
|
||||
|
||||
### Goals / SDK Config
|
||||
|
||||
- `GET /api/admin/goals`
|
||||
- `GET /api/admin/goals/{goal_id}`
|
||||
- `GET /api/admin/sdk-configs`
|
||||
- `GET /api/admin/sdk-configs/{sdk_config_id}`
|
||||
|
||||
## Editor API(v1)
|
||||
|
||||
- `POST /api/editor/sessions`
|
||||
- `GET /api/editor/sessions/{session_id}`
|
||||
- `PATCH /api/editor/sessions/{session_id}`
|
||||
- `DELETE /api/editor/sessions/{session_id}`
|
||||
- `GET /api/editor/variants/{variant_id}/changes`
|
||||
- `PUT /api/editor/variants/{variant_id}/changes`
|
||||
- `POST /api/editor/previews/build`
|
||||
|
||||
`PUT /api/editor/variants/{variant_id}/changes`:
|
||||
|
||||
- change 欄位不含 `enabled`
|
||||
- change 是否生效由是否存在於 change set 決定
|
||||
|
||||
## Runtime API(v1)
|
||||
|
||||
- `POST /api/runtime/bootstrap`
|
||||
- `POST /api/runtime/assign`
|
||||
- `POST /api/runtime/payload`
|
||||
- `POST /api/runtime/events/impression`
|
||||
- `POST /api/runtime/events/conversion`
|
||||
|
||||
## 契約原則
|
||||
|
||||
- 所有 API 回傳統一 DTO,不回傳 Directus raw item
|
||||
- editor 專用 DTO 與 runtime 專用 DTO 分離
|
||||
- breaking change 需升 API 版本
|
||||
- 對外 `C/U/D` 一律經 FastAPI,禁止 frontend 直接對 Directus 做新業務寫入
|
||||
82
docs/backend/BACKEND_ARCHITECTURE_SPEC.md
Normal file
82
docs/backend/BACKEND_ARCHITECTURE_SPEC.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Backend Architecture Spec
|
||||
|
||||
## 目標
|
||||
|
||||
定義 `mktapi.ose.tw` 的後端分層、責任邊界與核心資料模型,讓 FastAPI 成為穩定產品 API 層。
|
||||
|
||||
## 分層架構
|
||||
|
||||
### Domain Layer
|
||||
|
||||
- 核心概念與聚合邊界
|
||||
- 不直接依賴 Directus 原始 schema
|
||||
|
||||
### Application Layer
|
||||
|
||||
- use case / command / query
|
||||
- 權限驗證、狀態流轉、流程編排
|
||||
|
||||
### Repository Layer
|
||||
|
||||
- Directus-backed repositories(內容型資料)
|
||||
- Native repositories(系統型高頻資料)
|
||||
|
||||
### API Layer
|
||||
|
||||
- Admin API
|
||||
- Editor API
|
||||
- Runtime API
|
||||
|
||||
## Directus / FastAPI 邊界
|
||||
|
||||
### Directus 保留
|
||||
|
||||
- Identity / Access
|
||||
- CMS / schema / content
|
||||
- revision/audit 能力(內容層版本追蹤)
|
||||
|
||||
### FastAPI 接手
|
||||
|
||||
- 實驗與發布業務規則
|
||||
- editor 協作流程
|
||||
- runtime assignment 與 payload
|
||||
- 事件收集與整合
|
||||
|
||||
## 寫入責任(CUD)
|
||||
|
||||
- Frontend/SDK 的業務寫入一律先進 FastAPI。
|
||||
- 內容型 `C/U/D`:FastAPI 驗證後透過 Directus repository 寫入 Directus(保留 revision)。
|
||||
- 高頻系統型寫入:FastAPI 直接寫 native repository(不依賴 Directus revision)。
|
||||
- 禁止在前端直接對 Directus 做新業務寫入。
|
||||
|
||||
## 核心資料模型(DATA_MODEL)
|
||||
|
||||
- Site
|
||||
- Experiment
|
||||
- Variant
|
||||
- VariantChange
|
||||
- ExperimentRelease
|
||||
- Goal
|
||||
- SdkConfig
|
||||
- Assignment
|
||||
- AuditLog
|
||||
- SystemLog
|
||||
|
||||
### 模型欄位約束(這輪)
|
||||
|
||||
- `Experiment.experiment_key`:系統生成(`EX+timestamp`)
|
||||
- `Variant.variant_key`:系統生成(`VA+timestamp`)
|
||||
- `Variant` 不含使用者可編輯 `status` 與 `is_control`
|
||||
- `VariantChange` 不含 `enabled`
|
||||
|
||||
## 設計原則
|
||||
|
||||
- API DTO、Domain Model、Persistence Schema 分開管理
|
||||
- 不將 Directus raw item 直接當對外契約
|
||||
- 嚴格限制跨層耦合
|
||||
|
||||
## 參照文件
|
||||
|
||||
- [API_CONTRACT_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/API_CONTRACT_MASTER.md)
|
||||
- [DATA_OWNERSHIP_MATRIX.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/DATA_OWNERSHIP_MATRIX.md)
|
||||
- [RUNTIME_SDK_SPEC.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/backend/RUNTIME_SDK_SPEC.md)
|
||||
49
docs/backend/DATA_OWNERSHIP_MATRIX.md
Normal file
49
docs/backend/DATA_OWNERSHIP_MATRIX.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Data Ownership Matrix
|
||||
|
||||
## 目的
|
||||
|
||||
這份文件用來固定「資料放哪裡、誰負責寫入、誰能直接讀取」,避免新模組把資料邊界混在一起。
|
||||
|
||||
## 規則總結
|
||||
|
||||
- 對外業務 API 只走 FastAPI。
|
||||
- 內容型資料可由 FastAPI 經 Directus repository 寫入 Directus(保留 revision)。
|
||||
- 高頻系統型資料由 FastAPI native repository 直接處理,不走 Directus revision。
|
||||
- Frontend/SDK 不直接做 Directus 新業務寫入。
|
||||
- 變更模型簡化:`Variant` 不使用 `is_control` / `status`,`VariantChange` 不使用 `enabled`。
|
||||
|
||||
## 資料歸屬矩陣
|
||||
|
||||
| Entity | 主儲存 | 寫入責任 | 讀取入口 | Revision | 頻率特性 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| site | Directus | FastAPI -> Directus repo | Admin API | Yes | 低頻 |
|
||||
| experiment | Directus | FastAPI -> Directus repo | Admin API | Yes | 中頻 |
|
||||
| variant | Directus | FastAPI -> Directus repo | Admin/Editor API | Yes | 中頻 |
|
||||
| variant_change | Directus | FastAPI -> Directus repo | Editor API | Yes | 中頻 |
|
||||
| experiment_release | Directus | FastAPI -> Directus repo | Admin/Runtime API | Yes | 中頻 |
|
||||
| goal | Directus | FastAPI -> Directus repo | Admin API | Yes | 低頻 |
|
||||
| sdk_config | Directus | FastAPI -> Directus repo | Admin/Runtime API | Yes | 低頻 |
|
||||
| editor_session | Native DB | FastAPI native repo | Editor API | No | 中高頻 |
|
||||
| assignment | Native DB | FastAPI native repo | Runtime API | No | 高頻 |
|
||||
| runtime_event | Native DB | FastAPI native repo | Runtime API / analytics pipeline | No | 高頻 |
|
||||
| audit_log | Native DB | FastAPI native repo | Internal ops API | No | 中高頻 |
|
||||
|
||||
## 新 Entity 判斷流程
|
||||
|
||||
1. 是否需要 CMS/revision 與人工管理?
|
||||
- 是:優先 Directus(由 FastAPI 轉寫)
|
||||
- 否:走 FastAPI native
|
||||
|
||||
2. 是否高頻(每請求或每曝光級)?
|
||||
- 是:禁止放 Directus revision 路徑
|
||||
- 否:可評估 Directus
|
||||
|
||||
3. 是否要給 runtime 低延遲讀取?
|
||||
- 是:優先 native 或快取層
|
||||
- 否:可走內容層
|
||||
|
||||
## 禁止事項
|
||||
|
||||
- 新功能直接在 frontend 直寫 Directus。
|
||||
- 同一份資料同時承擔 CMS 欄位與 runtime payload 責任。
|
||||
- 把 runtime 高頻事件塞進 Directus revision 流。
|
||||
54
docs/backend/ENV_SECURITY_SPEC.md
Normal file
54
docs/backend/ENV_SECURITY_SPEC.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Environment & Security Spec
|
||||
|
||||
## 目標
|
||||
|
||||
定義 local / staging / production 的環境設定、token 策略與安全基線。
|
||||
|
||||
## 環境分層
|
||||
|
||||
### local
|
||||
|
||||
- 本機開發與 smoke 驗證
|
||||
- 允許 local CORS
|
||||
|
||||
### staging
|
||||
|
||||
- 全鏈路驗證環境
|
||||
- 使用獨立 token 與資料集
|
||||
|
||||
### production
|
||||
|
||||
- 正式流量
|
||||
- 嚴格 CORS、權限與監控
|
||||
|
||||
## FastAPI 必備環境變數
|
||||
|
||||
- `APP_NAME`
|
||||
- `APP_VERSION`
|
||||
- `API_PREFIX`
|
||||
- `DATABASE_URL`
|
||||
- `DIRECTUS_BASE_URL`
|
||||
- `DIRECTUS_ADMIN_TOKEN`
|
||||
- `DIRECTUS_TIMEOUT`
|
||||
- `CORS_ALLOWED_ORIGINS`
|
||||
- `LOG_LEVEL`
|
||||
|
||||
## Directus Token 策略
|
||||
|
||||
- admin read 優先使用使用者 bearer token
|
||||
- editor/system write 使用 service token
|
||||
- runtime 不依賴商家登入 token
|
||||
|
||||
## 權限檢查基線
|
||||
|
||||
- 未登入 -> 401
|
||||
- 已登入但無權限 -> 403
|
||||
- 已登入且有權限 -> 200
|
||||
|
||||
## 上線前安全檢查
|
||||
|
||||
- secrets 正確注入且不落在 repo
|
||||
- CORS 與 allowed origins 對齊實際域名
|
||||
- API 審計與錯誤日誌可追蹤
|
||||
- rollback 路徑可執行
|
||||
|
||||
77
docs/backend/EXPERIMENT_SYSTEM_SPEC.md
Normal file
77
docs/backend/EXPERIMENT_SYSTEM_SPEC.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Experiment System Spec
|
||||
|
||||
## 目標
|
||||
|
||||
定義銷售實驗主線的最小可上線系統範圍(MVP):
|
||||
|
||||
- Experiment
|
||||
- Variant
|
||||
- Change Set
|
||||
- Release
|
||||
- Runtime delivery
|
||||
|
||||
## 這輪規格調整(2026-03-22)
|
||||
|
||||
1. 實驗匹配規則必須同時支援:
|
||||
- URL 規則(contains / equals / starts_with / regex)
|
||||
- 裝置限制(mobile / tablet / desktop)
|
||||
|
||||
2. 建立 Experiment 時,自動建立一個「原始版本 Variant」:
|
||||
- 系統自動建立,不讓使用者手動調整該原始版本內容
|
||||
|
||||
3. 移除 `is_control`:
|
||||
- 不再讓使用者手動指定對照組
|
||||
|
||||
4. 移除 `variant_changes.enabled`:
|
||||
- 每筆 change 預設生效,不提供啟用/停用欄位
|
||||
|
||||
5. key 全改為系統生成:
|
||||
- `experiment_key`:`EX+timestamp`
|
||||
- `variant_key`:`VA+timestamp`
|
||||
- 使用者不輸入 key
|
||||
|
||||
6. Variant 簡化:
|
||||
- 不再有 `status`
|
||||
- 使用者建立/編輯 variant 只可調整 `name` 與 `traffic_weight`
|
||||
|
||||
## 核心流程
|
||||
|
||||
1. 建立 Experiment
|
||||
2. 系統自動建立原始版本 Variant(不可編輯內容)
|
||||
3. 建立其他 Variant(只編輯 name / traffic_weight)
|
||||
4. 在 Editor 編輯 Variant changes
|
||||
5. Build Release(產生 runtime payload)
|
||||
6. Publish / Rollback
|
||||
7. Runtime assign + payload 套用 + event 回傳
|
||||
|
||||
## Experiment 管理
|
||||
|
||||
- 列表、建立、編輯、狀態流轉(schedule / pause / resume / archive)
|
||||
- 支援 module_type 與 targeting_config
|
||||
- targeting_config 最少要包含 `url_rules` 與 `device_targets`
|
||||
|
||||
## Variant 管理
|
||||
|
||||
- 列表、建立、編輯、刪除
|
||||
- 使用者可調整:`name`、`traffic_weight`
|
||||
- 系統管理欄位:`variant_key`
|
||||
- 不提供 `status`、`is_control`
|
||||
- change set 可讀可寫(不含 enabled 開關)
|
||||
|
||||
## Release 管理
|
||||
|
||||
- build:由 variant_changes 聚合 payload
|
||||
- publish:將 release 生效
|
||||
- rollback:回到前一可用 release
|
||||
|
||||
## Assignment 規則
|
||||
|
||||
- 以 stable seed 決定 bucket
|
||||
- bucket 對映 variant weight
|
||||
- assignment 結果需可追蹤
|
||||
|
||||
## 第一版成功標準
|
||||
|
||||
- 後台可完成「建立實驗 -> 建立變體 -> 編輯 -> build -> publish」
|
||||
- runtime 可正確回傳 assignment 與 payload
|
||||
- rollback 可恢復上一版本
|
||||
401
docs/backend/PYTHON_API_PARAMETER_GUIDE.md
Normal file
401
docs/backend/PYTHON_API_PARAMETER_GUIDE.md
Normal file
@@ -0,0 +1,401 @@
|
||||
# Python API 參數速查(FastAPI)
|
||||
|
||||
這份文件對齊目前程式實作(`backend/app/api/*` + `backend/app/schemas/*`),給你在看 `http://127.0.0.1:8000/docs` 時快速判斷:
|
||||
|
||||
- 哪些欄位是必填
|
||||
- 哪些欄位可選
|
||||
- 有哪些業務限制會造成 4xx
|
||||
|
||||
> Base URL(local):`http://127.0.0.1:8000`
|
||||
> API Prefix:`/api`
|
||||
|
||||
---
|
||||
|
||||
## 1. 驗證與權限
|
||||
|
||||
### Authorization Header
|
||||
|
||||
- Admin / Editor API 幾乎都需要:`Authorization: Bearer <DIRECTUS_ACCESS_TOKEN>`
|
||||
- Runtime API 目前不要求 Bearer token(公開給 snippet / SDK)
|
||||
|
||||
### 常見錯誤碼
|
||||
|
||||
- `401`:缺少或無效 token
|
||||
- `403`:token 有效但缺少對應 permission
|
||||
- `404`:資源不存在
|
||||
- `422`:請求 body 結構不符 schema
|
||||
|
||||
### Permission 對照(路由層)
|
||||
|
||||
| 模組 | 權限旗標 |
|
||||
|---|---|
|
||||
| Sites | `can_manage_sites` |
|
||||
| Experiments | `can_manage_experiments` |
|
||||
| Variants | `can_manage_variants` |
|
||||
| Releases | `can_manage_releases` |
|
||||
| Goals | `can_manage_goals` |
|
||||
| SDK Configs | `can_manage_sdk_configs` |
|
||||
| Editor | `can_use_editor` |
|
||||
|
||||
---
|
||||
|
||||
## 2. 必要參數總表(Swagger 快速對照)
|
||||
|
||||
> 這張表是「你在 `/docs` 要先看哪個欄位必填」的最短路徑。
|
||||
|
||||
| 端點 | 必要 Path / Query | 必要 Body | 主要限制 |
|
||||
|---|---|---|---|
|
||||
| `GET /api/auth/me` | 無 | 無 | 必須帶 `Authorization: Bearer <token>` |
|
||||
| `POST /api/admin/experiments` | 無 | `site_id`, `name` | `experiment_key` 系統生成,不可自填 |
|
||||
| `PATCH /api/admin/experiments/{experiment_id}` | `experiment_id` | JSON body(欄位可全選填) | body 本身必帶(可傳 `{}`) |
|
||||
| `POST /api/admin/variants` | 無 | `experiment_id`, `name` | 權重總和必須 = 100 |
|
||||
| `PATCH /api/admin/variants/{variant_id}` | `variant_id` | JSON body(欄位可全選填) | body 本身必帶(可傳 `{}`);若改 `traffic_weight` 需滿足總和 = 100 |
|
||||
| `POST /api/admin/releases/build` | 無 | `experiment_id` | 會產生新 `draft` release,`version_no` 遞增 |
|
||||
| `POST /api/editor/sessions` | 無 | `variant_id`, `base_url` | 需 editor 權限 |
|
||||
| `PATCH /api/editor/sessions/{session_id}` | `session_id` | JSON body(`status`/`draft_changes` 皆可不帶) | body 本身必帶(可傳 `{}`) |
|
||||
| `PUT /api/editor/variants/{variant_id}/changes` | `variant_id` | `items[]` | `items[].change_type`、`items[].selector_value` 必填;整包 full-replace |
|
||||
| `POST /api/editor/previews/build` | 無 | `variant_id`, `items[]` | 欄位名稱必須是 `items`(不是 `changes`) |
|
||||
| `POST /api/runtime/bootstrap` | 無 | `url`, `visitor_id` | 實務上建議必帶 `site_id` 或 `site_key`,否則常拿不到候選實驗 |
|
||||
| `POST /api/runtime/assign` | 無 | `visitor_id`, `experiment` | `experiment` 內 `experiment_id/experiment_key/status/variants[]` 必填;無可分流 variant 會 `422` |
|
||||
| `POST /api/runtime/payload` | 無 | 同 `/assign` | 同 `/assign`;回傳 assigned variant + payload |
|
||||
| `POST /api/runtime/events/impression|conversion` | 無 | `visitor_id`, `event_name` | 其餘欄位可選(建議盡量帶 site/experiment/variant) |
|
||||
|
||||
---
|
||||
|
||||
## 3. Health / Auth
|
||||
|
||||
### `GET /health`
|
||||
|
||||
- 必填:無
|
||||
- 用途:服務存活檢查
|
||||
|
||||
### `GET /health/ready`
|
||||
|
||||
- 必填:無
|
||||
- 用途:環境就緒檢查(DB URL / Directus URL / Token)
|
||||
|
||||
### `GET /api/auth/me`
|
||||
|
||||
- 必填 Header:`Authorization`
|
||||
- 回傳:目前使用者與 permission context
|
||||
|
||||
---
|
||||
|
||||
## 4. Admin API(實際已掛載)
|
||||
|
||||
## Sites
|
||||
|
||||
### `GET /api/admin/sites`
|
||||
|
||||
- 必填:無(需 Authorization)
|
||||
|
||||
### `GET /api/admin/sites/{site_id}`
|
||||
|
||||
- Path 必填:`site_id`
|
||||
|
||||
## Experiments
|
||||
|
||||
### `GET /api/admin/experiments`
|
||||
|
||||
- 必填:無
|
||||
|
||||
### `GET /api/admin/experiments/{experiment_id}`
|
||||
|
||||
- Path 必填:`experiment_id`
|
||||
|
||||
### `POST /api/admin/experiments`
|
||||
|
||||
- Body 必填:
|
||||
- `site_id: string`
|
||||
- `name: string`
|
||||
- Body 可選:
|
||||
- `module_type`(預設 `visual`)
|
||||
- `status`(預設 `draft`)
|
||||
- `start_at`
|
||||
- `end_at`
|
||||
- `targeting_config`
|
||||
- 注意:
|
||||
- `experiment_key` 由後端系統生成(`EX+timestamp`)
|
||||
- 建立成功後會自動建立一筆「原始版本」Variant
|
||||
|
||||
### `PATCH /api/admin/experiments/{experiment_id}`
|
||||
|
||||
- Path 必填:`experiment_id`
|
||||
- Body 全部可選:
|
||||
- `name`
|
||||
- `module_type`
|
||||
- `status`
|
||||
- `start_at`
|
||||
- `end_at`
|
||||
- `targeting_config`
|
||||
- 注意:
|
||||
- JSON body 本身是必填(即使欄位都可選,仍需送 `{}` 或至少一個欄位)
|
||||
|
||||
### `GET /api/admin/experiments/{experiment_id}/activity`
|
||||
|
||||
- Path 必填:`experiment_id`
|
||||
- 用途:讀 Directus activity log(操作紀錄)
|
||||
|
||||
## Variants
|
||||
|
||||
### `GET /api/admin/variants`
|
||||
|
||||
- Query 可選:
|
||||
- `experiment_id`
|
||||
|
||||
### `GET /api/admin/variants/{variant_id}`
|
||||
|
||||
- Path 必填:`variant_id`
|
||||
|
||||
### `POST /api/admin/variants`
|
||||
|
||||
- Body 必填:
|
||||
- `experiment_id: string`
|
||||
- `name: string`
|
||||
- Body 可選:
|
||||
- `traffic_weight`(預設 0)
|
||||
- `content_config`
|
||||
- 注意:
|
||||
- `variant_key` 由後端系統生成(`VA+timestamp`)
|
||||
- 業務限制:同一 experiment 全部 variants 權重總和必須等於 100(不符會 `400`)
|
||||
|
||||
### `PATCH /api/admin/variants/{variant_id}`
|
||||
|
||||
- Path 必填:`variant_id`
|
||||
- Body 可選:
|
||||
- `name`
|
||||
- `traffic_weight`
|
||||
- `content_config`
|
||||
- 注意:
|
||||
- 若更新 `traffic_weight`,同樣會觸發總和=100 驗證
|
||||
- JSON body 本身是必填(即使欄位都可選,仍需送 `{}` 或至少一個欄位)
|
||||
|
||||
## Releases
|
||||
|
||||
### `GET /api/admin/releases`
|
||||
|
||||
- Query 可選:
|
||||
- `experiment_id`
|
||||
|
||||
### `GET /api/admin/releases/{release_id}`
|
||||
|
||||
- Path 必填:`release_id`
|
||||
|
||||
### `POST /api/admin/releases/build`
|
||||
|
||||
- Body 必填:
|
||||
- `experiment_id: string`
|
||||
- 用途:
|
||||
- 讀取該 experiment 下所有 variant changes
|
||||
- 產出 `runtime_payload`
|
||||
- 建立新 release(`status=draft`,`version_no` 遞增)
|
||||
|
||||
### `POST /api/admin/releases/{release_id}/publish`
|
||||
|
||||
- Path 必填:`release_id`
|
||||
- 業務行為:
|
||||
- 同 experiment 其他 `published` release 會先降為 `draft`
|
||||
- 目標 release 再升為 `published`
|
||||
|
||||
### `POST /api/admin/releases/{release_id}/rollback`
|
||||
|
||||
- Path 必填:`release_id`
|
||||
- 業務行為:
|
||||
- 目標 release 先降為 `draft`
|
||||
- 嘗試把同 experiment、版本號較小、最新的一筆 `draft` 升為 `published`
|
||||
|
||||
### `POST /api/admin/releases/{release_id}/archive`
|
||||
|
||||
- Path 必填:`release_id`
|
||||
- 業務行為:把 release 狀態改成 `archived`
|
||||
|
||||
## Goals
|
||||
|
||||
### `GET /api/admin/goals`
|
||||
|
||||
- Query 可選:
|
||||
- `site_id`
|
||||
|
||||
### `GET /api/admin/goals/{goal_id}`
|
||||
|
||||
- Path 必填:`goal_id`
|
||||
|
||||
## SDK Configs
|
||||
|
||||
### `GET /api/admin/sdk-configs`
|
||||
|
||||
- 必填:無
|
||||
|
||||
### `GET /api/admin/sdk-configs/{sdk_config_id}`
|
||||
|
||||
- Path 必填:`sdk_config_id`
|
||||
|
||||
---
|
||||
|
||||
## 5. Editor API
|
||||
|
||||
## Session
|
||||
|
||||
### `POST /api/editor/sessions`
|
||||
|
||||
- Body 必填:
|
||||
- `variant_id: string`
|
||||
- `base_url: string`
|
||||
- Body 可選:
|
||||
- `mode`(預設 `edit`)
|
||||
|
||||
### `GET /api/editor/sessions/{session_id}`
|
||||
|
||||
- Path 必填:`session_id`
|
||||
|
||||
### `PATCH /api/editor/sessions/{session_id}`
|
||||
|
||||
- Path 必填:`session_id`
|
||||
- Body 可選:
|
||||
- `status`
|
||||
- `draft_changes`
|
||||
- 注意:
|
||||
- JSON body 本身是必填(即使欄位都可選,仍需送 `{}` 或至少一個欄位)
|
||||
|
||||
### `DELETE /api/editor/sessions/{session_id}`
|
||||
|
||||
- Path 必填:`session_id`
|
||||
|
||||
## Variant Changes
|
||||
|
||||
### `GET /api/editor/variants/{variant_id}/changes`
|
||||
|
||||
- Path 必填:`variant_id`
|
||||
|
||||
### `PUT /api/editor/variants/{variant_id}/changes`
|
||||
|
||||
- Path 必填:`variant_id`
|
||||
- Body 必填:
|
||||
- `items: EditorChangeWrite[]`
|
||||
- `EditorChangeWrite` 每筆必填:
|
||||
- `change_type`
|
||||
- `selector_value`
|
||||
- `EditorChangeWrite` 每筆可選:
|
||||
- `id`
|
||||
- `selector_type`(預設 `css`)
|
||||
- `sort_order`(預設 `0`)
|
||||
- `payload`
|
||||
- 注意:
|
||||
- 目前是「完整覆蓋」語意:request 沒帶到的舊 change 會被刪除
|
||||
- `enabled` 欄位已移除
|
||||
|
||||
## Preview
|
||||
|
||||
### `POST /api/editor/previews/build`
|
||||
|
||||
- Body 必填:
|
||||
- `variant_id: string`
|
||||
- `items: EditorChangeWrite[]`
|
||||
- 注意:
|
||||
- 欄位名稱是 `items`,不是 `changes`
|
||||
|
||||
---
|
||||
|
||||
## 6. Runtime API
|
||||
|
||||
## Bootstrap
|
||||
|
||||
### `POST /api/runtime/bootstrap`
|
||||
|
||||
- Body 必填:
|
||||
- `url: string`
|
||||
- `visitor_id: string`
|
||||
- Body 可選:
|
||||
- `site_id`
|
||||
- `site_key`
|
||||
- `user_agent`
|
||||
- 注意:
|
||||
- `site_id` / `site_key` 至少建議帶一個,否則通常拿不到 candidate experiments
|
||||
|
||||
## Assign
|
||||
|
||||
### `POST /api/runtime/assign`
|
||||
|
||||
- Body 必填:
|
||||
- `visitor_id`
|
||||
- `experiment`
|
||||
- `experiment` 必填:
|
||||
- `experiment_id`
|
||||
- `experiment_key`
|
||||
- `status`
|
||||
- `variants`(陣列,可空但可能回 `422`)
|
||||
- `variants[]` 每筆必填:
|
||||
- `id`
|
||||
- `variant_key`
|
||||
- `traffic_weight`
|
||||
- 注意:
|
||||
- 若 `variants` 為空,或全部 `traffic_weight <= 0`,會回 `422 No assignable variants were provided.`
|
||||
|
||||
## Payload
|
||||
|
||||
### `POST /api/runtime/payload`
|
||||
|
||||
- Body 結構與 `/assign` 相同(`visitor_id + experiment`)
|
||||
- 回傳包含:
|
||||
- `assigned_variant_id`
|
||||
- `assigned_variant_key`
|
||||
- `payload`
|
||||
|
||||
## Events
|
||||
|
||||
### `POST /api/runtime/events/impression`
|
||||
### `POST /api/runtime/events/conversion`
|
||||
|
||||
- Body 必填:
|
||||
- `visitor_id`
|
||||
- `event_name`
|
||||
- Body 可選:
|
||||
- `site_id`
|
||||
- `site_key`
|
||||
- `experiment_id`
|
||||
- `experiment_key`
|
||||
- `variant_id`
|
||||
- `variant_key`
|
||||
- `payload`
|
||||
|
||||
---
|
||||
|
||||
## 7. 資料取得時,如何判斷「是缺參數還是被規則擋」
|
||||
|
||||
### `bootstrap` 回傳 `candidate_experiments = []` 常見原因
|
||||
|
||||
1. `site_id/site_key` 無法解析成站點。
|
||||
2. 該 site 沒有 `status=running` 的實驗。
|
||||
3. URL 規則不匹配(`contains/equals/starts_with/regex`)。
|
||||
4. 裝置不匹配(`device_targets` 與 user-agent 判斷不一致)。
|
||||
5. 實驗下沒有 variants。
|
||||
|
||||
### `assign` 回 `422` 常見原因
|
||||
|
||||
1. `experiment.variants` 空陣列。
|
||||
2. `experiment.variants` 全部權重為 `0` 或負值。
|
||||
|
||||
### `variants` 建立/更新回 `400` 常見原因
|
||||
|
||||
1. 同一 experiment 下,所有 variant 的 `traffic_weight` 加總不等於 `100`。
|
||||
|
||||
### `editor PUT changes` 看起來「少資料」的常見原因
|
||||
|
||||
1. 你沒有把舊 change id 一起送回去,會被 full-replace 刪掉。
|
||||
2. 你送的是 `changes` 欄位而不是 `items`。
|
||||
|
||||
---
|
||||
|
||||
## 8. 你在 Swagger(/docs)建議先看哪裡
|
||||
|
||||
1. 先看 `auth -> GET /api/auth/me`,確認 token 與 permission 正常。
|
||||
2. 再看 `admin/experiments` 與 `admin/variants` 的 request body schema。
|
||||
3. 看 `editor -> PUT changes` / `POST previews/build`,確認你送的是 `items`。
|
||||
4. 看 `runtime -> bootstrap/assign/payload` 的 nested schema,特別是 `experiment.variants[]`。
|
||||
|
||||
---
|
||||
|
||||
## 9. 已知注意事項(目前版本)
|
||||
|
||||
- `API_CONTRACT_MASTER.md` 已同步目前路由;這份文件偏重「必填參數 + 業務限制」。
|
||||
- 自動化測試(P2)尚未補齊,建議以 staging smoke + 這份欄位表當暫時驗證基準。
|
||||
50
docs/backend/RUNTIME_SDK_SPEC.md
Normal file
50
docs/backend/RUNTIME_SDK_SPEC.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Runtime SDK Spec
|
||||
|
||||
## 目標
|
||||
|
||||
定義 SDK 的部署、模式、payload 套用與追蹤邏輯,支援網站端實驗運行。
|
||||
|
||||
## SDK 雙模式
|
||||
|
||||
### Edit Mode
|
||||
|
||||
- 配合 editor 做選取與變更預覽
|
||||
- 提供 overlay / bridge 事件
|
||||
|
||||
### Runtime Mode
|
||||
|
||||
- 正式流量分流
|
||||
- 套用 payload 變更
|
||||
- 回傳 impression / conversion 事件
|
||||
|
||||
## 部署拓撲
|
||||
|
||||
- 商家網站 -> 載入 SDK(CloudFront)
|
||||
- SDK -> 呼叫 FastAPI Runtime API
|
||||
- Origin 由自有 VPS 提供靜態檔
|
||||
|
||||
## 變更規則(DOM Change)
|
||||
|
||||
- change_type:replace_text / set_attribute / set_style / insert / remove / toggle_visibility
|
||||
- selector 必須穩定可重建
|
||||
- payload 必須可序列化與回放
|
||||
|
||||
## Assignment 與 Payload
|
||||
|
||||
- assignment 由 runtime API 決策
|
||||
- payload 由 release 快照提供
|
||||
- 套用前必須驗 selector 是否存在
|
||||
|
||||
## 事件策略
|
||||
|
||||
- FastAPI 先收事件,再依策略轉送 GA4/GTM
|
||||
- 事件層次:audit event、runtime event、forwarded analytics event
|
||||
|
||||
## 風險與檢查
|
||||
|
||||
- CSP
|
||||
- iframe / script injection
|
||||
- DOM 穩定性
|
||||
- style 汙染與 z-index 衝突
|
||||
- cookie / storage 相容性
|
||||
|
||||
51
docs/frontend/FRONTEND_ARCHITECTURE_SPEC.md
Normal file
51
docs/frontend/FRONTEND_ARCHITECTURE_SPEC.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Frontend Architecture Spec
|
||||
|
||||
## 目標
|
||||
|
||||
定義 `mkt.ose.tw/frontend` 的主線架構,讓實驗管理與 Visual Editor 可長期維護。
|
||||
|
||||
## 技術基底
|
||||
|
||||
- Vue 3
|
||||
- Element Plus
|
||||
- Vuex
|
||||
- Vite
|
||||
|
||||
## 分層原則
|
||||
|
||||
### app / shell
|
||||
|
||||
- 路由骨架、layout、全域導航
|
||||
|
||||
### module
|
||||
|
||||
- 依業務模組切分:dashboard、experiment、variant、release、editor
|
||||
|
||||
### service / api client
|
||||
|
||||
- 集中 API 呼叫邏輯
|
||||
- 不在頁面內直接寫散落請求
|
||||
|
||||
### state
|
||||
|
||||
- 僅放跨頁狀態與 session
|
||||
- 頁面暫存留在模組內
|
||||
|
||||
## 主線與 legacy 邊界
|
||||
|
||||
- `experiment / variant / release / editor` 為主線
|
||||
- `ose-card / conutdown-timer` 為 legacy 過渡模組
|
||||
- 新功能不再掛到 legacy 路徑
|
||||
|
||||
## API 邊界
|
||||
|
||||
- Frontend 主入口為 FastAPI
|
||||
- Directus 保留在登入與既有相容路線
|
||||
- 不再新增頁面直接耦合 Directus raw response
|
||||
|
||||
## 近期重點
|
||||
|
||||
- Editor 穩定化(選取、編輯、結構、history)
|
||||
- 管理流補齊(create/edit/build/publish/rollback)
|
||||
- 逐步收斂語言與操作流程(流程化、簡單化、中文化)
|
||||
|
||||
48
docs/frontend/FRONTEND_ENV_SETUP.md
Normal file
48
docs/frontend/FRONTEND_ENV_SETUP.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Frontend Env Setup
|
||||
|
||||
## 目前 frontend 主線
|
||||
|
||||
- `mkt.ose.tw/frontend` 為主線前端
|
||||
- 技術棧:`Vue 3 + Element Plus + Vuex + Vite`
|
||||
- API 正在由 Directus 逐步收斂到 FastAPI
|
||||
|
||||
## env 來源
|
||||
|
||||
```text
|
||||
frontend/env/.env.development
|
||||
frontend/env/.env.production
|
||||
frontend/env/.env.local
|
||||
```
|
||||
|
||||
`vite.config.js` 目前允許:
|
||||
|
||||
- `VITE_*`
|
||||
- `_*`(相容用途)
|
||||
|
||||
## 建議欄位
|
||||
|
||||
```env
|
||||
VITE_DIRECTUS_BASE_URL=https://mktcms.ose.tw
|
||||
VITE_MKTAPI_BASE_URL=https://mktapi.ose.tw
|
||||
VITE_DIRECTUS_DEBUG_TOKEN=
|
||||
```
|
||||
|
||||
## local 建議
|
||||
|
||||
```env
|
||||
VITE_DIRECTUS_BASE_URL=https://mktcms.ose.tw
|
||||
VITE_MKTAPI_BASE_URL=http://127.0.0.1:8011
|
||||
VITE_DIRECTUS_DEBUG_TOKEN=
|
||||
```
|
||||
|
||||
## 舊欄位相容
|
||||
|
||||
仍相容舊欄位:
|
||||
|
||||
```env
|
||||
_API_URL
|
||||
_API_TOKEN
|
||||
```
|
||||
|
||||
但新程式應以統一 config 與 service 層讀取,不在頁面直接散讀 env。
|
||||
|
||||
28
docs/frontend/LEGACY_MODULES_PLAN.md
Normal file
28
docs/frontend/LEGACY_MODULES_PLAN.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Legacy Modules Plan
|
||||
|
||||
## 目標
|
||||
|
||||
定義 legacy 模組的過渡策略,避免影響主線「銷售實驗 + visual editor」進度。
|
||||
|
||||
## 目前定位
|
||||
|
||||
- `ose-card`:保留運作,延後深重構
|
||||
- `conutdown-timer`:保留運作,延後深重構
|
||||
|
||||
## 原則
|
||||
|
||||
- 主線開發不再往 legacy 模組新增核心能力
|
||||
- 新功能優先掛到 experiment / variant / release / editor 主線
|
||||
- legacy 僅做必要修補與相容調整
|
||||
|
||||
## 遷移策略
|
||||
|
||||
1. 先抽規則,不先大搬資料表
|
||||
2. 舊模組能力逐步以 FastAPI 主線接口承接
|
||||
3. 最後再做資料歸屬與 UI/UX 大重構
|
||||
|
||||
## 何時啟動深重構
|
||||
|
||||
- 當 editor 主幹、管理流、runtime 主線穩定後
|
||||
- 有明確商業需求才開新一輪 legacy 深拆
|
||||
|
||||
68
docs/frontend/VISUAL_EDITOR_SPEC.md
Normal file
68
docs/frontend/VISUAL_EDITOR_SPEC.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Visual Editor Spec
|
||||
|
||||
## 目標
|
||||
|
||||
提供行銷可直接操作的同頁編輯體驗,對齊 Google Optimize / Optimize99 的使用感。
|
||||
|
||||
## 核心互動規則
|
||||
|
||||
### 1. 選取回饋
|
||||
|
||||
- hover 顯示藍色虛線框
|
||||
- selected 顯示藍色實線框
|
||||
- 滑鼠移動時可快速預覽可選區域
|
||||
|
||||
### 2. 直接編輯
|
||||
|
||||
- 點選元素後可直接開啟編輯泡泡
|
||||
- 支援文字、按鈕文字、按鈕連結、圖片來源、樣式
|
||||
- 編輯為即時同步(不用再按套用)
|
||||
|
||||
### 3. 結構操作
|
||||
|
||||
- 上移 / 下移 / 拖移
|
||||
- 隱藏 / 顯示
|
||||
- 複製 / 刪除
|
||||
- 前插 / 後插
|
||||
|
||||
### 4. 歷史機制
|
||||
|
||||
- 內容編輯與結構操作都必須可 undo/redo
|
||||
- restore 後畫布狀態、選取狀態、泡泡狀態要一致
|
||||
|
||||
## 編輯泡泡規格
|
||||
|
||||
- 可拖拉、可關閉、固定於視窗可用位置
|
||||
- Header 保持簡潔:拖拉點 + 關閉
|
||||
- 內容區為可捲動區塊
|
||||
- icon hover 要有 tooltip(清楚告知作用)
|
||||
|
||||
## Bridge Protocol(頁面與 editor)
|
||||
|
||||
### page -> editor
|
||||
|
||||
- ready
|
||||
- hover/selection 變更
|
||||
- structure change 結果
|
||||
- history 狀態更新
|
||||
|
||||
### editor -> page
|
||||
|
||||
- focus selector
|
||||
- start inline edit
|
||||
- set text / attr / style
|
||||
- structure actions
|
||||
- restore state
|
||||
|
||||
## Selector 與定位策略
|
||||
|
||||
- 頁面載入時補唯一 `data-mkt-selector`
|
||||
- 插入與複製後重建 selector,避免衝突
|
||||
- 相似兄弟節點必須可各自選取
|
||||
|
||||
## 不做事項(此階段)
|
||||
|
||||
- 不走 Chrome Extension 路線
|
||||
- 不增加大型資訊面板干擾畫面
|
||||
- 不先做自由版面拖拉排版(以區塊重排為主)
|
||||
|
||||
42
docs/operations/RELEASE_OPERATIONS_MASTER.md
Normal file
42
docs/operations/RELEASE_OPERATIONS_MASTER.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Release Operations Master
|
||||
|
||||
## 目標
|
||||
|
||||
整合部署、監控、設定對齊、回滾與 staging 交接流程。
|
||||
|
||||
## 服務入口
|
||||
|
||||
- Frontend:`mkt.ose.tw`
|
||||
- FastAPI:`mktapi.ose.tw`
|
||||
- Directus:`mktcms.ose.tw`
|
||||
- SDK:CloudFront + VPS Origin
|
||||
|
||||
## 發布前檢查
|
||||
|
||||
- 環境變數與 secrets 已注入
|
||||
- CORS、domain、token 策略一致
|
||||
- API readiness 與 smoke 通過
|
||||
- 驗證資料完整
|
||||
|
||||
## 發布步驟
|
||||
|
||||
1. Build 與部署
|
||||
2. 健康檢查
|
||||
3. 核心流程 smoke
|
||||
4. 監控與錯誤觀察
|
||||
5. 記錄發布結果
|
||||
|
||||
## 回滾步驟
|
||||
|
||||
1. 停止新版本流量
|
||||
2. 切回上一 release
|
||||
3. 驗證健康與核心流程
|
||||
4. 補齊事故記錄與後續動作
|
||||
|
||||
## 監控基線
|
||||
|
||||
- API 錯誤率
|
||||
- Runtime 事件量與失敗率
|
||||
- Editor 主要操作失敗率
|
||||
- 發布後 30 分鐘內異常告警
|
||||
|
||||
55
docs/templates/MODULE_SPEC_TEMPLATE.md
vendored
Normal file
55
docs/templates/MODULE_SPEC_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
# Module Spec Template
|
||||
|
||||
## 1. 模組概要
|
||||
|
||||
- 模組名稱:
|
||||
- 目標使用者:
|
||||
- 問題定義:
|
||||
- 成功指標(KPI):
|
||||
|
||||
## 2. 範圍定義
|
||||
|
||||
- In scope:
|
||||
- Out of scope:
|
||||
- 與既有模組關係:
|
||||
|
||||
## 3. 架構與資料邊界
|
||||
|
||||
- API 入口(Admin / Editor / Runtime):
|
||||
- 主要 Entity:
|
||||
- Directus / Native 歸屬(參照 Data Ownership Matrix):
|
||||
- revision 需求:
|
||||
- 自動編碼規則(如 `EX+timestamp` / `VA+timestamp`):
|
||||
- 使用者可編輯欄位(只列可編輯):
|
||||
|
||||
## 4. API 與 DTO
|
||||
|
||||
- 新增/調整端點:
|
||||
- Request/Response DTO:
|
||||
- 錯誤碼:
|
||||
- 版本策略(是否影響 v1):
|
||||
|
||||
## 5. Frontend 互動
|
||||
|
||||
- 使用流程(行銷視角):
|
||||
- 主要頁面與狀態:
|
||||
- 中文化與簡化策略:
|
||||
|
||||
## 6. 驗收與測試
|
||||
|
||||
- 功能驗收案例:
|
||||
- 回歸測試範圍:
|
||||
- DoD:
|
||||
|
||||
## 7. 上線與回滾
|
||||
|
||||
- 發布步驟:
|
||||
- 監控指標:
|
||||
- 回滾條件:
|
||||
- 回滾步驟:
|
||||
|
||||
## 8. 風險與假設
|
||||
|
||||
- 主要風險:
|
||||
- 依賴與前置:
|
||||
- 已採用假設:
|
||||
46
docs/validation/TEST_ACCEPTANCE_MASTER.md
Normal file
46
docs/validation/TEST_ACCEPTANCE_MASTER.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Test Acceptance Master
|
||||
|
||||
## 目的
|
||||
|
||||
統一 MVP 驗收矩陣,作為 go/no-go 的依據。
|
||||
|
||||
## 驗收維度
|
||||
|
||||
### 功能
|
||||
|
||||
- Admin 流程可建立、編輯、發布、回退
|
||||
- Editor 可選取、編輯、結構操作、undo/redo
|
||||
- Runtime 可分流、套版、上報事件
|
||||
|
||||
### 穩定性
|
||||
|
||||
- 高頻操作無阻塞錯誤
|
||||
- selector 與 history 不失效
|
||||
|
||||
### 效能
|
||||
|
||||
- 前端建置時間與包體符合基線
|
||||
- API 主要端點回應時間在可接受範圍
|
||||
- SDK 套用變更不影響頁面可互動性
|
||||
|
||||
### 安全
|
||||
|
||||
- 權限檢查符合 401/403/200 基線
|
||||
- token 與環境配置符合安全策略
|
||||
|
||||
### 回滾
|
||||
|
||||
- release rollback 可執行
|
||||
- 資料回退與故障處置流程可演練
|
||||
|
||||
## Go / Conditional Go / No-Go
|
||||
|
||||
- Go:核心流程全部通過,無阻塞問題
|
||||
- Conditional Go:有可接受風險且有明確緩解方案
|
||||
- No-Go:核心流程阻塞或安全風險未關閉
|
||||
|
||||
## 驗收輸出
|
||||
|
||||
- 測試結果記錄到 [VALIDATION_EXECUTION_LOG.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/VALIDATION_EXECUTION_LOG.md)
|
||||
- 交接與回填使用 templates 文件
|
||||
|
||||
61
docs/validation/VALIDATION_EXECUTION_LOG.md
Normal file
61
docs/validation/VALIDATION_EXECUTION_LOG.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Validation Execution Log
|
||||
|
||||
## 用途
|
||||
|
||||
每次測試都更新這份,不另開平行版本。
|
||||
|
||||
## 批次資訊
|
||||
|
||||
- 日期:
|
||||
- 執行者:
|
||||
- 環境:local / staging / production
|
||||
- 範圍:
|
||||
|
||||
## 前提確認
|
||||
|
||||
- [ ] Env 完整
|
||||
- [ ] 權限可用
|
||||
- [ ] 測試資料可用
|
||||
|
||||
## 執行紀錄
|
||||
|
||||
### 1. Health / Readiness
|
||||
|
||||
- 結果:
|
||||
- 備註:
|
||||
|
||||
### 2. Auth / Session
|
||||
|
||||
- 結果:
|
||||
- 備註:
|
||||
|
||||
### 3. Admin Data Flow
|
||||
|
||||
- 結果:
|
||||
- 備註:
|
||||
|
||||
### 4. Editor Flow
|
||||
|
||||
- 結果:
|
||||
- 備註:
|
||||
|
||||
### 5. Runtime Flow
|
||||
|
||||
- 結果:
|
||||
- 備註:
|
||||
|
||||
## 問題清單
|
||||
|
||||
### 阻塞問題
|
||||
|
||||
-
|
||||
|
||||
### 非阻塞問題
|
||||
|
||||
-
|
||||
|
||||
## 結論
|
||||
|
||||
- Go / Conditional Go / No-Go:
|
||||
- 後續動作:
|
||||
|
||||
58
docs/validation/VALIDATION_MASTER.md
Normal file
58
docs/validation/VALIDATION_MASTER.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Validation Master
|
||||
|
||||
## 目的
|
||||
|
||||
整合驗證入口、前置條件、執行流程、triage 規則與批次策略。
|
||||
|
||||
## 驗證前提
|
||||
|
||||
- API 與 frontend 可啟動
|
||||
- 有可用帳號與權限
|
||||
- 最小測試資料已建立
|
||||
|
||||
## 最短啟動路徑
|
||||
|
||||
1. 準備 env(參考 scripts 與 env 模板)
|
||||
2. 跑 preflight 檢查
|
||||
3. 跑 smoke
|
||||
4. 跑 editor / runtime 指定流程
|
||||
5. 記錄結果到 execution log
|
||||
|
||||
## 驗證批次建議
|
||||
|
||||
### Batch 1:環境與身份
|
||||
|
||||
- health / ready
|
||||
- auth / session
|
||||
|
||||
### Batch 2:後台資料流
|
||||
|
||||
- experiments / variants / releases / goals
|
||||
|
||||
### Batch 3:Editor 主流程
|
||||
|
||||
- 選取、即時編輯、結構操作、history
|
||||
|
||||
### Batch 4:Runtime 主流程
|
||||
|
||||
- bootstrap / assign / payload / events
|
||||
|
||||
### Batch 5:回填與審查
|
||||
|
||||
- triage
|
||||
- readiness 結論
|
||||
|
||||
## Triage 規則
|
||||
|
||||
- 先判斷失敗階段:Auth / Admin / Editor / Runtime
|
||||
- 再判斷根因:環境 / 資料 / 程式 / 範圍誤判
|
||||
- 阻塞與非阻塞分開紀錄
|
||||
|
||||
## 搭配文件
|
||||
|
||||
- [TEST_ACCEPTANCE_MASTER.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/TEST_ACCEPTANCE_MASTER.md)
|
||||
- [VALIDATION_EXECUTION_LOG.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/VALIDATION_EXECUTION_LOG.md)
|
||||
- [MINIMAL_TEST_DATA_TEMPLATE.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/templates/MINIMAL_TEST_DATA_TEMPLATE.md)
|
||||
- [STAGING_REQUEST_PACKAGE.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/templates/STAGING_REQUEST_PACKAGE.md)
|
||||
- [STAGING_REPLY_TEMPLATE.md](/Users/chirs/Documents/workspace/marketing/mkt.ose.tw/docs/validation/templates/STAGING_REPLY_TEMPLATE.md)
|
||||
|
||||
28
docs/validation/templates/MINIMAL_TEST_DATA_TEMPLATE.md
Normal file
28
docs/validation/templates/MINIMAL_TEST_DATA_TEMPLATE.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Minimal Test Data Template
|
||||
|
||||
## 最小資料集
|
||||
|
||||
- corporate_customer
|
||||
- site
|
||||
- experiment
|
||||
- variants
|
||||
- variant_changes
|
||||
- experiment_releases
|
||||
- goals
|
||||
- sdk_configs
|
||||
|
||||
## 建議命名
|
||||
|
||||
- site_key:`ose-main-site`
|
||||
- experiment_key:`EX+timestamp`(系統生成)
|
||||
- variant_key:`VA+timestamp`(系統生成)
|
||||
- control variant:`control`
|
||||
- challenger variant:`v1`
|
||||
|
||||
## 驗證時常用值
|
||||
|
||||
- site_id:
|
||||
- experiment_id:
|
||||
- variant_id(control):
|
||||
- variant_id(challenger):
|
||||
- release_id:
|
||||
20
docs/validation/templates/STAGING_REPLY_TEMPLATE.md
Normal file
20
docs/validation/templates/STAGING_REPLY_TEMPLATE.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Staging Reply Template
|
||||
|
||||
## 回填模板
|
||||
|
||||
- frontend URL:
|
||||
- API URL:
|
||||
- Directus URL:
|
||||
- 測試帳號:
|
||||
- 權限角色:
|
||||
- token / session 方式:
|
||||
- site_id:
|
||||
- experiment_id:
|
||||
- variant_id:
|
||||
- release_id:
|
||||
|
||||
## 備註
|
||||
|
||||
- 本輪限制:
|
||||
- 已知問題:
|
||||
|
||||
24
docs/validation/templates/STAGING_REQUEST_PACKAGE.md
Normal file
24
docs/validation/templates/STAGING_REQUEST_PACKAGE.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Staging Request Package
|
||||
|
||||
## 目的
|
||||
|
||||
向環境管理者索取 staging 驗證必需資訊。
|
||||
|
||||
## 最小需要項目
|
||||
|
||||
1. 環境入口
|
||||
- frontend URL
|
||||
- API URL
|
||||
- Directus URL
|
||||
|
||||
2. 身份與權限
|
||||
- 測試帳號
|
||||
- 權限角色
|
||||
- token 提供方式
|
||||
|
||||
3. 最小測試資料
|
||||
- site / experiment / variant / release
|
||||
|
||||
4. 驗證範圍
|
||||
- 本輪要驗證的流程與限制
|
||||
|
||||
Reference in New Issue
Block a user