# 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()` 會回退到較早版本。 - [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 `"*"`)。 - [x] `P1` Release rollback 邊界條件補強:只允許 rollback `published` release,並在 publish/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),目前剩餘:2 項 P2 強化。** 目前系統可運作;P1/P2 完成後可進一步提高一致性與可回歸性。 ## 延後項目 - 大型 UI polish - `ose-card` 深度重構 - `conutdown-timer` 深度重構