5.7 KiB
Shared File Blob Storage 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: 将网盘文件模型改造成 StoredFile -> FileBlob 引用关系,让分享导入与网盘复制复用同一份底层对象,而不是再次写入物理文件。
Architecture: 新增独立 FileBlob 实体承载真实对象 key、大小和内容类型,StoredFile 只保留逻辑目录元数据并引用 FileBlob。网盘上传为每个新文件创建新 blob,分享导入和文件复制直接复用 blob;删除时按引用是否归零决定是否删除底层对象。补一个面向旧 portal_file.storage_name 数据的一次性回填路径,避免线上旧数据在新模型下失联。
Tech Stack: Spring Boot 3.3.8, Spring Data JPA, Java 17, Maven, H2 tests, local filesystem storage, S3-compatible object storage
Task 1: Define Blob Data Model
Files:
-
Create:
backend/src/main/java/com/yoyuzh/files/FileBlob.java -
Create:
backend/src/main/java/com/yoyuzh/files/FileBlobRepository.java -
Modify:
backend/src/main/java/com/yoyuzh/files/StoredFile.java -
Modify:
backend/src/main/java/com/yoyuzh/files/StoredFileRepository.java -
Step 1: Write the failing tests
Add/update backend tests that expect file copies and share imports to preserve a shared blob id rather than a per-user storage name.
- Step 2: Run test to verify it fails
Run: cd /Users/mac/Documents/my_site/backend && mvn test -Dtest=FileServiceTest,FileShareControllerIntegrationTest
Expected: FAIL because StoredFile does not yet expose blob references and current logic still duplicates file content.
- Step 3: Write minimal implementation
Add FileBlob entity/repository, move file-object ownership from StoredFile.storageName to StoredFile.blob, and add repository helpers for blob reference counting / physical size queries.
- Step 4: Run test to verify it passes
Run: cd /Users/mac/Documents/my_site/backend && mvn test -Dtest=FileServiceTest,FileShareControllerIntegrationTest
Expected: PASS for data-model expectations.
Task 2: Refactor File Storage Flow To Blob Keys
Files:
-
Modify:
backend/src/main/java/com/yoyuzh/files/FileService.java -
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/S3FileContentStorage.java -
Test:
backend/src/test/java/com/yoyuzh/files/FileServiceTest.java -
Test:
backend/src/test/java/com/yoyuzh/files/FileServiceEdgeCaseTest.java -
Step 1: Write the failing tests
Add/update tests for:
-
upload creates a new blob
-
share import reuses the source blob and does not store bytes again
-
file copy reuses the source blob and does not copy bytes again
-
deleting a non-final reference keeps the blob/object alive
-
deleting the final reference removes the blob/object
-
Step 2: Run test to verify it fails
Run: cd /Users/mac/Documents/my_site/backend && mvn test -Dtest=FileServiceTest,FileServiceEdgeCaseTest
Expected: FAIL because current service still calls readFile/storeImportedFile/copyFile/moveFile/renameFile for ordinary files.
- Step 3: Write minimal implementation
Refactor file upload/download/import/copy/delete to operate on blob object keys. Keep directory behavior metadata-only. Ensure file rename/move/copy no longer trigger physical object mutations, and deletion only removes the object when the last StoredFile reference disappears.
- Step 4: Run test to verify it passes
Run: cd /Users/mac/Documents/my_site/backend && mvn test -Dtest=FileServiceTest,FileServiceEdgeCaseTest
Expected: PASS.
Task 3: Backfill Old File Rows Into Blob References
Files:
-
Create:
backend/src/main/java/com/yoyuzh/files/FileBlobBackfillService.java -
Modify:
backend/src/main/java/com/yoyuzh/files/StoredFileRepository.java -
Test:
backend/src/test/java/com/yoyuzh/files/FileShareControllerIntegrationTest.java -
Step 1: Write the failing test
Add an integration-path expectation that persisted file rows still download/import correctly after the blob model change.
- Step 2: Run test to verify it fails
Run: cd /Users/mac/Documents/my_site/backend && mvn test -Dtest=FileShareControllerIntegrationTest
Expected: FAIL because legacy portal_file rows created without blobs can no longer resolve file content.
- Step 3: Write minimal implementation
Add a startup/on-demand backfill that creates FileBlob rows for existing non-directory files using their legacy object key and attaches them to StoredFile rows with missing blob references.
- Step 4: Run test to verify it passes
Run: cd /Users/mac/Documents/my_site/backend && mvn test -Dtest=FileShareControllerIntegrationTest
Expected: PASS.
Task 4: Update Docs And Full Verification
Files:
-
Modify:
memory.md -
Modify:
docs/architecture.md -
Modify:
docs/api-reference.md(only if API semantics changed) -
Step 1: Document the new storage model
Record that logical file metadata now points to shared blobs, that share import and copy reuse blobs, and that physical keys are global rather than user-path keys.
- Step 2: Run full backend verification
Run: cd /Users/mac/Documents/my_site/backend && mvn test
Expected: PASS.
- Step 3: Summarize migration requirement
In the final handoff, call out that old production data must be backfilled to FileBlob rows before or during rollout; otherwise pre-existing files cannot resolve blob references under the new model.