# C7 — Implementation Plan

> 對應 design：[design-C7.md](design-C7.md)
> 級別：小
> 預估工時：BE 0.5 天（含 smoke + 樣板版本確認）

---

## Pre-flight 驗證

```bash
# 1. 確認 SHEET_LEVERAGED 定義仍在
grep -n "SHEET_LEVERAGED" app/module_frame/excel_template/sheet_definitions.py
# 預期：line 184

# 2. 確認 parse_leveraged_sheet handler 仍在
grep -n "parse_leveraged_sheet" app/oscal/service/excel_parser/sheet_handlers.py
# 預期：line 139

# 3. 確認 LeveragedWriteStrategy 仍存活
grep -rn "LeveragedWriteStrategy\b" app/oscal/service/ --include="*.py" | head -3
# 預期：被 ssp_excel_import_app_service.py 注入

# 4. 樣板版本目前值
grep -n "TEMPLATE_VERSION\b" app/module_frame/excel_template/sheet_definitions.py
# 預期：v2.0.0

# 5. A2 parser 相容性檢查邏輯
grep -rn "template_version" app/oscal/service/excel_parser/ --include="*.py" | head -5
# → 確認對 v2.0.0 / v2.1.0 容錯處理
```

---

## 任務清單

### T1 — `sheet_definitions.py` ALL_SHEETS 加回 SHEET_LEVERAGED（BE）

**檔案**：`app/module_frame/excel_template/sheet_definitions.py:259`

**改動**：對齊 design-C7.md §5.1（tuple 內加 `SHEET_LEVERAGED` 在 SHEET_INFO_SYSTEMS 後 / SHEET_CONTROLS 前）

**附帶**：移除 line 255-258 註解（解釋 v2.0.0 隱藏的歷史脈絡），改成 C7 註解說明恢復理由

**Commit message**：`feat(ssp-excel-template): C7 恢復 06_外部利用服務 sheet`

---

### T2 — `parser.py` 改回讀取（BE）

**檔案**：`app/oscal/service/excel_parser/parser.py:70`

**改動**：對齊 design-C7.md §5.2（呼叫 `sh.parse_leveraged_sheet`）

**Commit message**：合併到 T1 同個 commit（連動改動）

---

### T3 — TEMPLATE_VERSION bump v2.0.0 → v2.1.0（BE）

**檔案**：`app/module_frame/excel_template/sheet_definitions.py`（或對應位置）

**改動**：
```python
TEMPLATE_VERSION = "v2.1.0"   # C7 (2026-MM-DD): 恢復 06_外部利用服務 sheet
```

**相容性檢查**：
- A2 parser 對 v2.0.0 / v2.1.0 / v1.x 的處理邏輯（pre-flight Step 5 驗證）
- 若 parser 對舊版本 strict reject → 改 lenient mode + WARN

**Commit message**：合併到 T1

---

### T4 — Unit test：06 sheet 匯入流程（BE）

**檔案**：`tests/test_excel_template_generator_blank.py` / `test_excel_template_generator_filled.py`

**新測試 case**：
- 樣板下載含 06 sheet（v2.1.0 generator 輸出）
- 06 sheet 結構：3 欄 + header style + 黃底必填欄位

**檔案**：`tests/test_excel_parser.py`

**新測試 case**：
- 餵一份 v2.1.0 樣板 → parser 回 `ParsedExcel(leveraged=[...])` 非空
- 餵一份 v2.0.0 舊樣板（無 06 sheet）→ parser 回 `leveraged=[]` 且 validation_errors 加 non-blocking warning
- `service_name` 缺 → validation error

**檔案**：`tests/test_a4_write_strategy_leveraged.py` 已存在，沿用

**Commit message**：`test(ssp-excel): C7 加 06_外部利用服務 sheet 匯入流程測試`

---

### T5 — Smoke test：下載 + 匯入 round-trip（manual）

**步驟**：
1. `GET /api/1.0/module-frame/<uid>/ssp-import-template?mode=blank` 下載樣板
2. 開啟確認 06 sheet 存在、有 3 欄
3. 手動填 2 筆 leveraged 資料
4. 透過 SSP 匯入流程（A2 endpoint）上傳
5. 確認 `ssp_system_implementation_items` 內有 `implementation_type='leveraged-authorization'` 對應 2 筆

**SQL 驗證**：
```sql
SELECT name, title, purpose, implementation_type
  FROM oscal.ssp_system_implementation_items
 WHERE implementation_type = 'leveraged-authorization'
   AND scope_type = 'ssp'
   AND scope_id = <test_ssp_id>
 ORDER BY created_at DESC LIMIT 5;
```

---

### T6 — Changelog

**檔案**：`docs/changelog/YYYY-MM-DD-feat-ssp-excel-leveraged-sheet-restore.md`

```markdown
---
type: feat
breaking: false
modules: [module_frame, oscal]
---

## 需求說明
C7：恢復 v2.0.0 隱藏的 06_外部利用服務 sheet。Phase C 走向 SSP 直接編輯後，
純文字輸入到 SSP 變得合理，重啟此 sheet 的匯入路徑。

## 變更範圍
### BE
- `app/module_frame/excel_template/sheet_definitions.py`：ALL_SHEETS 加回 SHEET_LEVERAGED
- `app/oscal/service/excel_parser/parser.py`：leveraged=[] 改回呼叫 parse_leveraged_sheet
- TEMPLATE_VERSION v2.0.0 → v2.1.0
- `tests/`：新增 06 sheet round-trip 測試

## 行為差異
- Excel 樣板下載多一頁 06_外部利用服務（3 欄純文字：service_name / provider / purpose）
- 匯入流程處理 06 sheet 資料 → ssp_system_implementation_items (type='leveraged-authorization')
- v2.0.0 舊樣板仍可匯入（向後相容，無 06 sheet 視為空）
```

---

## 完成標準（DoD）

- [ ] ALL_SHEETS 加回 SHEET_LEVERAGED
- [ ] parser.py 改回讀取
- [ ] TEMPLATE_VERSION → v2.1.0
- [ ] BE unit test 全綠（含新 case）
- [ ] Smoke round-trip 驗證通過
- [ ] Changelog 完成
- [ ] README tracker (C7) 狀態更新

---

## 風險 / Rollback

| 風險 | 緩解 |
|------|------|
| v2.1.0 樣板 user 用舊 parser 匯入 break | 已驗證 parser 對缺 sheet 是 non-blocking warning |
| LeveragedWriteStrategy 已 stale 不能用 | A4 階段已有測試，無 stale 風險 |
| 寫入時撞 A5 bugfix「整份覆蓋」邏輯 | 此 fix 對 leveraged 已生效（write_strategy base.py） |

**Rollback**：純樣板改動，`git revert` 即可。已匯入的 leveraged 資料維持在 SSP items 表內，不會被影響。
