# T830 — review state domain and mapping

> Status: `done`
> Milestone: `M3`
> Est. change: `~180 lines`

## Goal

完成後 backend domain 將 ReviewState 與 OpportunityStatus 分離，並能對舊文件完成安全映射與合法狀態轉移。

## Depends on

- T823（Phase B UX approval）
- T800、T802

## Inputs

- `apps/backend/internal/module/radar/domain/opportunity.go`
- `apps/backend/internal/module/radar/domain/repository.go`
- Spec §3.1–§3.2、驗收 #1–#5

## Outputs

### 程式變更（預期路徑）

| 路徑 | 動作 | 說明 |
|------|------|------|
| `apps/backend/internal/module/radar/domain/opportunity.go` | edit | review state、reason、previous state、移除欄位與 transition |
| `apps/backend/internal/module/radar/domain/opportunity_review.go` | add | review audit／mapping domain |
| `apps/backend/internal/module/radar/domain/opportunity_test.go` | edit | 狀態與 legacy table tests |

### 行為變更

- accept 仍是 CRM business status；完成／移除只改 review state。
- dismissed 舊資料映射 removed(legacy_unknown)，不可偷偷回 qualified。

### API / 契約（若有）

- domain validation 與 T800 API enum 一致。

## Out of scope

- 不實作 Mongo、HTTP logic、worker。

## Acceptance

- [x] 合法 transition、非法 transition、idempotent update 與 legacy mapping table tests 通過。
- [ ] 指令：

```bash
cd apps/backend && go test ./internal/module/radar/domain -run 'Review|Opportunity' -count=1
```

## Notes

review event 需可 append-only 保存，但本 task 只定義 domain shape。
