Fix Android WebView API access and mobile shell layout

This commit is contained in:
yoyuzh
2026-04-03 14:37:21 +08:00
parent f02ff9342f
commit 56f2a9fe0d
121 changed files with 4751 additions and 700 deletions

View File

@@ -0,0 +1,115 @@
# 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.

View File

@@ -0,0 +1,115 @@
# Transfer Simple Peer Integration 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:** Replace the hand-rolled online transfer WebRTC peer wiring with `simple-peer` while preserving the current pickup-code flow, backend signaling APIs, and offline transfer mode.
**Architecture:** Keep the existing product boundaries: Spring Boot remains a dumb signaling relay and session store, while the React frontend owns online-transfer peer creation and file streaming. Instead of manually managing `RTCPeerConnection`, ICE candidates, and SDP state across sender/receiver pages, introduce a thin `simple-peer` adapter that serializes peer signals through the existing `/api/transfer/sessions/{id}/signals` endpoints and reuses the current transfer control/data protocol.
**Tech Stack:** Vite 6, React 19, TypeScript, node:test, `simple-peer`, existing Spring Boot transfer signaling API.
---
### Task 1: Lock the new peer adapter contract with failing tests
**Files:**
- Create: `front/src/lib/transfer-peer.test.ts`
- Create: `front/src/lib/transfer-peer.ts`
- [ ] **Step 1: Write the failing test**
Add tests that assert:
- local `simple-peer` signal events serialize into a backend-friendly payload
- incoming backend signal payloads are routed back into the peer instance
- peer connection lifecycle maps to app-friendly callbacks without exposing raw browser SDP/ICE handling to pages
- [ ] **Step 2: Run test to verify it fails**
Run: `cd front && npm run test -- src/lib/transfer-peer.test.ts`
- [ ] **Step 3: Write minimal implementation**
Create a focused adapter around `simple-peer` with:
- sender/receiver construction
- `signal` event forwarding
- `connect`, `data`, `close`, and `error` callbacks
- send helpers used by the existing transfer pages
- [ ] **Step 4: Run test to verify it passes**
Run: `cd front && npm run test -- src/lib/transfer-peer.test.ts`
### Task 2: Replace online sender wiring in the desktop and mobile transfer pages
**Files:**
- Modify: `front/src/pages/Transfer.tsx`
- Modify: `front/src/mobile-pages/MobileTransfer.tsx`
- Modify: `front/src/lib/transfer.ts`
- [ ] **Step 1: Write the failing test**
Add or extend focused tests for the new signaling payload shape if needed so the sender path no longer depends on manual offer/answer/ICE branches.
- [ ] **Step 2: Run test to verify it fails**
Run: `cd front && npm run test`
- [ ] **Step 3: Write minimal implementation**
Use the adapter in both sender pages:
- build an initiator peer instead of a raw `RTCPeerConnection`
- post serialized peer signals through the existing backend endpoint
- keep the current file manifest and binary chunk sending protocol
- [ ] **Step 4: Run test to verify it passes**
Run: `cd front && npm run test`
### Task 3: Replace online receiver wiring while keeping the current receive UX
**Files:**
- Modify: `front/src/pages/TransferReceive.tsx`
- [ ] **Step 1: Write the failing test**
Add or update tests around receiver signal handling and data delivery if gaps remain after Task 2.
- [ ] **Step 2: Run test to verify it fails**
Run: `cd front && npm run test`
- [ ] **Step 3: Write minimal implementation**
Use the adapter in the receiver page:
- build a non-initiator peer
- feed backend-delivered signals into it
- keep the current control messages, archive flow, and netdisk save flow unchanged
- [ ] **Step 4: Run test to verify it passes**
Run: `cd front && npm run test`
### Task 4: Verification and release
**Files:**
- Modify if required by validation failures: `front/package.json`, `front/package-lock.json`
- [ ] **Step 1: Install the dependency**
Run: `cd front && npm install simple-peer @types/simple-peer`
- [ ] **Step 2: Run frontend tests**
Run: `cd front && npm run test`
- [ ] **Step 3: Run frontend typecheck**
Run: `cd front && npm run lint`
- [ ] **Step 4: Run frontend build**
Run: `cd front && npm run build`
- [ ] **Step 5: Publish the frontend**
Run: `node scripts/deploy-front-oss.mjs`