21 KiB
Multi User Platform Upgrade Phase 2 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: 在当前“邀请制多用户个人盘”稳定后,把系统升级到最小可用的“空间 + 成员角色 + 文件 ACL + 站内共享 + 审计”平台模型,同时不破坏现有个人网盘、公开分享、快传和管理台主链路。
Architecture: 继续保留现有 portal_user + StoredFile + FileBlob/FileEntity 主模型,不推翻个人网盘语义,而是在其上增加 Space、SpaceMember、FilePermissionEntry 和 AuditLog 这四层扩展。个人网盘先通过“每个用户自动拥有一个 personal space”兼容到新模型,桌面端和管理台先接入空间与权限入口,移动端只保兼容、不在本阶段新增完整协作 UI。
Tech Stack: Spring Boot 3.3.8, Spring Data JPA, H2/MySQL, React 19, TypeScript, Vite 6, Tailwind CSS v4, existing /api/v2 patterns, existing mvn test, npm run test, npm run lint, @test-driven-development.
Scope And Sequencing
- 本计划默认在当前
2026-04-08-cloudreve-inspired-upgrade-and-refactor.md的既定升级、尤其是阶段 6 和全站前端重设计完成并合入后执行。 - 本计划只覆盖桌面 Web、现有管理台、后端模型/API、现有测试体系,不在本阶段实现移动端协作页、WebDAV 权限联动、组织/部门层级、团队回收站、第三方 OAuth scope 细化。
- 所有新能力优先挂在
/api/v2/**;旧/api/files/**、/api/admin/**只做必要兼容,不强制一次性重写。 - 执行中始终使用 @test-driven-development:先写失败测试,再补最小实现,再跑最小验证,最后补全集验证。
Task 1: Add Space Domain Skeleton And Default Personal Space
Files:
-
Create:
backend/src/main/java/com/yoyuzh/files/space/Space.java -
Create:
backend/src/main/java/com/yoyuzh/files/space/SpaceType.java -
Create:
backend/src/main/java/com/yoyuzh/files/space/SpaceRole.java -
Create:
backend/src/main/java/com/yoyuzh/files/space/SpaceMember.java -
Create:
backend/src/main/java/com/yoyuzh/files/space/SpaceRepository.java -
Create:
backend/src/main/java/com/yoyuzh/files/space/SpaceMemberRepository.java -
Create:
backend/src/main/java/com/yoyuzh/files/space/SpaceService.java -
Modify:
backend/src/main/java/com/yoyuzh/auth/User.java -
Modify:
backend/src/main/java/com/yoyuzh/files/StoredFile.java -
Modify:
backend/src/main/java/com/yoyuzh/files/StoredFileRepository.java -
Create:
backend/src/test/java/com/yoyuzh/files/space/SpaceServiceTest.java -
Modify:
backend/src/test/java/com/yoyuzh/files/FileServiceTest.java -
Step 1: Write the failing space-domain tests
Run: cd backend && mvn test -Dtest=SpaceServiceTest,FileServiceTest
Expected: FAIL because Space, SpaceMember, and StoredFile.space support do not exist yet.
- Step 2: Add the minimal schema and repository layer
Implement:
-
SpacewithPERSONALandCOLLABORATIVEtypes -
SpaceMemberwithOWNER,MANAGER,EDITOR,VIEWER -
StoredFile.spaceas nullable-to-required migration target -
repository methods for “default personal space by user” and “space membership by user”
-
Step 3: Add default personal-space bootstrap
Implement SpaceService.ensurePersonalSpace(User) so:
-
existing users can lazily receive a personal space
-
new users automatically get one after registration/bootstrap
-
files created through current private flows can still resolve to a valid space
-
Step 4: Re-run the targeted backend tests
Run: cd backend && mvn test -Dtest=SpaceServiceTest,FileServiceTest
Expected: PASS for personal-space bootstrap and StoredFile compatibility assertions.
- Step 5: Commit
git add backend/src/main/java/com/yoyuzh/files/space backend/src/main/java/com/yoyuzh/auth/User.java backend/src/main/java/com/yoyuzh/files/StoredFile.java backend/src/main/java/com/yoyuzh/files/StoredFileRepository.java backend/src/test/java/com/yoyuzh/files/space/SpaceServiceTest.java backend/src/test/java/com/yoyuzh/files/FileServiceTest.java
git commit -m "feat(files): add space domain skeleton"
Task 2: Route Existing File Ownership Through Spaces Without Breaking Private Disk
Files:
-
Modify:
backend/src/main/java/com/yoyuzh/files/FileService.java -
Modify:
backend/src/main/java/com/yoyuzh/files/FileSearchService.java -
Modify:
backend/src/main/java/com/yoyuzh/files/ShareV2Service.java -
Modify:
backend/src/main/java/com/yoyuzh/files/BackgroundTaskService.java -
Modify:
backend/src/main/java/com/yoyuzh/files/StoredFileRepository.java -
Create:
backend/src/test/java/com/yoyuzh/files/StoredFileSpaceCompatibilityTest.java -
Modify:
backend/src/test/java/com/yoyuzh/files/FileSearchServiceTest.java -
Modify:
backend/src/test/java/com/yoyuzh/files/BackgroundTaskServiceTest.java -
Step 1: Write failing compatibility tests for old personal-disk flows
Run: cd backend && mvn test -Dtest=StoredFileSpaceCompatibilityTest,FileSearchServiceTest,BackgroundTaskServiceTest
Expected: FAIL because current create/search/task flows still assume “user owns everything directly”.
- Step 2: Thread
spaceIdthrough internal file creation and lookup
Implement the smallest compatibility rules:
-
private files default to current user personal space
-
current search/list/task flows keep returning the same personal files as before
-
share import, archive/extract, upload complete, and metadata tasks preserve the owning space
-
Step 3: Keep old API semantics stable
Do not change:
- existing personal path semantics
- public share token behavior
- anonymous transfer behavior
- current admin file listing shape
Only add internal space routing needed for future collaborative flows.
- Step 4: Re-run targeted compatibility tests
Run: cd backend && mvn test -Dtest=StoredFileSpaceCompatibilityTest,FileSearchServiceTest,BackgroundTaskServiceTest
Expected: PASS with no regression on existing personal-disk behavior.
- Step 5: Commit
git add backend/src/main/java/com/yoyuzh/files/FileService.java backend/src/main/java/com/yoyuzh/files/FileSearchService.java backend/src/main/java/com/yoyuzh/files/ShareV2Service.java backend/src/main/java/com/yoyuzh/files/BackgroundTaskService.java backend/src/main/java/com/yoyuzh/files/StoredFileRepository.java backend/src/test/java/com/yoyuzh/files/StoredFileSpaceCompatibilityTest.java backend/src/test/java/com/yoyuzh/files/FileSearchServiceTest.java backend/src/test/java/com/yoyuzh/files/BackgroundTaskServiceTest.java
git commit -m "refactor(files): route private disk through personal spaces"
Task 3: Add V2 Space APIs And Membership Management
Files:
-
Create:
backend/src/main/java/com/yoyuzh/api/v2/spaces/SpaceV2Controller.java -
Create:
backend/src/main/java/com/yoyuzh/api/v2/spaces/SpaceResponse.java -
Create:
backend/src/main/java/com/yoyuzh/api/v2/spaces/SpaceMemberResponse.java -
Create:
backend/src/main/java/com/yoyuzh/api/v2/spaces/CreateSpaceRequest.java -
Create:
backend/src/main/java/com/yoyuzh/api/v2/spaces/AddSpaceMemberRequest.java -
Create:
backend/src/main/java/com/yoyuzh/api/v2/spaces/UpdateSpaceMemberRoleRequest.java -
Modify:
backend/src/main/java/com/yoyuzh/config/SecurityConfig.java -
Modify:
backend/src/main/java/com/yoyuzh/auth/UserDetailsServiceImpl.java -
Create:
backend/src/test/java/com/yoyuzh/api/v2/spaces/SpaceV2ControllerIntegrationTest.java -
Step 1: Write failing API tests for creating and listing spaces
Run: cd backend && mvn test -Dtest=SpaceV2ControllerIntegrationTest
Expected: FAIL because /api/v2/spaces/** endpoints and security wiring do not exist.
- Step 2: Implement the minimal V2 space endpoints
Implement:
POST /api/v2/spacesGET /api/v2/spacesGET /api/v2/spaces/{id}POST /api/v2/spaces/{id}/membersPATCH /api/v2/spaces/{id}/members/{userId}DELETE /api/v2/spaces/{id}/members/{userId}
Rules:
-
only authenticated users can list their spaces
-
only
OWNER/MANAGERcan manage members -
personal spaces cannot remove the owner or add arbitrary members
-
Step 3: Return DTOs only
Do not expose JPA entities directly. Keep API outputs small:
-
space identity
-
type
-
display name
-
current user role
-
member summaries
-
Step 4: Re-run targeted V2 API tests
Run: cd backend && mvn test -Dtest=SpaceV2ControllerIntegrationTest
Expected: PASS for create/list/member add/remove/role change rules.
- Step 5: Commit
git add backend/src/main/java/com/yoyuzh/api/v2/spaces backend/src/main/java/com/yoyuzh/config/SecurityConfig.java backend/src/main/java/com/yoyuzh/auth/UserDetailsServiceImpl.java backend/src/test/java/com/yoyuzh/api/v2/spaces/SpaceV2ControllerIntegrationTest.java
git commit -m "feat(api): add v2 space and member management"
Task 4: Add File ACL Entries And Permission Evaluation
Files:
-
Create:
backend/src/main/java/com/yoyuzh/files/permission/FilePermissionEntry.java -
Create:
backend/src/main/java/com/yoyuzh/files/permission/FilePermissionRole.java -
Create:
backend/src/main/java/com/yoyuzh/files/permission/FilePermissionSubjectType.java -
Create:
backend/src/main/java/com/yoyuzh/files/permission/FilePermissionEntryRepository.java -
Create:
backend/src/main/java/com/yoyuzh/files/permission/FilePermissionService.java -
Create:
backend/src/main/java/com/yoyuzh/files/permission/FileAccessEvaluator.java -
Modify:
backend/src/main/java/com/yoyuzh/files/FileService.java -
Modify:
backend/src/main/java/com/yoyuzh/files/FileSearchService.java -
Modify:
backend/src/main/java/com/yoyuzh/files/ShareV2Service.java -
Create:
backend/src/test/java/com/yoyuzh/files/permission/FilePermissionServiceTest.java -
Modify:
backend/src/test/java/com/yoyuzh/files/FileServiceEdgeCaseTest.java -
Step 1: Write failing ACL tests
Run: cd backend && mvn test -Dtest=FilePermissionServiceTest,FileServiceEdgeCaseTest
Expected: FAIL because file access is still governed only by owner/admin checks.
- Step 2: Implement the minimal ACL model
Implement:
- subject types:
USER,SPACE - permission roles:
VIEWER,EDITOR,MANAGER - inheritance flag for directory-to-descendant lookup
Rules:
-
owner/personal-space owner always has full access
-
collaborative space role provides the default baseline
-
explicit file ACL can grant additional access to a user
-
Step 3: Enforce ACL at service boundaries
Apply permission checks to:
-
list directory
-
upload into folder
-
rename/move/copy/delete
-
create public share
-
import into target folder
-
start background tasks on a file
-
Step 4: Re-run the ACL and edge-case tests
Run: cd backend && mvn test -Dtest=FilePermissionServiceTest,FileServiceEdgeCaseTest
Expected: PASS with clear denials for users outside the owning space or without explicit grants.
- Step 5: Commit
git add backend/src/main/java/com/yoyuzh/files/permission backend/src/main/java/com/yoyuzh/files/FileService.java backend/src/main/java/com/yoyuzh/files/FileSearchService.java backend/src/main/java/com/yoyuzh/files/ShareV2Service.java backend/src/test/java/com/yoyuzh/files/permission/FilePermissionServiceTest.java backend/src/test/java/com/yoyuzh/files/FileServiceEdgeCaseTest.java
git commit -m "feat(files): add acl-based permission evaluation"
Task 5: Add In-App Sharing And “Shared With Me” V2 Views
Files:
-
Create:
backend/src/main/java/com/yoyuzh/api/v2/files/ShareFileToUserV2Request.java -
Create:
backend/src/main/java/com/yoyuzh/api/v2/files/SharedFileV2Response.java -
Create:
backend/src/main/java/com/yoyuzh/api/v2/files/FilePermissionsV2Controller.java -
Modify:
backend/src/main/java/com/yoyuzh/api/v2/files/FileSearchV2Controller.java -
Modify:
backend/src/main/java/com/yoyuzh/files/permission/FilePermissionService.java -
Modify:
backend/src/main/java/com/yoyuzh/files/StoredFileRepository.java -
Create:
backend/src/test/java/com/yoyuzh/api/v2/files/FilePermissionsV2ControllerIntegrationTest.java -
Modify:
backend/src/test/java/com/yoyuzh/files/FileShareControllerIntegrationTest.java -
Step 1: Write failing tests for in-app share and shared-with-me listing
Run: cd backend && mvn test -Dtest=FilePermissionsV2ControllerIntegrationTest,FileShareControllerIntegrationTest
Expected: FAIL because there is no station-internal share grant endpoint or “shared with me” query.
- Step 2: Add minimal in-app sharing endpoints
Implement:
GET /api/v2/files/{fileId}/permissionsPUT /api/v2/files/{fileId}/permissionsDELETE /api/v2/files/{fileId}/permissions/{entryId}GET /api/v2/files/shared-with-me
Rules:
-
only
MANAGERor owner can grant/revoke -
station-internal share writes ACL entries, not public share tokens
-
shared-with-meexcludes files already owned through the current user’s own personal space -
Step 3: Keep public sharing separate
Do not merge station-internal sharing into FileShareLink.
Continue using:
-
FileShareLinkfor public token shares -
FilePermissionEntryfor logged-in user-to-user sharing -
Step 4: Re-run targeted integration tests
Run: cd backend && mvn test -Dtest=FilePermissionsV2ControllerIntegrationTest,FileShareControllerIntegrationTest
Expected: PASS for grant, revoke, and shared-with-me listing behavior.
- Step 5: Commit
git add backend/src/main/java/com/yoyuzh/api/v2/files backend/src/main/java/com/yoyuzh/files/permission/FilePermissionService.java backend/src/main/java/com/yoyuzh/files/StoredFileRepository.java backend/src/test/java/com/yoyuzh/api/v2/files/FilePermissionsV2ControllerIntegrationTest.java backend/src/test/java/com/yoyuzh/files/FileShareControllerIntegrationTest.java
git commit -m "feat(files): add in-app sharing and shared-with-me"
Task 6: Add Cross-Cutting Audit Logs And Admin Audit Read API
Files:
-
Create:
backend/src/main/java/com/yoyuzh/common/audit/AuditLogEntry.java -
Create:
backend/src/main/java/com/yoyuzh/common/audit/AuditAction.java -
Create:
backend/src/main/java/com/yoyuzh/common/audit/AuditLogEntryRepository.java -
Create:
backend/src/main/java/com/yoyuzh/common/audit/AuditLogService.java -
Create:
backend/src/main/java/com/yoyuzh/admin/AdminAuditLogResponse.java -
Modify:
backend/src/main/java/com/yoyuzh/admin/AdminController.java -
Modify:
backend/src/main/java/com/yoyuzh/admin/AdminService.java -
Modify:
backend/src/main/java/com/yoyuzh/files/FileService.java -
Modify:
backend/src/main/java/com/yoyuzh/files/space/SpaceService.java -
Modify:
backend/src/main/java/com/yoyuzh/files/permission/FilePermissionService.java -
Modify:
backend/src/test/java/com/yoyuzh/admin/AdminControllerIntegrationTest.java -
Create:
backend/src/test/java/com/yoyuzh/common/audit/AuditLogServiceTest.java -
Step 1: Write failing audit tests
Run: cd backend && mvn test -Dtest=AuditLogServiceTest,AdminControllerIntegrationTest
Expected: FAIL because no audit entity/service exists and admin cannot query audit logs.
- Step 2: Implement the smallest useful audit model
Persist at least:
- actor user id
- action type
- target type
- target id
- summary text
- created at
Log these events:
-
space create/member change
-
file permission grant/revoke
-
public share create/delete
-
file delete/restore
-
Step 3: Add admin read API only
Implement a read-only admin endpoint:
GET /api/admin/audit-logs?page=0&size=20&query=...
Do not add end-user audit UI in this phase.
- Step 4: Re-run audit tests
Run: cd backend && mvn test -Dtest=AuditLogServiceTest,AdminControllerIntegrationTest
Expected: PASS for audit persistence and admin listing.
- Step 5: Commit
git add backend/src/main/java/com/yoyuzh/common/audit backend/src/main/java/com/yoyuzh/admin/AdminController.java backend/src/main/java/com/yoyuzh/admin/AdminService.java backend/src/main/java/com/yoyuzh/files/FileService.java backend/src/main/java/com/yoyuzh/files/space/SpaceService.java backend/src/main/java/com/yoyuzh/files/permission/FilePermissionService.java backend/src/test/java/com/yoyuzh/admin/AdminControllerIntegrationTest.java backend/src/test/java/com/yoyuzh/common/audit/AuditLogServiceTest.java
git commit -m "feat(admin): add audit log backbone"
Task 7: Add Desktop-Web Space, Permission, And Shared-With-Me UI
Files:
-
Modify:
front/src/lib/types.ts -
Modify:
front/src/lib/api.ts -
Create:
front/src/lib/spaces.ts -
Create:
front/src/lib/spaces.test.ts -
Create:
front/src/lib/file-permissions.ts -
Create:
front/src/lib/file-permissions.test.ts -
Modify:
front/src/App.tsx -
Modify:
front/src/components/layout/Layout.tsx -
Modify:
front/src/pages/files/FilesDirectoryRail.tsx -
Modify:
front/src/pages/files/FilesToolbar.tsx -
Modify:
front/src/pages/files/useFilesDirectoryState.ts -
Create:
front/src/pages/Spaces.tsx -
Create:
front/src/pages/SharedWithMe.tsx -
Create:
front/src/pages/files/SpaceMembersDialog.tsx -
Create:
front/src/pages/files/FilePermissionsDialog.tsx -
Create:
front/src/pages/spaces-state.ts -
Create:
front/src/pages/spaces-state.test.ts -
Create:
front/src/pages/shared-with-me-state.ts -
Create:
front/src/pages/shared-with-me-state.test.ts -
Step 1: Write failing frontend helper tests
Run: cd front && npm run test -- src/lib/spaces.test.ts src/lib/file-permissions.test.ts src/pages/spaces-state.test.ts src/pages/shared-with-me-state.test.ts
Expected: FAIL because the new API helpers and page state modules do not exist.
- Step 2: Add typed API helpers first
Implement the smallest helpers for:
- list/create spaces
- list/update members
- get/update file permissions
- list shared-with-me files
Do not start with JSX-heavy pages before helpers and tests exist.
- Step 3: Add desktop-only navigation and management UI
Implement:
Spacespage for list/create/member managementSharedWithMepage for station-internal shares- file page dialogs for members and permissions
- a space switcher in the file rail or toolbar
Rules:
-
keep current private disk route working
-
personal space remains default landing target
-
mobile app can stay unchanged in this phase
-
Step 4: Re-run targeted frontend tests
Run: cd front && npm run test -- src/lib/spaces.test.ts src/lib/file-permissions.test.ts src/pages/spaces-state.test.ts src/pages/shared-with-me-state.test.ts
Expected: PASS with helpers and page state stabilized before broad UI verification.
- Step 5: Commit
git add front/src/lib/types.ts front/src/lib/api.ts front/src/lib/spaces.ts front/src/lib/spaces.test.ts front/src/lib/file-permissions.ts front/src/lib/file-permissions.test.ts front/src/App.tsx front/src/components/layout/Layout.tsx front/src/pages/files/FilesDirectoryRail.tsx front/src/pages/files/FilesToolbar.tsx front/src/pages/files/useFilesDirectoryState.ts front/src/pages/Spaces.tsx front/src/pages/SharedWithMe.tsx front/src/pages/files/SpaceMembersDialog.tsx front/src/pages/files/FilePermissionsDialog.tsx front/src/pages/spaces-state.ts front/src/pages/spaces-state.test.ts front/src/pages/shared-with-me-state.ts front/src/pages/shared-with-me-state.test.ts
git commit -m "feat(front): add spaces and shared-with-me ui"
Task 8: Full Verification And Documentation Handoff
Files:
-
Modify:
docs/architecture.md -
Modify:
docs/api-reference.md -
Modify:
memory.md -
Modify only if verification reveals gaps:
backend/**,front/** -
Step 1: Run full backend verification
Run: cd backend && mvn test
Expected: PASS with no regressions in auth, files, tasks, shares, admin, and API v2 tests.
- Step 2: Run full frontend verification
Run: cd front && npm run test
Expected: PASS with no regressions in files, transfer, admin, and new spaces/shared state tests.
- Step 3: Run frontend type/lint verification
Run: cd front && npm run lint
Expected: PASS with no TypeScript errors.
- Step 4: Update project memory and architecture docs
Document:
-
space model
-
member roles
-
ACL rules
-
in-app sharing vs public share split
-
admin audit log availability
-
mobile deferred scope
-
Step 5: Final commit
git add docs/architecture.md docs/api-reference.md memory.md
git commit -m "docs: record multi-user platform phase 2 architecture"
Deferred Explicitly
- 移动端
MobileFiles/MobileOverview/MobileApp的空间协作 UI - 组织/部门/用户组层级,不在本计划混入
- WebDAV、OAuth scope、桌面同步客户端权限联动
- 团队回收站、空间级生命周期策略、空间级存储策略切换
- 文件评论、审批流、在线协作文档
Success Criteria
- 现有个人网盘用户登录后仍能像今天一样使用自己的私有文件空间。
- 每个用户可看到自己的 personal space,且可创建 collaborative space。
- collaborative space 支持最小成员角色与目录/文件 ACL。
- 站内用户可通过 ACL 被共享文件,并在 “Shared With Me” 中看到结果。
- 审计日志能覆盖空间、权限、分享、删除/恢复等关键动作。
- 旧公开分享、快传、上传会话、后台任务和管理台文件列表不被打断。