Files
my_site/docs/superpowers/plans/2026-04-02-shared-file-blob-storage.md

116 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.