# 2026-05-25 — 服务器表单 UX 重构：预设下拉菜单 + SSH 密钥输入

## 变更摘要

重构服务器添加/编辑 Modal 的认证区域：
1. 密码预设从🔑弹窗 + prompt()二次验证 → `<select>` 下拉菜单，选预设后密码框自动隐藏，后端自动解析
2. SSH 密钥模式新增「私钥内容」textarea，支持直接粘贴 PEM 格式私钥
3. Server 模型新增 `preset_id` 字段，关联密码预设

## 动机

- 旧方案：点击🔑按钮 → 浮层弹窗 → prompt() 输入登录密码 → 解密预设 → 填入密码框。流程冗长，且 prompt() 不安全（明文密码出现在 JS 变量中）
- 新方案：直接选预设下拉 → 密码框自动隐藏 → 保存时后端自动解密预设密码并加密存储。零前端密码暴露
- 密钥模式之前只有「密钥路径」，无法粘贴私钥内容，功能缺失

## 涉及文件

| 文件 | 改动 |
|------|------|
| `server/domain/models/__init__.py` | Server 新增 `preset_id` 列 |
| `server/api/schemas.py` | ServerCreate/ServerUpdate 新增 `preset_id` 字段 |
| `server/api/servers.py` | create_server/update_server 自动解析预设密码；`ssh_key_private` 时自动设 `ssh_key_configured=True`；`_server_to_dict` 输出 `preset_id` |
| `web/app/servers.html` | Modal 重构：密码区=预设下拉+密码输入框(联动)；密钥区=路径+私钥textarea；删除旧 preset 弹窗代码 |

## 是否需迁移/重启

- **DB 迁移**: `ALTER TABLE servers ADD COLUMN preset_id INT NULL COMMENT '关联的密码预设ID(SSH认证)' AFTER agent_api_key;`
- **需重启**: 是（Python 后端模型+路由变更）

## 安全考量

- 前端不再接触预设密码明文 → 减少攻击面
- `preset_id` 仅在后端解析，前端只传 ID → 无 XSS 泄露风险
- 预设不存在时静默忽略，不报错（用户仍可手动输入密码）

## 验证方式

1. 打开添加服务器 → 密码模式：预设下拉可见，选预设后密码框隐藏
2. 切换到密钥模式：密钥路径+私钥内容 textarea 可见，密码区隐藏
3. API 测试 `POST /servers/` 传 `preset_id=2` → 返回 `password_set:true, preset_id:2`
4. API 测试 `POST /servers/` 传 `ssh_key_private` → 返回 `ssh_key_configured:true, ssh_key_private_set:true`
