refactor(files): reorganize backend package layout
This commit is contained in:
23
memory.md
23
memory.md
@@ -139,8 +139,8 @@
|
||||
- 管理员改密接口: `backend/src/main/java/com/yoyuzh/admin/AdminService.java`
|
||||
- 管理台统计与 7 天上线记录: `backend/src/main/java/com/yoyuzh/admin/AdminMetricsService.java`、`backend/src/main/java/com/yoyuzh/admin/AdminDailyActiveUserEntity.java`、`backend/src/main/java/com/yoyuzh/config/JwtAuthenticationFilter.java`
|
||||
- 管理台 dashboard 展示与请求折线图: `front/src/admin/dashboard.tsx`、`front/src/admin/dashboard-state.ts`
|
||||
- 网盘 blob 模型与回填: `backend/src/main/java/com/yoyuzh/files/FileService.java`、`backend/src/main/java/com/yoyuzh/files/FileBlob.java`、`backend/src/main/java/com/yoyuzh/files/FileBlobBackfillService.java`
|
||||
- 网盘回收站与恢复: `backend/src/main/java/com/yoyuzh/files/FileService.java`、`backend/src/main/java/com/yoyuzh/files/FileController.java`、`backend/src/main/java/com/yoyuzh/files/StoredFile.java`、`front/src/pages/RecycleBin.tsx`、`front/src/pages/recycle-bin-state.ts`
|
||||
- 网盘 blob 模型与回填: `backend/src/main/java/com/yoyuzh/files/core/FileService.java`、`backend/src/main/java/com/yoyuzh/files/core/FileBlob.java`、`backend/src/main/java/com/yoyuzh/files/core/FileBlobBackfillService.java`
|
||||
- 网盘回收站与恢复: `backend/src/main/java/com/yoyuzh/files/core/FileService.java`、`backend/src/main/java/com/yoyuzh/files/core/FileController.java`、`backend/src/main/java/com/yoyuzh/files/core/StoredFile.java`、`front/src/pages/RecycleBin.tsx`、`front/src/pages/recycle-bin-state.ts`
|
||||
- 前端生产 API 基址: `front/.env.production`
|
||||
- Capacitor Android 入口与配置: `front/capacitor.config.ts`、`front/android/`
|
||||
## 2026-04-08 阶段 1 升级记录
|
||||
@@ -153,7 +153,7 @@
|
||||
|
||||
- 已新增文件实体模型二期的兼容表模型:`FileEntity`、`StoredFileEntity`、`FileEntityType`,并在 `StoredFile` 上新增 `primaryEntity` 与 `updatedAt`。
|
||||
- 已新增 `FileEntityBackfillService`,启动后在旧 `FileBlob` 仍保留的前提下,把已有 `StoredFile.blob` 只增量映射到 `FileEntity.VERSION` 与 `StoredFile.primaryEntity`;现有下载、复制、移动、分享、回收站读写路径暂不切换。
|
||||
- 当前阶段未删除 `FileBlob`,未切换前端,未引入上传会话二期。
|
||||
- 当时阶段未删除 `FileBlob`,未切换前端,也还未引入上传会话二期。
|
||||
## 2026-04-08 阶段 2 第二小步记录
|
||||
|
||||
- 文件写入路径开始双写 `FileBlob + FileEntity.VERSION`:普通代理上传、直传完成、外部文件导入、分享导入,以及网盘复制复用 blob 时,都会给新 `StoredFile` 写入 `primaryEntity` 并创建 `StoredFileEntity(PRIMARY)` 关系。
|
||||
@@ -164,13 +164,22 @@
|
||||
- 2026-04-08 阶段 3 第三小步:新增 `PUT /api/v2/files/upload-sessions/{sessionId}/parts/{partIndex}`,用于记录当前用户上传会话的 part 元数据到 `uploadedPartsJson`,并把会话状态从 `CREATED` 推进到 `UPLOADING`;该接口只记录 `etag/size` 等状态,不承担真正的对象存储分片内容写入或合并。
|
||||
- 2026-04-08 阶段 3 第四小步:`UploadSessionService` 新增定时过期清理,按小时扫描 `CREATED/UPLOADING/COMPLETING` 且已过期的会话,尝试删除对应临时 `blobs/...` 对象,并把会话标记为 `EXPIRED`;`COMPLETED/CANCELLED/FAILED/EXPIRED` 不在本轮清理范围内。
|
||||
- 2026-04-08 multipart 评估结论:暂不把 v2 上传会话直接接入真实对象存储分片写入/合并。当前 `FileContentStorage` 仍是单对象上传/校验抽象,缺少 multipart uploadId、part URL 预签名、complete/abort 语义;立即接入会把上传会话写死在当前多吉云 S3 配置上,并让过期清理误以为 `deleteBlob` 能释放未完成分片。下一步先做阶段 4 存储策略与能力声明骨架,再按 `multipartUpload` 能力接 S3 multipart。
|
||||
- 2026-04-08 阶段 4 第一小步:新增 `StoragePolicy`、`StoragePolicyType`、`StoragePolicyCredentialMode`、`StoragePolicyCapabilities` 与 `StoragePolicyService`,启动时把当前 `app.storage.provider` 映射成一条默认策略;本地策略声明 `serverProxyDownload=true`、`multipartUpload=false`,多吉云/S3 兼容策略声明 `directUpload=true`、`signedDownloadUrl=true`、`requiresCors=true`、`multipartUpload=false`。新 v2 上传会话会记录默认 `storagePolicyId`,但旧上传下载路径和前端上传队列仍未切换。
|
||||
- 2026-04-08 阶段 4 第一小步:新增 `StoragePolicy`、`StoragePolicyType`、`StoragePolicyCredentialMode`、`StoragePolicyCapabilities` 与 `StoragePolicyService`,启动时把当前 `app.storage.provider` 映射成一条默认策略;当时本地策略声明 `serverProxyDownload=true`、`multipartUpload=false`,多吉云/S3 兼容策略也先声明为 `directUpload=true`、`signedDownloadUrl=true`、`requiresCors=true`、`multipartUpload=false`。新 v2 上传会话会记录默认 `storagePolicyId`,但旧上传下载路径和前端上传队列仍未切换。
|
||||
- 2026-04-08 合并 `files/storage` 补提交后修复:`S3FileContentStorage` 改为复用 `DogeCloudS3SessionProvider` / `DogeCloudTmpTokenClient` 获取并缓存运行期 `S3Client` 与 `S3Presigner`,保留生产构造器 `S3FileContentStorage(FileStorageProperties)`,同时提供测试用注入构造器;S3 直传、签名下载、上传校验、读旧对象键 fallback、rename/move/copy、离线快传对象读写继续通过 `FileContentStorage` 统一抽象。
|
||||
- 2026-04-08 阶段 4 第二小步:新写入和回填生成的 `FileEntity.VERSION` 会记录默认 `StoragePolicy.id` 到 `storagePolicyId`,让物理实体可以追踪归属存储策略;复用已有 `FileEntity` 时只增加引用计数,不覆盖历史实体策略字段。旧 `/api/files/**` 读取路径仍继续依赖 `StoredFile.blob`。
|
||||
- 2026-04-08 阶段 4 第三小步:新增管理员只读存储策略查看能力,后端暴露 `GET /api/admin/storage-policies`,前端管理台新增“存储策略”资源列表和能力矩阵展示;该接口只返回白名单 DTO 与结构化 `StoragePolicyCapabilities`,不暴露凭证、不支持新增/编辑/启停/删除策略,也不启用真实 multipart。
|
||||
- 2026-04-08 阶段 4 第三小步:新增管理员只读存储策略查看能力,后端暴露 `GET /api/admin/storage-policies`,前端管理台新增“存储策略”资源列表和能力矩阵展示;该接口只返回白名单 DTO 与结构化 `StoragePolicyCapabilities`,不暴露凭证,也不支持新增/编辑/启停/删除策略。
|
||||
- 2026-04-08 阶段 5 第一小步:新增用户侧 v2 文件搜索最小闭环,后端暴露受保护的 `GET /api/v2/files/search`,复用 `StoredFile` 查询当前用户未删除文件,支持 `name`、`type=file|directory|folder|all`、`sizeGte/sizeLte`、`createdGte/createdLte`、`updatedGte/updatedLte` 与分页;同时新增 `FileMetadata` / `FileMetadataRepository` 扩展表骨架,暂不迁移回收站字段、暂不接入标签/metadata 过滤、暂不改前端上传队列和旧 `/api/files/**` 行为。
|
||||
- 2026-04-08 阶段 5 第二小步:前端桌面端接入最小搜索下游,新增 `front/src/lib/file-search.ts` 和 `front/src/lib/file-search.test.ts`,桌面 `front/src/pages/Files.tsx` 可通过 v2 search 单独搜索并展示结果,不写入 `getFilesListCacheKey(...)`,也不影响原有目录缓存和上传主链路;移动端暂未接入搜索,后续可按同一 helper 补入。
|
||||
- 2026-04-08 阶段 5 第三小步:新增分享二期后端最小骨架。`FileShareLink` 增加 `passwordHash`、`expiresAt`、`maxDownloads`、`downloadCount`、`viewCount`、`allowImport`、`allowDownload`、`shareName`;新增 `com.yoyuzh.api.v2.shares` 与 `ShareV2Service`,提供 v2 创建、公开读取、密码校验、导入、我的分享列表和删除。公开访问仅限 `GET /api/v2/shares/{token}` 与 `POST /api/v2/shares/{token}/verify-password`;创建、导入、我的分享、删除仍需登录。v2 导入会先校验过期时间、密码、`allowImport` 和 `maxDownloads`,再复用旧导入持久化链路;旧 `/api/files/share-links/**` 继续兼容。当前 `allowDownload` 只落库和返回,尚未接入独立 v2 下载路由。
|
||||
- 2026-04-08 阶段 5 第三小步:新增分享二期后端最小骨架。`FileShareLink` 增加 `passwordHash`、`expiresAt`、`maxDownloads`、`downloadCount`、`viewCount`、`allowImport`、`allowDownload`、`shareName`;新增 `com.yoyuzh.api.v2.shares` 与 `ShareV2Service`,提供 v2 创建、公开读取、密码校验、导入、我的分享列表和删除。公开访问包括 `GET /api/v2/shares/{token}`、`POST /api/v2/shares/{token}/verify-password`,以及 `GET /api/v2/shares/{token}?download=1` 下载入口;后者会统一校验过期时间、密码、`allowDownload` 和 `maxDownloads`,成功后复用现有下载链路并递增 `downloadCount`。创建、导入、我的分享、删除仍需登录;v2 导入仍会先校验过期时间、密码、`allowImport` 和 `maxDownloads`,再复用旧导入持久化链路;旧 `/api/files/share-links/**` 继续兼容。
|
||||
- 2026-04-08 阶段 5 第四小步:新增文件事件流前后端最小闭环。后端落地 `FileEvent` / `FileEventType` / `FileEventRepository` / `FileEventService`,并提供受保护的 `GET /api/v2/files/events?path=/` SSE 入口;当前可按用户广播、按路径前缀过滤、按 `X-Yoyuzh-Client-Id` 抑制自身事件,首次连接会收到 `READY` 事件。前端新增 fetch-stream 版 `front/src/lib/file-events.ts`,不直接使用无法带鉴权头的原生 `EventSource`;桌面 `Files` 与移动 `MobileFiles` 已订阅当前目录事件,收到文件变更后失效当前目录缓存并刷新列表,搜索结果状态不被清空。
|
||||
- 2026-04-08 阶段 6 第一步:新增后台任务框架与 worker 最小骨架。后端新增 `BackgroundTask` / `BackgroundTaskType` / `BackgroundTaskStatus` / `BackgroundTaskRepository` / `BackgroundTaskService`,并暴露受保护的 `GET /api/v2/tasks`、`GET /api/v2/tasks/{id}`、`DELETE /api/v2/tasks/{id}` 以及 `POST /api/v2/tasks/archive`、`POST /api/v2/tasks/extract`、`POST /api/v2/tasks/media-metadata` 占位创建接口;任务创建入口已校验 `fileId` 属于当前用户、未删除、请求 `path` 匹配服务端派生逻辑路径,并按任务类型限制目录/压缩包/媒体文件,任务 state 使用服务端文件信息;当前 worker 会定时领取 `QUEUED` 任务、切换为 `RUNNING`,其中 `MEDIA_META` 已由最小真实 handler 写入基础媒体元数据与图片宽高,其余任务类型仍通过 no-op handler 标记 `COMPLETED`,异常时标记 `FAILED` 并记录错误原因。压缩/解压/缩略图/视频时长/前端任务面板仍未接入。
|
||||
- 2026-04-09 阶段 5 第五小步:上传会话二期后端接入真实 multipart。`FileContentStorage` 新增 `createMultipartUpload/prepareMultipartPartUpload/completeMultipartUpload/abortMultipartUpload` 抽象,`S3FileContentStorage` 用预签名 `UploadPart` 和 `Complete/AbortMultipartUpload` 落地实现;默认 S3 存储策略能力改为 `multipartUpload=true`。`UploadSession` 新增 `multipartUploadId`,创建会话时若默认策略支持 multipart 会立即初始化 uploadId;v2 会话响应新增 `multipartUpload`,并开放 `GET /api/v2/files/upload-sessions/{sessionId}/parts/{partIndex}/prepare` 返回单分片直传地址。完成会话时会先按已记录 part 元数据提交 multipart complete,再复用旧 `FileService.completeUpload()` 落库;过期清理也会对未完成 multipart 执行 abort。前端上传队列仍未切到这条新链路。
|
||||
- 2026-04-08 阶段 6 第一步:新增后台任务框架与 worker 最小骨架。后端新增 `BackgroundTask` / `BackgroundTaskType` / `BackgroundTaskStatus` / `BackgroundTaskRepository` / `BackgroundTaskService`,并暴露受保护的 `GET /api/v2/tasks`、`GET /api/v2/tasks/{id}`、`DELETE /api/v2/tasks/{id}` 以及 `POST /api/v2/tasks/archive`、`POST /api/v2/tasks/extract`、`POST /api/v2/tasks/media-metadata` 创建接口;任务创建入口会校验 `fileId` 属于当前用户、未删除、请求 `path` 匹配服务端派生逻辑路径,并按任务类型限制目录、zip-compatible 解压源和媒体文件,任务 state 使用服务端文件信息。
|
||||
- 2026-04-09 阶段 6 第二步:`MEDIA_META` 之外的后台任务开始真实化。`ARCHIVE` 任务现在会派生 `outputPath/outputFilename`,由 `ArchiveBackgroundTaskHandler` 复用 `FileService.buildArchiveBytes(...)` 把目录或单文件打成 zip,并通过 `importExternalFile(...)` 写回同级目录;`EXTRACT` 任务现在会派生 `outputPath/outputDirectoryName`,由 `ExtractBackgroundTaskHandler` 读取 zip-compatible 归档、剥离共享根目录、支持单文件归档直接恢复到父目录,并通过 `FileService.importExternalFilesAtomically(...)` 在预检冲突后批量落库,失败时清理已写入的 `blobs/...`,避免留下孤儿 blob。worker 仍按 `QUEUED -> RUNNING -> COMPLETED/FAILED` 驱动,当前未实现非 zip 解压格式、缩略图/视频时长,以及 archive/extract 的前端入口。
|
||||
- 2026-04-09 阶段 6 第三步:后台任务新增最小 progress 字段,但仍不做假百分比。`BackgroundTaskService` 现在会在 `publicStateJson` 里统一维护 `phase`:创建时为 `queued`,claim 后为 `running`,worker 开始执行时按任务类型细化成 `archiving` / `extracting` / `extracting-metadata`,完成/失败/取消时分别收口为 `completed` / `failed` / `cancelled`。`GET /api/v2/tasks/**` 会直接透出这些阶段;`BackgroundTaskV2ControllerIntegrationTest` 也已覆盖 archive/extract 完成态、extract 失败态和取消态的 phase 回读。
|
||||
- 2026-04-09 阶段 6 第六步:`ARCHIVE/EXTRACT` 后台任务补了真实条目计数进度。worker 现在会把 progress reporter 传入 handler;`ARCHIVE` 会按实际写入 zip entry 推进 `processedFileCount/totalFileCount` 与 `processedDirectoryCount/totalDirectoryCount`,`EXTRACT` 会按实际创建目录和导入文件推进同一组字段。重试和启动恢复仍按 `privateStateJson` 重建公开 state,因此这些运行期计数字段不会被错误保留到下一次执行。
|
||||
- 2026-04-09 阶段 6 第四步:后台任务补了最小手动重试闭环。后端新增 `POST /api/v2/tasks/{id}/retry`,只允许当前用户把自己 `FAILED` 状态的任务重新置回 `QUEUED`;重试时会清空 `finishedAt/errorMessage`,按 `privateStateJson` 重建公开 state,并把 `publicStateJson.phase` 重置为 `queued`,不会保留失败时写入的 `worker` 等瞬时字段。
|
||||
- 2026-04-09 阶段 6 第五步:后台任务补了服务启动时的 `RUNNING` 恢复。最初版本会在 `ApplicationReadyEvent` 后直接把遗留 `RUNNING` 任务重排回 `QUEUED`;2026-04-09 晚些时候又升级为只回收 lease 已过期或旧数据里缺少 lease 的 `RUNNING` 任务,避免多实例场景误抢活跃 worker。
|
||||
- 2026-04-09 阶段 6 第七步:后台任务补了保守的自动重试/退避骨架。`BackgroundTask` 现在有 `attemptCount/maxAttempts/nextRunAt`;最初 `ARCHIVE`、`EXTRACT`、`MEDIA_META` 都默认最多执行 3 次,worker claim 时会递增 `attemptCount`。同日后续又升级为按任务类型区分预算与退避:`ARCHIVE` 最多 4 次、`EXTRACT` 最多 3 次、`MEDIA_META` 最多 2 次;失败分类从布尔可重试升级为 `UNSUPPORTED_INPUT/DATA_STATE/TRANSIENT_INFRASTRUCTURE/RATE_LIMITED/UNKNOWN`,公开 state 会写入 `failureCategory` 与 `retryDelaySeconds`,并按类别和任务类型决定是否自动回队列及退避时长。
|
||||
- 2026-04-09 阶段 6 第八步:后台任务补了运行期 heartbeat 与多实例 lease。`BackgroundTask` 现在持久化 `leaseOwner/leaseExpiresAt/heartbeatAt`;worker 每次 claim 会写入唯一 `workerOwner` 并续租,运行中 progress/完成/失败都会刷新 heartbeat。`ARCHIVE/EXTRACT` 的公开 state 现已附带真实 `progressPercent`,`MEDIA_META` 会暴露 `metadataStage`;多实例下会先回收 lease 过期的 `RUNNING` 任务,再领取 `QUEUED` 任务,旧 worker 若丢失 owner 则不会再覆盖新状态。
|
||||
- 2026-04-09 桌面端 `Files` 已补最近 10 条后台任务面板,支持查看状态、取消 `QUEUED/RUNNING` 任务,并可为当前选中文件创建媒体信息提取任务;移动端和 archive/extract 的前端入口暂未接入。
|
||||
- 2026-04-09 files 后端结构清理:`backend/src/main/java/com/yoyuzh/files` 不再平铺大部分领域类,现已按职责重组为 `core/upload/share/search/events/tasks/storage/policy` 八个子包;类名、接口路径、数据库表名/字段名和现有测试语义保持不变,主要是通过 package 重组、import 修正和测试路径同步降低后续继续演进 upload/share/search/events/tasks/storage-policy 的维护摩擦。
|
||||
|
||||
Reference in New Issue
Block a user