# INP2P 最终方案 v1（用户网络模型）

> 状态：已冻结（按 2026-03-03 讨论结论）
> 目标：稳定优先，先完成认证/网络模型收敛，再做增量体验优化。

---

## 0. 冻结决策（已确认）

1. 一账号=一网络（1:1）
2. Hub 离线自动回 Mesh
3. 改 IP 后：目标节点重连 + 同网广播更新
4. API Key：保留后台能力，前台不突出
5. 暂不上 Refresh Token
6. Node 唯一标识采用 UUID（稳定优先）

---

## 1. 核心对象模型

### 1.1 Account（账号）
- 控制台登录主体（人）
- 字段：
  - `account_id` (int64 PK)
  - `username` (unique)
  - `password_hash`
  - `status` (1/0)
  - `created_at`

### 1.2 Network（用户网络）
- 每个账号唯一绑定一个网络
- 字段：
  - `network_id` (int64 PK)
  - `account_id` (unique FK -> accounts)
  - `cidr` (e.g. `10.0.1.0/24`)
  - `mode` (`mesh`|`hub`)
  - `hub_node_id` (nullable, FK -> nodes.node_id)
  - `fallback_to_mesh` (bool, default true)
  - `status` (1/0)
  - `created_at`, `updated_at`

### 1.3 Node（设备）
- 设备唯一标识不变；展示名可变
- 字段：
  - `node_id` (UUID, PK)  ✅ 后端唯一键
  - `network_id` (FK)
  - `hostname` (设备上报)
  - `alias` (用户自定义昵称，可空)
  - `virtual_ip` (network cidr 内)
  - `node_secret_hash`
  - `relay_enabled` (bool)
  - `online` (bool)
  - `last_seen`
  - `created_at`, `updated_at`

### 1.4 凭证对象
- `session_tokens`（控制台会话，短期）
- `enroll_tokens`（一次性/短期入网码）
- `api_keys`（后台自动化，非控制台主要路径）

---

## 2. 凭证与认证边界（彻底拆分）

### 2.1 会话 token（控制台）
- 登录成功后返回 `session_token`
- 内含：`account_id`, `network_id`, `role=owner`, `exp`
- 用于所有控制台 API

### 2.2 enroll token（设备入网）
- 控制台生成，一次性，短时有效（默认 10 分钟）
- 设备携带 `hostname` + enroll token 兑换 `node_id + node_secret + virtual_ip`

### 2.3 node_secret（设备长期）
- 设备 WS 登录凭证
- 仅设备连接信令使用，不用于控制台

### 2.4 API Key（后台能力）
- 用于自动化脚本/平台对接
- 不作为控制台默认登录路径
- 前台不突出，仅高级设置页可见

---

## 3. 网络与 IPAM 规则

### 3.1 子网分配
- 池：`10.0.1.0/24` ~ `10.0.254.0/24`
- 保留：`10.0.0.0/24`、`10.0.255.0/24`
- 账号注册时分配第一个可用网段

### 3.2 地址分配
- 每网络内自动分配：从 `.2` 开始
- 保留 `.0/.255/.1`
- 禁止重复占用

### 3.3 手动改 IP
- 必须在网络 CIDR 内
- 不可与现有节点冲突
- 成功后触发：
  1) 目标节点收到 `ip_changed` 推送并重连
  2) 服务端广播 `peer_ip_changed` 给同网在线节点

---

## 4. 拓扑模式状态机

### 4.1 Mesh（默认）
- 同网节点按策略尝试直连（UDP/TCP）
- 失败后按中继策略兜底

### 4.2 Hub
- 条件：`hub_node_id` 必填，且必须“在线 + 同网络 + relay_enabled=true”
- 数据面按 hub 转发

### 4.3 Hub 离线回退
- 监测阈值：15~30 秒无心跳
- 自动回 `mesh`（记录审计日志）
- Hub 恢复后暂不自动切回（v1 简化）

---

## 5. API 草图（v1）

## 5.1 认证
- `POST /api/v1/auth/register`
  - req: `{username,password}`
  - rsp: `{account_id, network:{cidr,mode}}`
- `POST /api/v1/auth/login`
  - req: `{username,password}`
  - rsp: `{session_token, expires_in, network}`
- `POST /api/v1/auth/logout`

## 5.2 网络配置
- `GET /api/v1/network`
- `POST /api/v1/network/mode`
  - req: `{mode:"mesh"|"hub", hub_node_id?}`
- `POST /api/v1/network/hub`
  - req: `{hub_node_id}`（含在线校验）

## 5.3 节点管理
- `GET /api/v1/nodes`
- `POST /api/v1/nodes/{node_id}/alias`
  - req: `{alias}`
- `POST /api/v1/nodes/{node_id}/ip`
  - req: `{virtual_ip}`
- `POST /api/v1/nodes/{node_id}/kick`

## 5.4 入网与设备凭证
- `POST /api/v1/enroll/create`
- `POST /api/v1/enroll/revoke/{id}`
- `POST /api/v1/enroll/consume`
  - req: `{code, hostname}`
  - rsp: `{node_id, node_secret, virtual_ip, network_cidr}`

## 5.5 自动化（低显著）
- `GET/POST /api/v1/settings/api-keys`

---

## 6. 前端展示规范

- 节点主显示名：`alias || hostname`
- 次级显示：`node_id`（短）
- 明确区分：
  - "控制台会话"（session）
  - "设备凭证"（node_secret）
  - "自动化凭证"（api key）
- API Key 页面放到“高级设置”折叠区，不作为主流程入口

---

## 7. 迁移计划（分阶段）

### Phase A（认证收敛，必做）
1. `auth/login` 改为返回 session token，不再返回 API key
2. 中间件基于 session 解出 `account_id/network_id`
3. 控制台 API 全量改用 session 鉴权

### Phase B（节点模型升级）
1. 引入 `node_id(UUID)`
2. 增加 `alias` 字段
3. 节点唯一性改以 `node_id` 为准（非 hostname）

### Phase C（IPAM + 拓扑闭环）
1. 改 IP 重连与广播机制
2. Hub 在线校验 + 自动回 mesh
3. 观测与审计日志完善

---

## 8. 验收标准（v1）

1. 用户登录后拿到 session token（不是 API key）
2. 同一网络外的数据不可见
3. 改 IP 后目标节点重连，其他节点收到变更通知
4. hub 下线后自动回 mesh
5. node_id 在重命名 hostname/alias 后仍不变
6. API Key 不影响控制台主流程

---

## 9. 风险与规避

- 风险：旧 token 体系与新 session 并存期可能混淆
  - 规避：版本开关 + 明确响应字段（`token_type=session`）
- 风险：节点重连窗口导致短时抖动
  - 规避：变更前提示 + 逐节点串行生效
- 风险：hub 恢复/掉线频繁导致模式抖动
  - 规避：加入最小驻留时间（如 60s）

---

## 10. 下一步实施顺序（立即执行）

1. 后端：新增 session token 生成/校验（无 refresh）
2. 后端：中间件切换到 session 识别 network
3. 前端：登录流程改读 `session_token`
4. 后端：保留 API key 能力但移出主登录流程
5. 回归联调：登录、节点、sdwan、connect、enroll、hub 回退
