# 审计 — 登录 IP 门禁 + SPA 无感切换

**Changelog**: `docs/changelog/2026-06-08-login-gate-seamless-nav.md`  
**设计**: `docs/design/specs/2026-06-08-login-gate-seamless-nav-design.md`

## 变更文件

**本批次（登录门禁 + 无感切换）**  
`login_allowlist.py` · `auth.py` · `auth_jwt.py` · `auth_service.py` · `LoginPage.vue` · `App.vue` · `cachedPages.ts` · `usePageActivateRefresh.ts` · `useCachedQuery.ts` · `useRoutePrefetch.ts` · `useServerCategories.ts` · `usePushPage.ts` · `usePushLogs.ts` · `useFilesBrowse.ts` · `useFilesNavigation.ts` · 12 页 `*Page.vue` · `tests/test_login_access.py`

**同工作区未提交（服务器排序修复，已审计 `2026-06-08-servers-live-sort-fix`）**  
`server_list_sort.py` · `server_repo.py` · `servers.py` · `useServerPagination.ts` · `DashboardPage.vue` · `ServersPage.vue` · `tests/test_server_list_sort.py` · `web/app/index.html` · `web/app/assets/*`

## Step 3 安全

| 项 | 结论 |
|----|------|
| `GET /api/auth/login-access` 不泄露白名单 | PASS |
| 与 `POST /login` IP 结论一致 | PASS（单测覆盖） |
| 公开路径仅 GET | PASS（`PUBLIC_EXACT_PATHS`） |
| 登出清 query 缓存 | PASS（`clearCachedQueries`） |

## Step 3 架构

| 项 | 结论 |
|----|------|
| keep-alive 排除 Terminal/Login | PASS |
| `max=12` 控内存 | PASS |
| ScriptRuns `watch(params.id)` + `route.name` key | PASS |
| stale-while-revalidate TTL 30s | PASS |

## Closure

- `pytest tests/test_login_access.py` — 7 passed
- `bash scripts/local_verify.sh` — PASS
- `npm run build` — PASS（vue-tsc + vite）
- 门控 — 7/7 PASS
- 生产 — `/health` ok · `/app/` 200（tar+scp 部署，Gitea pull 500 绕过）

## DoD

- [x] P0 三态登录页 + 预检 API
- [x] P1 路由 key + replace + Dashboard 预载
- [x] P2 keep-alive + 12 页 silent 激活刷新
- [x] P3 stats/categories 共享缓存
- [x] P4 侧栏 hover 预取 + Dashboard/Servers 骨架屏
