添加快传7天离线传

This commit is contained in:
yoyuzh
2026-03-24 09:12:10 +08:00
parent e004e64009
commit b9ab1a7640
32 changed files with 1927 additions and 81 deletions

350
docs/api-reference.md Normal file
View File

@@ -0,0 +1,350 @@
# API 接口文档
本文档用于快速了解 `yoyuzh.xyz` 当前后端 API 的职责、鉴权方式和主要接口分组。
## 1. 基本约定
### 基础路径
- 后端接口统一以 `/api` 开头
- 本地开发默认地址:`http://localhost:8080`
### 返回格式
大部分接口返回统一结构:
```json
{
"code": 0,
"msg": "success",
"data": {}
}
```
常见含义:
- `code = 0`:成功
- `code = 1000`:参数校验失败
- `code = 1001`:未登录
- `code = 1002`:权限不足
- `code = 1003`:业务对象不存在、邀请码错误、取件码失效等业务失败
### 鉴权方式
- 采用 `Authorization: Bearer <accessToken>`
- `refreshToken` 通过 `/api/auth/refresh` 换取新的登录态
- 当前实现为“单账号单设备在线”
- 新设备登录后,旧设备的 access token 会失效
### 权限分层
- 公开接口:
- `/api/auth/**`
- `/api/transfer/**`
- `GET /api/files/share-links/{token}`
- 登录后接口:
- `/api/user/**`
- `/api/files/**`
- `/api/admin/**`
## 2. 认证模块
控制器:
- `backend/src/main/java/com/yoyuzh/auth/AuthController.java`
- `backend/src/main/java/com/yoyuzh/auth/DevAuthController.java`
- `backend/src/main/java/com/yoyuzh/auth/UserController.java`
### 2.1 注册
`POST /api/auth/register`
说明:
- 使用邀请码注册
- 注册成功后直接返回登录态
- 邀请码成功使用后会自动刷新
请求重点字段:
- `username`
- `email`
- `phoneNumber`
- `password`
- `confirmPassword`
- `inviteCode`
### 2.2 登录
`POST /api/auth/login`
请求字段:
- `username`
- `password`
返回字段:
- `token`
- `accessToken`
- `refreshToken`
- `user`
### 2.3 刷新登录态
`POST /api/auth/refresh`
请求字段:
- `refreshToken`
说明:
- 刷新后会返回新的 access token 与 refresh token
- 当前系统会让旧 refresh token 失效
### 2.4 开发环境登录
`POST /api/auth/dev-login`
说明:
- 仅用于开发联调
- 是否可用取决于当前环境配置
### 2.5 获取用户资料
`GET /api/user/profile`
### 2.6 更新用户资料
`PUT /api/user/profile`
### 2.7 修改密码
`POST /api/user/password`
说明:
- 成功后会重新签发新的登录态
- 同时会顶掉旧设备会话
### 2.8 头像相关
- `POST /api/user/avatar/upload/initiate`
- `POST /api/user/avatar/upload`
- `POST /api/user/avatar/upload/complete`
- `GET /api/user/avatar/content`
说明:
- 支持初始化直传
- 支持代理上传
- 最终通过完成接口落库
## 3. 网盘模块
控制器:
- `backend/src/main/java/com/yoyuzh/files/FileController.java`
### 3.1 上传相关
- `POST /api/files/upload`
- `POST /api/files/upload/initiate`
- `POST /api/files/upload/complete`
说明:
- 兼容普通上传和 OSS 直传
- 前端会优先尝试“初始化上传 -> 直传/代理 -> 完成上传”
### 3.2 目录与列表
- `POST /api/files/mkdir`
- `GET /api/files/list`
- `GET /api/files/recent`
说明:
- `list` 支持 `path``page``size`
- 当前前端会在网盘页缓存目录内容和最后访问路径
### 3.3 下载
- `GET /api/files/download/{fileId}`
- `GET /api/files/download/{fileId}/url`
说明:
- 普通文件优先获取下载 URL
- 文件夹可走 ZIP 下载
### 3.4 文件操作
- `PATCH /api/files/{fileId}/rename`
- `PATCH /api/files/{fileId}/move`
- `POST /api/files/{fileId}/copy`
- `DELETE /api/files/{fileId}`
说明:
- `move` 用于移动到目标路径
- `copy` 用于复制到目标路径
- 文件和文件夹都支持移动 / 复制
### 3.5 分享链接
- `POST /api/files/{fileId}/share-links`
- `GET /api/files/share-links/{token}`
- `POST /api/files/share-links/{token}/import`
说明:
- 已登录用户可为自己的文件或文件夹创建分享链接
- 公开访客可查看分享详情
- 登录用户可将分享内容导入自己的网盘
## 4. 快传模块
控制器:
- `backend/src/main/java/com/yoyuzh/transfer/TransferController.java`
### 4.1 创建会话
`POST /api/transfer/sessions`
说明:
- 创建快传会话需要发送端登录
- 请求体必须区分 `mode`
- `ONLINE`: 在线快传15 分钟有效,只能被接收一次
- `OFFLINE`: 离线快传7 天有效,文件会落到站点存储并可被重复接收
- 返回会话 ID、取件码、模式、过期时间和文件清单
### 4.2 通过取件码查找会话
`GET /api/transfer/sessions/lookup?pickupCode=xxxxxx`
说明:
- 接收端通过 6 位取件码查找会话
### 4.3 加入会话
`POST /api/transfer/sessions/{sessionId}/join`
说明:
- 在线快传会占用一次性会话
- 离线快传返回可下载文件清单,不需要建立 P2P 通道
### 4.4 信令交换
- `POST /api/transfer/sessions/{sessionId}/signals`
- `GET /api/transfer/sessions/{sessionId}/signals`
说明:
- 后端负责 WebRTC 信令交换
- 文件内容本身不经过后端
- 实际文件通过浏览器 DataChannel 进行 P2P 传输
- 该组接口仅用于 `ONLINE` 模式
### 4.5 上传离线快传文件
`POST /api/transfer/sessions/{sessionId}/files/{fileId}/content`
说明:
- 需要发送端登录
- 发送端把离线文件内容上传到站点存储
- 线上环境会把离线文件落到 OSS
### 4.6 下载离线快传文件
`GET /api/transfer/sessions/{sessionId}/files/{fileId}/download`
说明:
- 公开接口
- 离线文件在有效期内可以被重复下载
### 4.7 存入网盘
`POST /api/transfer/sessions/{sessionId}/files/{fileId}/import`
说明:
- 需要登录
- 把离线快传文件导入到当前用户网盘
## 5. 管理台模块
控制器:
- `backend/src/main/java/com/yoyuzh/admin/AdminController.java`
### 5.1 总览
`GET /api/admin/summary`
返回内容包括:
- 用户总数
- 文件总数
- 当前邀请码
### 5.2 用户管理
- `GET /api/admin/users`
- `PATCH /api/admin/users/{userId}/role`
- `PATCH /api/admin/users/{userId}/status`
- `PUT /api/admin/users/{userId}/password`
- `POST /api/admin/users/{userId}/password/reset`
说明:
- 可调整用户角色
- 可封禁用户
- 可重置或直接设置密码
- 封禁/改密会使原登录态失效
### 5.3 文件管理
- `GET /api/admin/files`
- `DELETE /api/admin/files/{fileId}`
## 6. 前端公开路由与接口关系
前端入口在:
- `front/src/App.tsx`
主要页面:
- `/login`
- `/overview`
- `/files`
- `/transfer`
- `/share/:token`
- `/admin/*`
接口关系:
- 登录页:调用 `/api/auth/login``/api/auth/register`
- 网盘页:调用 `/api/files/**`
- 快传页:调用 `/api/transfer/**`
- 分享页:调用 `/api/files/share-links/{token}` 和导入接口
- 管理台:调用 `/api/admin/**`
## 7. 建议阅读顺序
后续新窗口如果要接手后端功能,建议按这个顺序看:
1. `memory.md`
2. `docs/architecture.md`
3. `docs/api-reference.md`
4. `backend/src/main/java/com/yoyuzh/config/SecurityConfig.java`
5. 对应业务模块的 `Controller + Service`

340
docs/architecture.md Normal file
View File

@@ -0,0 +1,340 @@
# 架构文档
本文档用于描述 `yoyuzh.xyz` 当前的系统结构、模块边界、关键流程和部署方式,便于后续窗口快速建立整体上下文。
## 1. 系统概览
项目是一个前后端分离的全栈站点,核心由三部分组成:
1. React 前端站点
2. Spring Boot 后端 API
3. 文件存储层(本地文件系统或 OSS
业务主线已经从旧教务方向切换为:
- 账号系统
- 个人网盘
- 快传
- 管理台
## 2. 仓库结构与职责
### 2.1 前端
路径:
- `front/`
核心职责:
- 页面路由与交互
- 登录态管理
- 网盘 UI 与缓存
- 快传发/收流程
- 管理台前端
- 生产环境 API 基址拼装与调用
关键入口:
- `front/src/App.tsx`
- `front/src/lib/api.ts`
- `front/src/components/layout/Layout.tsx`
主要页面:
- `front/src/pages/Login.tsx`
- `front/src/pages/Overview.tsx`
- `front/src/pages/Files.tsx`
- `front/src/pages/Transfer.tsx`
- `front/src/pages/TransferReceive.tsx`
- `front/src/pages/FileShare.tsx`
### 2.2 后端
路径:
- `backend/`
核心职责:
- 认证与 JWT 鉴权
- 网盘元数据与文件流转
- 快传信令与会话状态
- 管理台 API
- OSS / 本地存储抽象
后端包结构:
- `com.yoyuzh.auth`
- `com.yoyuzh.files`
- `com.yoyuzh.transfer`
- `com.yoyuzh.admin`
- `com.yoyuzh.config`
- `com.yoyuzh.common`
启动类:
- `backend/src/main/java/com/yoyuzh/PortalBackendApplication.java`
### 2.3 文档与脚本
- `docs/`: 实现计划与补充文档
- `scripts/`: 前端 OSS 发布、存储迁移和本地辅助脚本
## 3. 模块划分
### 3.1 认证模块
核心文件:
- `backend/src/main/java/com/yoyuzh/auth/AuthController.java`
- `backend/src/main/java/com/yoyuzh/auth/AuthService.java`
- `backend/src/main/java/com/yoyuzh/auth/JwtTokenProvider.java`
- `backend/src/main/java/com/yoyuzh/config/JwtAuthenticationFilter.java`
- `backend/src/main/java/com/yoyuzh/auth/RefreshTokenService.java`
职责:
- 注册、登录、刷新登录态
- 用户资料查询和修改
- 头像上传
- 单设备登录控制
- 邀请码消费与轮换
关键实现说明:
- access token 使用 JWT
- refresh token 持久化到数据库
- 当前会话通过 `activeSessionId + JWT sid claim` 绑定
- 新登录会挤掉旧设备
### 3.2 网盘模块
核心文件:
- `backend/src/main/java/com/yoyuzh/files/FileController.java`
- `backend/src/main/java/com/yoyuzh/files/FileService.java`
- `backend/src/main/java/com/yoyuzh/files/storage/*`
- `front/src/pages/Files.tsx`
职责:
- 文件/文件夹上传、下载、删除、重命名
- 目录创建与分页列表
- 移动、复制
- 分享链接与导入
- 前端树状目录导航
关键实现说明:
- 文件元数据在数据库
- 文件内容走存储层抽象
- 支持本地磁盘和 OSS
- 前端会缓存目录列表和最后访问路径
### 3.3 快传模块
核心文件:
- `backend/src/main/java/com/yoyuzh/transfer/TransferController.java`
- `backend/src/main/java/com/yoyuzh/transfer/TransferService.java`
- `backend/src/main/java/com/yoyuzh/transfer/TransferSession.java`
- `front/src/pages/Transfer.tsx`
- `front/src/pages/TransferReceive.tsx`
- `front/src/lib/transfer-runtime.ts`
- `front/src/lib/transfer-protocol.ts`
职责:
- 创建快传会话
- 生成取件码与分享链接
- WebRTC 信令交换
- 浏览器端文件发送与接收
- 接收后下载或存入网盘
关键实现说明:
- 后端只做信令和会话状态,不中转文件内容
- 文件内容走浏览器 DataChannel
- 接收端支持部分文件选择
- 多文件或文件夹可走 ZIP 下载
- 在线快传是一次性浏览器 P2P 传输,首个接收者进入后即占用该会话
- 离线快传会把文件内容落到站点存储,线上环境使用 OSS默认保留 7 天并支持重复接收
### 3.4 管理台模块
核心文件:
- `backend/src/main/java/com/yoyuzh/admin/AdminController.java`
- `backend/src/main/java/com/yoyuzh/admin/AdminService.java`
- `front/src/admin/*`
职责:
- 管理用户
- 管理文件
- 查看邀请码
关键实现说明:
- 管理台依赖后端 summary/users/files 接口
- 当前邀请码由后端返回给管理台展示
## 4. 关键业务流程
### 4.1 登录流程
1. 前端登录页调用 `/api/auth/login`
2. 后端鉴权成功后签发 access token + refresh token
3. 后端刷新 `activeSessionId`
4. 前端本地存储 `portal-session`
5. 后续请求通过 `Authorization: Bearer <token>` 访问
6. JWT 过滤器校验 token、用户状态和会话 ID 是否仍匹配
补充说明:
- 前端生产构建当前仍会把 API 基址固化为 `https://api.yoyuzh.xyz/api`
- 因此前端登录、刷新、受保护接口访问都依赖 `api.yoyuzh.xyz` 这条独立 API 子域名链路
- 若该子域名在某些网络环境下 TLS/SNI 不稳定,前端会直接表现为“网络异常”或“登录失败”
### 4.2 邀请码注册流程
1. 用户提交注册信息与邀请码
2. 后端验证用户名、邮箱、手机号唯一性
3. 邀请码服务校验当前邀请码
4. 注册成功后自动轮换邀请码
5. 返回登录态
### 4.3 网盘上传流程
1. 前端在 `Files` 页面选择文件或文件夹
2. 前端优先调用 `/api/files/upload/initiate`
3. 如果存储支持直传,则浏览器直接上传到 OSS
4. 前端再调用 `/api/files/upload/complete`
5. 如果直传失败,会回退到代理上传接口 `/api/files/upload`
### 4.4 文件分享流程
1. 登录用户创建分享链接
2. 后端生成 token
3. 公开用户通过 `/share/:token` 查看详情
4. 登录用户可以导入到自己的网盘
### 4.5 快传流程
1. 发送端登录后创建快传会话
2. 若是在线模式,后端返回 `sessionId + pickupCode` 并保留 15 分钟的一次性会话
3. 接收端通过取件码或分享链接加入在线会话
4. 双方通过 `/api/transfer/.../signals` 交换 offer / answer / ice
5. DataChannel 建立后传输文件内容
6. 接收端可直接下载或存入网盘
### 4.6 离线快传流程
1. 发送端登录后创建离线快传会话
2. 后端生成 `sessionId + pickupCode`,并为每个文件创建离线存储槽位
3. 发送端把文件上传到站点存储
4. 上传完成后,会话变为可接收状态并保留 7 天
5. 接收端通过取件码或分享链接打开会话
6. 接收端可直接下载离线文件,也可登录后存入网盘
7. 文件在有效期内不会因一次接收而被删除,过期后由后端清理任务自动销毁
## 5. 前端路由架构
路由入口:
- `front/src/App.tsx`
主要路由:
- `/login`
- `/overview`
- `/files`
- `/transfer`
- `/share/:token`
- `/admin/*`
说明:
- `/transfer` 同时承担发送端和接收端入口
- `/share/:token` 是公开文件分享页
- `/admin/*` 为懒加载管理台
## 6. 安全模型
### 6.1 访问控制
`SecurityConfig` 控制:
- `/api/auth/**` 公开
- `/api/transfer/**` 公开
- `GET /api/files/share-links/{token}` 公开
- `/api/files/**``/api/user/**``/api/admin/**` 需登录
### 6.2 单设备登录
当前实现不是只撤销 refresh token而是同时控制 access token
- 用户表记录 `activeSessionId`
- JWT 里包含 `sid`
- 过滤器每次请求都会比对当前用户的 `activeSessionId`
- 新登录成功后,旧设备 token 会失效
## 7. 存储架构
抽象层:
- `backend/src/main/java/com/yoyuzh/files/storage/FileContentStorage.java`
实现方向:
- 本地文件系统
- OSS
设计目的:
- 让文件元数据逻辑与底层存储解耦
- 上传、下载、复制、移动都通过统一抽象收口
## 8. 部署架构
### 8.1 前端
- 构建工具Vite
- 发布方式OSS 静态资源发布
- 发布脚本:`node scripts/deploy-front-oss.mjs`
### 8.2 后端
- 打包方式:`mvn package`
- 产物:`backend/target/yoyuzh-portal-backend-0.0.1-SNAPSHOT.jar`
- 线上通常采用 jar + systemd 方式运行
当前已知线上信息:
- 服务名:`my-site-api.service`
- 运行包路径:`/opt/yoyuzh/yoyuzh-portal-backend.jar`
## 9. 开发注意事项
- 仓库根目录没有 `package.json`,不要在根目录执行 `npm`
- 前端命令只从 `front/package.json` 读取
- 后端命令只从 `backend/pom.xml` 读取
- 前端 `npm run lint` 实际是 `tsc --noEmit`
- 后端没有单独 lint 命令
- 本仓库大量使用 LombokVS Code 若出现“final 字段未初始化”之类误报,优先检查 Lombok 扩展、Java Language Server 和 annotation processor
## 10. 新窗口建议阅读顺序
后续新窗口进入仓库时,建议顺序:
1. `memory.md`
2. `docs/architecture.md`
3. `docs/api-reference.md`
4. `AGENTS.md`
如果要继续某个具体功能,再进入对应模块的:
- 前端页面文件
- 后端 Controller / Service
- 紧邻测试文件

View File

@@ -0,0 +1,94 @@
# Transfer Online Offline Mode Implementation Plan
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Distinguish quick transfer online and offline sending so online stays one-time P2P, while offline persists files for 7 days in storage and can be received repeatedly.
**Architecture:** Keep the current in-memory WebRTC signaling flow for online transfers and add a persistent offline transfer path in the backend. Offline transfers store file metadata plus storage references, expose repeatable public download/import behavior, and let the frontend branch between P2P receive and offline download based on the transfer mode returned by the API.
**Tech Stack:** Spring Boot 3.3.8, Java 17, JPA/H2 tests, Vite 6, React 19, TypeScript, existing OSS/local storage abstraction
---
### Task 1: Plan the transfer domain split
**Files:**
- Modify: `backend/src/main/java/com/yoyuzh/transfer/CreateTransferSessionRequest.java`
- Modify: `backend/src/main/java/com/yoyuzh/transfer/TransferSessionResponse.java`
- Modify: `backend/src/main/java/com/yoyuzh/transfer/LookupTransferSessionResponse.java`
- Create: `backend/src/main/java/com/yoyuzh/transfer/TransferMode.java`
- Create: `backend/src/main/java/com/yoyuzh/transfer/OfflineTransfer*`
- [ ] **Step 1: Write the failing backend tests for mode-aware session responses**
- [ ] **Step 2: Run `cd backend && mvn test -Dtest=TransferSessionTest,TransferControllerIntegrationTest` and verify the new assertions fail for missing mode-aware behavior**
- [ ] **Step 3: Add the minimal transfer mode types, request fields, and response fields**
- [ ] **Step 4: Run the same Maven test command and verify the new mode assertions pass**
### Task 2: Add offline transfer storage and repeatable receive flow
**Files:**
- Modify: `backend/src/main/java/com/yoyuzh/files/storage/FileContentStorage.java`
- Modify: `backend/src/main/java/com/yoyuzh/files/storage/LocalFileContentStorage.java`
- Modify: `backend/src/main/java/com/yoyuzh/files/storage/OssFileContentStorage.java`
- Modify: `backend/src/main/java/com/yoyuzh/transfer/TransferController.java`
- Modify: `backend/src/main/java/com/yoyuzh/transfer/TransferService.java`
- Create: `backend/src/main/java/com/yoyuzh/transfer/OfflineTransfer*.java`
- Test: `backend/src/test/java/com/yoyuzh/transfer/TransferControllerIntegrationTest.java`
- [ ] **Step 1: Write failing integration tests for offline create, upload, lookup, repeatable receive, and 7-day expiry metadata**
- [ ] **Step 2: Run `cd backend && mvn test -Dtest=TransferControllerIntegrationTest` and verify the offline scenarios fail for the expected missing endpoints/fields**
- [ ] **Step 3: Implement the minimal persistent offline transfer entities, repositories, service methods, and public download/import endpoints**
- [ ] **Step 4: Run `cd backend && mvn test -Dtest=TransferControllerIntegrationTest` and verify the offline scenarios pass**
### Task 3: Keep online transfers one-time
**Files:**
- Modify: `backend/src/main/java/com/yoyuzh/transfer/TransferSession.java`
- Modify: `backend/src/main/java/com/yoyuzh/transfer/TransferService.java`
- Test: `backend/src/test/java/com/yoyuzh/transfer/TransferSessionTest.java`
- [ ] **Step 1: Write the failing test that a second online receiver cannot join/re-receive**
- [ ] **Step 2: Run `cd backend && mvn test -Dtest=TransferSessionTest` and verify it fails for the current reusable online session behavior**
- [ ] **Step 3: Implement the minimal online single-receive guard**
- [ ] **Step 4: Run `cd backend && mvn test -Dtest=TransferSessionTest` and verify it passes**
### Task 4: Add frontend mode-aware API helpers and state
**Files:**
- Modify: `front/src/lib/types.ts`
- Modify: `front/src/lib/transfer.ts`
- Modify: `front/src/pages/transfer-state.ts`
- Test: `front/src/pages/transfer-state.test.ts`
- [ ] **Step 1: Write failing frontend tests for transfer mode options, request payloads, and helper text/state**
- [ ] **Step 2: Run `cd front && npm run test` and verify the new mode-aware tests fail**
- [ ] **Step 3: Implement the minimal frontend types and helpers for online/offline mode branching**
- [ ] **Step 4: Run `cd front && npm run test` and verify the helper tests pass**
### Task 5: Update the transfer send and receive pages
**Files:**
- Modify: `front/src/pages/Transfer.tsx`
- Modify: `front/src/pages/TransferReceive.tsx`
- Modify: `front/src/lib/transfer.ts`
- Test: `front/src/pages/transfer-state.test.ts`
- [ ] **Step 1: Add failing tests for send-mode selection and receive-mode branching where possible in existing frontend test files**
- [ ] **Step 2: Run `cd front && npm run test` and verify the new assertions fail**
- [ ] **Step 3: Implement the minimal UI and flow split so online stays P2P and offline uses backend-backed receive/download behavior**
- [ ] **Step 4: Run `cd front && npm run test` and verify the mode flow tests pass**
### Task 6: Verify and release
**Files:**
- Modify: `docs/architecture.md`
- Modify: `docs/api-reference.md`
- [ ] **Step 1: Run `cd backend && mvn test`**
- [ ] **Step 2: Run `cd front && npm run test`**
- [ ] **Step 3: Run `cd front && npm run lint`**
- [ ] **Step 4: Run `cd front && npm run build`**
- [ ] **Step 5: Run `cd backend && mvn package`**
- [ ] **Step 6: Update the docs to describe online/offline transfer behavior and offline endpoints**
- [ ] **Step 7: Publish frontend with `node scripts/deploy-front-oss.mjs` from repo root**
- [ ] **Step 8: Upload `backend/target/yoyuzh-portal-backend-0.0.1-SNAPSHOT.jar` to the real server and restart the existing backend service**