# 内置浏览器 — 网站导航（收藏）设计说明

> 关联：[2026-06-11-embedded-browser-design.md](./2026-06-11-embedded-browser-design.md) · [2026-06-11-global-floating-browser 变更](../../changelog/2026-06-11-global-floating-browser.md)

## 背景与目标

用户希望在 Nexus **全局浮动浏览器**内维护一份**自定义网站导航**（类似浏览器收藏夹），便于反复打开常用运维站点（监控、面板、客户站点等），而不依赖浏览器自带书签。

### 用户原话（2026-06-11）

> 浏览器内置网站导航，我自己可以增加，类似收藏功能。

### 与现有能力的关系

| 已有 | 导航（收藏） |
|------|----------------|
| **浏览记录** `visits` | 被动、按访问时间倒序，不可编辑名称 |
| **URL 历史** `url_history` | 去重 URL 列表，无自定义标题 |
| **网站导航** `nav_links` | 用户主动添加/编辑/删除，固定名称 + URL，长期入口 |

三者并存：记录 ≠ 收藏；收藏用于「我关心的固定站点」。

## 非目标

- 不做浏览器引擎替换（首版 iframe；**2026-06-11 改为服务端 Chromium**，见 [server-browser-chromium-design.md](./2026-06-11-server-browser-chromium-design.md)）
- 不做 HTTP 反向代理
- 不做跨管理员共享导航（按账号隔离，与 `admin_ui_preferences` 一致）
- 首版不做文件夹/分组（可后续 `group` 字段扩展）

## 数据模型

存储：`admin_ui_preferences`，`context = embedded_browser`，字段 `nav_links`（JSON 数组）。

```json
{
  "nav_links": [
    {
      "id": "uuid",
      "title": "Grafana",
      "url": "https://grafana.example.com",
      "sort_order": 0
    }
  ]
}
```

约束（后端 `browser_ui_state.py`）：

| 字段 | 规则 |
|------|------|
| `id` | 非空字符串，≤64 |
| `title` | 非空，≤80 |
| `url` | 仅 `http`/`https`，无凭据，与现有 URL 白名单一致 |
| 数量上限 | 64 条 |
| `sort_order` | 整数，用于排序 |

API：沿用 `GET/PUT /api/browser/state`，`nav_links` 随整体 state 读写（与 tabs、visits 相同）。

## 交互设计

### 入口

1. 浮动浏览器工具栏：**「导航」**按钮（`mdi-star-outline`），与「浏览记录」并列
2. 侧栏 Tab：**网站导航** | **浏览记录**（同一侧栏区域切换，避免双栏占宽）
3. 空白页：展示导航卡片网格，点击即打开

### 用户操作

| 操作 | 行为 |
|------|------|
| 添加 | 对话框：名称 + URL；可预填当前地址栏 / 当前页 URL |
| 编辑 | 同对话框，改名称或 URL |
| 删除 | 列表项菜单或删除图标，需确认（可选） |
| 打开 | 点击条目 → 当前标签导航到该 URL |
| 从当前页收藏 | 地址栏旁「星标」一键添加（已存在则提示或进入编辑） |

### 持久化

- 保存至 MySQL，换设备/清 localStorage 不丢
- 与浏览记录、标签、窗口位置同一 debounce 写入策略

## 安全

- URL 校验复用 `_is_safe_url`，拒绝 `javascript:`、`data:` 等
- 无服务端 fetch，无 SSRF
- 按 `admin_id` 隔离

## 内核与风控说明（用户关切）

内置浏览器 **不是** 独立 Firefox/Chrome 安装包，而是 **iframe + 用户当前浏览器引擎**。

- User-Agent 与普通浏览器一致，**不会因 Nexus 被单独判为机器人**
- 部分站点禁止 iframe 或要求顶层窗口 → 仍用「新标签打开」
- 收藏导航仅保存 URL，不改变加载方式

## 实现状态（2026-06-11）

| 层 | 状态 |
|----|------|
| 后端 `nav_links` 解析 / API 字段 | ✅ 已入代码（待前端联调） |
| 前端侧栏 + 增删改 UI | ⏳ 待实现 |
| 单测 `nav_links` 解析 | ✅ `tests/test_browser_ui_state.py::test_parse_nav_links` |
| 部署 | ⏳ 前端完成后一并门控 |

## 验收标准

- [ ] 可添加、编辑、删除导航项，刷新后仍在
- [ ] 点击导航项在当前标签打开对应 https 站点
- [ ] 可从当前页一键加入收藏
- [ ] 非法 URL 拒绝并提示
- [ ] 不同管理员账号导航互不可见
- [ ] 与浏览记录、标签、最小化状态可同时正常工作
