# T551 — fe-radar-today-page

> Status: `done`  
> Milestone: `M3`  
> Kind: `feat`  
> Est. change: `~200 lines`

## Goal

完成後系統應：`/app/radar` 打開就看到今日統計列與高／中／低分組名單（低意向預設收合），0 筆時顯示原因與下一步。

## Depends on

- T502、T503、T545

## Inputs

- Spec：`../spec.md` §4.4、§5.3、§9.3（TD-01、TD-02）
- 既有：`apps/web/src/pages/TodayPage.tsx`（版面語彙參考）、`src/components/ui/`

## Outputs

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

| 路徑 | 動作 | 說明 |
|------|------|------|
| `apps/web/src/pages/RadarTodayPage.tsx` | add | 統計列＋三個分組＋截斷提示＋空狀態 |
| `apps/web/src/components/radar/OpportunityCard.tsx` | add | 五欄位卡片：原文摘要、分數、band badge、地區、發布距今 |
| `apps/web/src/App.tsx` | edit | 註冊 `/app/radar` |
| `apps/web/src/data/live/radarRepos.ts` | edit | today／opportunities 實作 |
| `apps/web/src/styles/radar.css` | edit | 統計列與卡片樣式 |

### 行為變更

- 空狀態依後端 `empty_reason` 顯示對應原因與行動按鈕（去建服務檔案／去恢復 watch／放寬關鍵字／看失敗紀錄），**不得顯示空白頁**。
- 有 `truncated_count` 時顯示「已達今日上限，N 筆較低意向未收錄」。
- 發布距今由 `posted_at`（ns）在前端換算。
- 低意向分組預設收合，可展開。

## Out of scope

- 卡片動作與回覆面板（T552）
- 側欄與手機底欄（T553）

## Acceptance

- [x] 18 筆情境：統計與分組數字一致
- [x] 0 筆情境：六種 `empty_reason` 各有對應文案與動作
- [x] 指令：

```bash
cd apps/web && npm run build && npm run check:tokens && npm run test && npm run lint
```
