# Changelog — 登录 IP 白名单订阅刷新多 Worker 同步与保存竞态修复

**日期**：2026-06-11

## 摘要

修复设置页保存订阅 URL 后节点 IP 不立即显示、以及多 uvicorn worker 下各进程白名单内存不一致的问题。保存时同步等待订阅拉取完成并返回新 IP；刷新/保存后通过 Redis `nexus:settings` 广播 `login_*` 键。

## 动机

- 保存后立即 `GET /ip-allowlist` 与异步 `_do_refresh` 竞态，UI 常显示旧/空节点。
- 与 2026-06-08 Telegram 开关同类：仅处理请求的 worker 热更新内存，登录校验读各 worker 本地 `LOGIN_SUBSCRIPTION_IPS`，导致订阅更新后登录时好时坏。

## 涉及文件

- `server/infrastructure/settings_broadcast.py` — 新增 `publish_setting_changes`
- `server/background/ip_allowlist_refresh.py` — `RefreshResult`、`do_refresh`、刷新后广播
- `server/api/settings.py` — 保存/切换/手动 IP 路径 await 刷新并广播；保存响应含 `subscription_ips` / `last_refresh`
- `frontend/src/types/api.ts` — `IpAllowlistSaveResponse`
- `frontend/src/pages/SettingsPage.vue` — 保存后用响应更新节点 chip
- `tests/test_ip_allowlist_sync.py`

## 行为变更

- `POST /settings/ip-allowlist`：有订阅 URL 时**同步**拉取订阅后再返回；响应增加 `subscription_ips`、`last_refresh`、`refresh_ok`、`refresh_error`。
- 白名单相关 settings 变更（含 2h 定时刷新）广播至全部 worker。

## 迁移 / 重启

- 无 DB 迁移。
- 需重启/部署后端以加载新逻辑（settings subscriber 已存在，无需额外配置）。

## 验证

```bash
pytest tests/test_ip_allowlist_sync.py tests/test_notify_toggle_sync.py -q
cd frontend && npm run type-check
```

设置页：填订阅 URL → 解析预览 → 保存 → 节点 chip 与「上次刷新」立即更新；多 worker 下任意 worker 处理登录均使用同一 IP 列表。
