diff --git a/deploy/gate_log.jsonl b/deploy/gate_log.jsonl
index 59967f86..f98275cd 100644
--- a/deploy/gate_log.jsonl
+++ b/deploy/gate_log.jsonl
@@ -1547,3 +1547,23 @@
{"ts":"2026-06-10T01:30:56+08:00","date":"2026-06-10","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"}
{"ts":"2026-06-10T01:30:56+08:00","date":"2026-06-10","gate":"text_eol","result":"PASS","detail":"git index LF"}
{"ts":"2026-06-10T01:30:56+08:00","date":"2026-06-10","gate":"summary","result":"PASS","detail":"7/7"}
+{"ts":"2026-06-10T01:38:03+08:00","date":"2026-06-10","gate":"changelog","result":"PASS","detail":"2026-06-10-push-success-sound.md 26lines"}
+{"ts":"2026-06-10T01:38:03+08:00","date":"2026-06-10","gate":"audit","result":"PASS","detail":"2026-06-10-rdp-browser-guacd.md"}
+{"ts":"2026-06-10T01:38:03+08:00","date":"2026-06-10","gate":"test","result":"PASS","detail":"all passed"}
+{"ts":"2026-06-10T01:38:03+08:00","date":"2026-06-10","gate":"lint","result":"PASS","detail":"0 violations"}
+{"ts":"2026-06-10T01:38:03+08:00","date":"2026-06-10","gate":"import","result":"PASS","detail":"ok"}
+{"ts":"2026-06-10T01:38:03+08:00","date":"2026-06-10","gate":"security","result":"PASS","detail":"0 HIGH"}
+{"ts":"2026-06-10T01:38:03+08:00","date":"2026-06-10","gate":"review","result":"BLOCK","detail":"audit missing changed files"}
+{"ts":"2026-06-10T01:38:03+08:00","date":"2026-06-10","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"}
+{"ts":"2026-06-10T01:38:03+08:00","date":"2026-06-10","gate":"text_eol","result":"PASS","detail":"git index LF"}
+{"ts":"2026-06-10T01:38:03+08:00","date":"2026-06-10","gate":"summary","result":"BLOCK","detail":"6/7"}
+{"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"changelog","result":"PASS","detail":"2026-06-10-rdp-hosts-standalone.md 32lines"}
+{"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"audit","result":"PASS","detail":"2026-06-10-rdp-browser-guacd.md"}
+{"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"test","result":"PASS","detail":"all passed"}
+{"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"lint","result":"PASS","detail":"0 violations"}
+{"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"import","result":"PASS","detail":"ok"}
+{"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"security","result":"PASS","detail":"0 HIGH"}
+{"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"review","result":"BLOCK","detail":"audit missing changed files"}
+{"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"}
+{"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"text_eol","result":"PASS","detail":"git index LF"}
+{"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"summary","result":"BLOCK","detail":"6/7"}
diff --git a/docs/audit/2026-06-10-rdp-hosts-standalone.md b/docs/audit/2026-06-10-rdp-hosts-standalone.md
new file mode 100644
index 00000000..9f1042c6
--- /dev/null
+++ b/docs/audit/2026-06-10-rdp-hosts-standalone.md
@@ -0,0 +1,61 @@
+# 审计 — 3389 独立 RDP 主机(rdp_hosts)
+
+**Changelog**: `docs/changelog/2026-06-10-rdp-hosts-standalone.md`
+
+## 变更文件
+
+| 文件 | 说明 |
+|------|------|
+| `server/domain/models/__init__.py` | `RdpHost` 模型 |
+| `server/infrastructure/database/migrations.py` | `rdp_hosts` 表 |
+| `server/infrastructure/database/rdp_host_repo.py` | 仓储 |
+| `server/api/rdp_hosts.py` | CRUD + connect REST |
+| `server/api/rdp.py` | WS `/ws/rdp/hosts/{host_id}` |
+| `server/main.py` | 注册 `rdp_hosts_router` |
+| `frontend/src/pages/RdpPage.vue` | 列表/添加/连接 |
+| `frontend/src/components/rdp/RdpHostFormDialog.vue` | 添加/编辑对话框 |
+| `frontend/src/composables/rdp/useRdpHostList.ts` | 列表与 CUD |
+| `frontend/src/composables/rdp/useRdpSession.ts` | 改连 `rdp_hosts` |
+| `frontend/src/components/servers/ServerFormDialog.vue` | 移除 RDP 区块 |
+| `frontend/src/composables/servers/useServerFormDialog.ts` | 移除 rdp 字段 |
+| `frontend/src/pages/ServersPage.vue` | 移除 RDP 跳转 |
+| `tests/test_rdp_hosts.py` | 模型/端口单测 |
+
+## 入口表
+
+| 方法 | 路径 | 鉴权 | 说明 |
+|------|------|------|------|
+| GET | `/api/rdp/hosts/` | admin JWT | 列表(无密码) |
+| POST | `/api/rdp/hosts/` | admin JWT + 审计 | 创建,密码 Fernet |
+| PUT | `/api/rdp/hosts/{id}` | admin JWT + 审计 | 更新 |
+| DELETE | `/api/rdp/hosts/{id}` | admin JWT + 审计 | 删除 |
+| GET | `/api/rdp/hosts/{id}/connect` | admin JWT | 返回明文密码供 Guacamole |
+| WS | `/ws/rdp/hosts/{id}?token=` | access JWT | guacd 透明桥 |
+
+## Step 3(规则扫描)
+
+| 规则 | 结论 | 说明 |
+|------|------|------|
+| 鉴权 | PASS | 全部 REST/WS 需管理员 JWT |
+| IDOR | PASS(平台模型) | 与终端一致:管理员可连任意 RDP 主机 |
+| 密钥落库 | PASS | `password` 列 Fernet;列表仅 `password_set` |
+| 明文 connect | RISK 接受 | Guacamole 客户端必需;HTTPS |
+| CUD 审计 | PASS | create/update/delete_rdp_host |
+| guacd | PASS | 仍仅内网侧车 |
+| 静默吞错 | PASS | API HTTPException;WS close code |
+
+## Closure(走读)
+
+| 文件 | 结论 |
+|------|------|
+| `rdp_hosts.py` | SAFE — 名称唯一 IntegrityError→409;connect 校验 guacd |
+| `rdp_host_repo.py` | SAFE — 标准 CRUD |
+| `rdp.py` | SAFE — host 存在性校验后桥接 |
+| `RdpPage.vue` | SAFE — 无 v-html;添加后 `host_id` 连接 |
+| `useRdpHostList.ts` | SAFE — formatApiError |
+
+## DoD
+
+- [x] changelog + 本审计
+- [x] `local_verify` + type-check
+- [ ] 生产部署与浏览器验收
diff --git a/docs/changelog/2026-06-10-rdp-hosts-standalone.md b/docs/changelog/2026-06-10-rdp-hosts-standalone.md
new file mode 100644
index 00000000..0904b3db
--- /dev/null
+++ b/docs/changelog/2026-06-10-rdp-hosts-standalone.md
@@ -0,0 +1,32 @@
+# 2026-06-10 — 3389 独立 RDP 主机管理
+
+## 摘要
+
+RDP 远程桌面改为在「3389远程」页单独添加/管理,不再依赖子机列表或服务器编辑表单。
+
+## 动机
+
+3389 目标数量少、与 SSH 子机资产无关;用户希望在 RDP 页直接录入地址与凭据后点击连接。
+
+## 涉及文件
+
+- `server/domain/models/__init__.py` — `rdp_hosts` 表
+- `server/infrastructure/database/migrations.py`
+- `server/infrastructure/database/rdp_host_repo.py`
+- `server/api/rdp_hosts.py` — CRUD + connect
+- `server/api/rdp.py` — WS `/ws/rdp/hosts/{id}`
+- `frontend/src/pages/RdpPage.vue` — 列表、添加、连接
+- `frontend/src/components/rdp/RdpHostFormDialog.vue`
+- `frontend/src/composables/rdp/useRdpHostList.ts`
+- 移除服务器表单与子机页 RDP 入口
+
+## 行为
+
+- `GET/POST/PUT/DELETE /api/rdp/hosts/` 管理独立 RDP 主机
+- 添加成功后自动跳转连接;列表项可「连接 / 编辑 / 删除」
+- 密码 Fernet 加密存储;connect 接口仅管理员 JWT
+
+## 验证
+
+- `pytest tests/test_rdp_hosts.py`
+- 3389远程 → 添加 → 连接 Windows RDP
diff --git a/frontend/src/components/rdp/RdpHostFormDialog.vue b/frontend/src/components/rdp/RdpHostFormDialog.vue
new file mode 100644
index 00000000..31a5032d
--- /dev/null
+++ b/frontend/src/components/rdp/RdpHostFormDialog.vue
@@ -0,0 +1,115 @@
+
+
选择已启用 RDP 的服务器
-- 未出现在列表?请在「服务器 → 编辑 → 高级选项」启用浏览器远程桌面并填写 RDP 密码。 -
+{{ status === 'loading' ? '加载连接参数…' : '正在连接远程桌面…' }}
@@ -59,18 +92,44 @@=e.x&&t<=e.x+e.width&&n>=e.y&&n<=e.y+e.height},e.prototype.contain=function(t,n){return e.contain(this,t,n)},e.prototype.clone=function(){return new e(this.x,this.y,this.width,this.height)},e.prototype.copy=function(e){En(this,e)},e.prototype.plain=function(){return{x:this.x,y:this.y,width:this.width,height:this.height}},e.prototype.isFinite=function(){return isFinite(this.x)&&isFinite(this.y)&&isFinite(this.width)&&isFinite(this.height)},e.prototype.isZero=function(){return this.width===0||this.height===0},e.create=function(t){return new e(t?t.x:0,t?t.y:0,t?t.width:0,t?t.height:0)},e.copy=function(e,t){return e.x=t.x,e.y=t.y,e.width=t.width,e.height=t.height,e},e.applyTransform=function(e,t,n){if(!n){e!==t&&En(e,t);return}if(n[1]<1e-5&&n[1]>-1e-5&&n[2]<1e-5&&n[2]>-1e-5){var r=n[0],i=n[3],a=n[4],o=n[5];e.x=t.x*r+a,e.y=t.y*i+o,e.width=t.width*r,e.height=t.height*i,e.width<0&&(e.x+=e.width,e.width=-e.width),e.height<0&&(e.y+=e.height,e.height=-e.height);return}gn.x=vn.x=t.x,gn.y=yn.y=t.y,_n.x=yn.x=t.x+t.width,_n.y=vn.y=t.y+t.height,gn.transform(n),yn.transform(n),_n.transform(n),vn.transform(n),e.x=dn(gn.x,_n.x,vn.x,yn.x),e.y=dn(gn.y,_n.y,vn.y,yn.y);var s=fn(gn.x,_n.x,vn.x,yn.x),c=fn(gn.y,_n.y,vn.y,yn.y);e.width=s-e.x,e.height=c-e.y},e.calculateTransform=function(e,t,n){var r=n.width/t.width,i=n.height/t.height;return e=nn(e||[]),on(e,e,ct(Mn,-t.x,-t.y)),cn(e,e,ct(Mn,r,i)),on(e,e,ct(Mn,n.x,n.y)),e},e}(),wn=Y.create,Tn=Y.set,En=Y.copy,Dn=Y.calculateTransform,On=Y.applyTransform,kn=Y.contain,An=new Y(0,0,0,0),jn=new Y(0,0,0,0),Mn=[];function Nn(e,t,n,r,i,a,o,s){var c=pn(t-n),l=pn(r-e),u=dn(c,l),d=mn[i],f=mn[1-i],p=hn[i];t =0&&g =0&&l<=1&&(i[c++]=l)}}else{var u=o*o-4*a*s;if(_r(u)){var l=-o/(2*a);l>=0&&l<=1&&(i[c++]=l)}else if(u>0){var d=lr(u),l=(-o+d)/(2*a),f=(-o-d)/(2*a);l>=0&&l<=1&&(i[c++]=l),f>=0&&f<=1&&(i[c++]=f)}}return c}function kr(e,t,n){var r=e+n-2*t;return r===0?.5:(e-t)/r}function Ar(e,t,n,r,i){var a=(t-e)*r+e,o=(n-t)*r+t,s=(o-a)*r+a;i[0]=e,i[1]=a,i[2]=s,i[3]=s,i[4]=o,i[5]=n}function jr(e,t,n,r,i,a,o,s,c){var l,u=.005,d=1/0;mr[0]=o,mr[1]=s;for(var f=0;f<1;f+=.05){hr[0]=Er(e,n,i,f),hr[1]=Er(t,r,a,f);var p=vt(mr,hr);p =e.x&&t<=e.x+e.width&&n>=e.y&&n<=e.y+e.height},e.prototype.contain=function(t,n){return e.contain(this,t,n)},e.prototype.clone=function(){return new e(this.x,this.y,this.width,this.height)},e.prototype.copy=function(e){En(this,e)},e.prototype.plain=function(){return{x:this.x,y:this.y,width:this.width,height:this.height}},e.prototype.isFinite=function(){return isFinite(this.x)&&isFinite(this.y)&&isFinite(this.width)&&isFinite(this.height)},e.prototype.isZero=function(){return this.width===0||this.height===0},e.create=function(t){return new e(t?t.x:0,t?t.y:0,t?t.width:0,t?t.height:0)},e.copy=function(e,t){return e.x=t.x,e.y=t.y,e.width=t.width,e.height=t.height,e},e.applyTransform=function(e,t,n){if(!n){e!==t&&En(e,t);return}if(n[1]<1e-5&&n[1]>-1e-5&&n[2]<1e-5&&n[2]>-1e-5){var r=n[0],i=n[3],a=n[4],o=n[5];e.x=t.x*r+a,e.y=t.y*i+o,e.width=t.width*r,e.height=t.height*i,e.width<0&&(e.x+=e.width,e.width=-e.width),e.height<0&&(e.y+=e.height,e.height=-e.height);return}gn.x=vn.x=t.x,gn.y=yn.y=t.y,_n.x=yn.x=t.x+t.width,_n.y=vn.y=t.y+t.height,gn.transform(n),yn.transform(n),_n.transform(n),vn.transform(n),e.x=dn(gn.x,_n.x,vn.x,yn.x),e.y=dn(gn.y,_n.y,vn.y,yn.y);var s=fn(gn.x,_n.x,vn.x,yn.x),c=fn(gn.y,_n.y,vn.y,yn.y);e.width=s-e.x,e.height=c-e.y},e.calculateTransform=function(e,t,n){var r=n.width/t.width,i=n.height/t.height;return e=nn(e||[]),on(e,e,ct(Mn,-t.x,-t.y)),cn(e,e,ct(Mn,r,i)),on(e,e,ct(Mn,n.x,n.y)),e},e}(),wn=Y.create,Tn=Y.set,En=Y.copy,Dn=Y.calculateTransform,On=Y.applyTransform,kn=Y.contain,An=new Y(0,0,0,0),jn=new Y(0,0,0,0),Mn=[];function Nn(e,t,n,r,i,a,o,s){var c=pn(t-n),l=pn(r-e),u=dn(c,l),d=mn[i],f=mn[1-i],p=hn[i];t =0&&g =0&&l<=1&&(i[c++]=l)}}else{var u=o*o-4*a*s;if(_r(u)){var l=-o/(2*a);l>=0&&l<=1&&(i[c++]=l)}else if(u>0){var d=lr(u),l=(-o+d)/(2*a),f=(-o-d)/(2*a);l>=0&&l<=1&&(i[c++]=l),f>=0&&f<=1&&(i[c++]=f)}}return c}function kr(e,t,n){var r=e+n-2*t;return r===0?.5:(e-t)/r}function Ar(e,t,n,r,i){var a=(t-e)*r+e,o=(n-t)*r+t,s=(o-a)*r+a;i[0]=e,i[1]=a,i[2]=s,i[3]=s,i[4]=o,i[5]=n}function jr(e,t,n,r,i,a,o,s,c){var l,u=.005,d=1/0;mr[0]=o,mr[1]=s;for(var f=0;f<1;f+=.05){hr[0]=Er(e,n,i,f),hr[1]=Er(t,r,a,f);var p=vt(mr,hr);p4)return;this._downPoint=null}this.dispatchToElement(a,e,t)}});function Un(e,t,n){if(e[e.rectHover?`rectContain`:`contain`](t,n)){for(var r=e,i=void 0,a=!1;r;){if(r.ignoreClip&&(a=!0),!a){var o=r.getClipPath();if(o&&!o.contain(t,n))return!1}r.silent&&(i=!0);var s=r.__hostTarget;r=s?r.ignoreHostSilent?null:s:r.parent}return i?Fn:!0}return!1}function Wn(e,t,n,r,i){for(var a=e.length-1;a>=0;a--){var o=e[a],s=void 0;if(o!==i&&!o.ignore&&(s=Un(o,n,r))&&(!t.topTarget&&(t.topTarget=o),s!==Fn)){t.target=o;break}}}function Gn(e,t,n){var r=e.painter;return t<0||t>r.getWidth()||n<0||n>r.getHeight()}var Kn=32,qn=7;function Jn(e){for(var t=0;e>=Kn;)t|=e&1,e>>=1;return e+t}function Yn(e,t,n,r){var i=t+1;if(i===n)return 1;if(r(e[i++],e[t])<0){for(;i0;)o=c,c=(c<<1)+1,c<=0&&(c=s);c>s&&(c=s),o+=i,c+=i}else{for(s=i+1;cs&&(c=s);var l=o;o=i-c,c=i-l}for(o++;os&&(c=s);var l=o;o=i-c,c=i-l}else{for(s=r-i;c=0;)o=c,c=(c<<1)+1,c<=0&&(c=s);c>s&&(c=s),o+=i,c+=i}for(o++;o=0;c--)e[p+c]=e[f+c];e[d]=o[u];return}for(var m=n;;){var h=0,g=0,_=!1;do if(t(o[u],e[l])<0){if(e[d--]=e[l--],h++,g=0,--i===0){_=!0;break}}else if(e[d--]=o[u--],g++,h=0,--s===1){_=!0;break}while((h|g)s&&(c=s),Zn(e,n,n+c,n+a,t),a=c}o.pushRun(n,a),o.mergeRuns(),i-=a,n+=a}while(i!==0);o.forceMergeRuns()}}var nr=!1;function rr(){nr||(nr=!0,console.warn(`z / z2 / zlevel of displayable is invalid, which may cause unexpected errors`))}function ir(e,t){return e.zlevel===t.zlevel?e.z===t.z?e.z2-t.z2:e.z-t.z:e.zlevel-t.zlevel}var ar=function(){function e(){this._roots=[],this._displayList=[],this._displayListLen=0,this.displayableSortFunc=ir}return e.prototype.traverse=function(e,t){for(var n=0;n4)return;this._downPoint=null}this.dispatchToElement(a,e,t)}});function Un(e,t,n){if(e[e.rectHover?`rectContain`:`contain`](t,n)){for(var r=e,i=void 0,a=!1;r;){if(r.ignoreClip&&(a=!0),!a){var o=r.getClipPath();if(o&&!o.contain(t,n))return!1}r.silent&&(i=!0);var s=r.__hostTarget;r=s?r.ignoreHostSilent?null:s:r.parent}return i?Fn:!0}return!1}function Wn(e,t,n,r,i){for(var a=e.length-1;a>=0;a--){var o=e[a],s=void 0;if(o!==i&&!o.ignore&&(s=Un(o,n,r))&&(!t.topTarget&&(t.topTarget=o),s!==Fn)){t.target=o;break}}}function Gn(e,t,n){var r=e.painter;return t<0||t>r.getWidth()||n<0||n>r.getHeight()}var Kn=32,qn=7;function Jn(e){for(var t=0;e>=Kn;)t|=e&1,e>>=1;return e+t}function Yn(e,t,n,r){var i=t+1;if(i===n)return 1;if(r(e[i++],e[t])<0){for(;i0;)o=c,c=(c<<1)+1,c<=0&&(c=s);c>s&&(c=s),o+=i,c+=i}else{for(s=i+1;cs&&(c=s);var l=o;o=i-c,c=i-l}for(o++;os&&(c=s);var l=o;o=i-c,c=i-l}else{for(s=r-i;c=0;)o=c,c=(c<<1)+1,c<=0&&(c=s);c>s&&(c=s),o+=i,c+=i}for(o++;o=0;c--)e[p+c]=e[f+c];e[d]=o[u];return}for(var m=n;;){var h=0,g=0,_=!1;do if(t(o[u],e[l])<0){if(e[d--]=e[l--],h++,g=0,--i===0){_=!0;break}}else if(e[d--]=o[u--],g++,h=0,--s===1){_=!0;break}while((h|g)s&&(c=s),Zn(e,n,n+c,n+a,t),a=c}o.pushRun(n,a),o.mergeRuns(),i-=a,n+=a}while(i!==0);o.forceMergeRuns()}}var nr=!1;function rr(){nr||(nr=!0,console.warn(`z / z2 / zlevel of displayable is invalid, which may cause unexpected errors`))}function ir(e,t){return e.zlevel===t.zlevel?e.z===t.z?e.z2-t.z2:e.z-t.z:e.zlevel-t.zlevel}var ar=function(){function e(){this._roots=[],this._displayList=[],this._displayListLen=0,this.displayableSortFunc=ir}return e.prototype.traverse=function(e,t){for(var n=0;n