# 文件管理器 P4/P5 实施说明

## 涉及文件

| 文件 | 变更 |
|------|------|
| `server/application/services/files_browse_service.py` | 新建：SSH 列目录 + ETag 计算 + 服务端 5s 缓存 |
| `server/api/files.py` | 新建：`GET /api/files/browse` + `If-None-Match` → 304 |
| `server/api/sync_v2.py` | `POST /browse` 委托 service（兼容保留） |
| `server/main.py` | 注册 `files_router` |
| `frontend/src/api/index.ts` | `fetchJson`（304/ETag） |
| `frontend/src/stores/files.ts` | 缓存项含 `etag`；`loadingVisible` |
| `frontend/src/composables/files/useFilesBrowse.ts` | GET + 条件请求；loading 防抖 |
| `frontend/src/components/files/FilesList.vue` | 进度条 + 保留旧列表 |
| `tests/test_files_browse_etag.py` | ETag/缓存单测 |

## 步骤

1. 后端抽取 `list_remote_directory`，GET 返回 `ETag` 头。
2. 客户端 `If-None-Match`：304 时沿用 Pinia 缓存项并 `touchCache`。
3. `FilesList`：`loadingVisible`（200ms）+ 不清空 `files`。
4. `pytest tests/test_files_browse_etag.py` + `ruff check server/`。

## 测试要点

- 同一目录 5s 内二次进入：0 次网络（前端 TTL）或 304（etag 仍有效）。
- 快速切换目录：表格不出现「空 → 满」闪烁。
- `POST /api/sync/browse` 仍可用（旧客户端）。

## 回滚

- `git revert` P4/P5 commit；前端改回 `POST /sync/browse` 即可。
