# 2026-06-02 — 文件管理器 P4/P5（REST + ETag + 零闪烁）

## 摘要

- 新增 `GET /api/files/browse?server_id=&path=`，响应 `ETag`；`If-None-Match` 命中时返回 **304**（服务端 5s 缓存可跳过 SSH）。
- 前端浏览改走 GET，Pinia 缓存保存 `etag`；`POST /api/sync/browse` 保留兼容。
- 列表加载：**保留旧文件行** + 表头下 `v-progress-linear`；**200ms** 后才显示 loading（`loadingVisible`）。

## 动机

设计文档 P4/P5：减少重复 SSH、消除进目录时表格先空后满的闪烁。

## 涉及文件

- `server/application/services/files_browse_service.py`
- `server/api/files.py`
- `server/api/sync_v2.py`
- `server/main.py`
- `frontend/src/api/index.ts`
- `frontend/src/stores/files.ts`
- `frontend/src/composables/files/useFilesBrowse.ts`
- `frontend/src/components/files/FilesList.vue`
- `tests/test_files_browse_etag.py`

## 迁移 / 重启

- 需重启 `nexus` Supervisor 进程以加载新 API。
- 前端需重新 `vite build` 并部署（含 `prune_frontend_assets.py`）。

## 验证

```bash
pytest tests/test_files_browse_etag.py -q
ruff check server/
cd frontend && npx vite build
```

浏览器：DevTools 见 `GET /api/files/browse`；重复进入同目录可见 304 或 0 请求（5s 内缓存）。

## 补充（加载失败体验）

- `useFilesBrowse`：HTTP 错误展示后端 `detail`（不再统一「浏览目录失败」）；GET 5xx/404 自动回退 `POST /sync/browse`；304 无本地缓存时强制全量拉取。
- `useFilesNavigation`：权限探测与目录浏览串行，减轻 SSH 连接池争抢。
