feat(files): W5-A2 move/copy via planImport, organize overrides, delete records, download

- /files/move|copy go through planImport's new `transfer` variant (keep names, directory
  expanded to per-file plan) → organization_record + verifyAndImport/executeRecord: per-file
  ledger resumable, fsproxy, cross-volume directory move = per-file copy→verify→delete then
  remove empty source dirs; shared plan store + plan_stale; asset_location follows per file,
  path_binding revised when a whole directory moved (finalizeTransfer); request waits up to
  FILES_TRANSFER_WAIT_SEC, else executed.pending
- /files/organize per-item overrides take effect: season/episodes (domain planOrganize
  overrides), contentUnitId coverage, targetDir (no binding), operation, slotId (satisfied
  after verify); warnings only for inapplicable overrides
- delete/trash/restore write organization_record (action trash|delete|restore, file-level
  results; migration 0026)
- GET /files/download (admin session, nfo/subtitle/image, size cap, streamed, audited)
- GET /files/records?ids|planIds for the organize page
- fs race errors map to 503/404/403/400 instead of 500
- runbook updated

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-27 23:53:50 +08:00
1 parent 3641ab9573
commit 36aa99b8aa
25 files changed
+1766 -271

No files matched your search

+3
View File
@@ -65,6 +65,9 @@ const ORG_ACTION: Record<string, string> = {
rename: "重命名",
relocate: "目录调整",
hardlink: "硬链接",
trash: "移入回收站",
delete: "永久删除",
restore: "从回收站还原",
};
export const organizationActionLabel = (v: string) => ORG_ACTION[v] ?? v;
@@ -17,6 +17,9 @@ const ACTION_LABEL = {
rename: "重命名",
relocate: "目录调整",
hardlink: "硬链接",
trash: "移入回收站",
delete: "永久删除",
restore: "从回收站还原",
} as const;
const VIEW_LABEL = { downloader: "下载器视角", local: "执行进程本地", library: "库根相对" } as const;
const FILE_STATUS: Record<PublicOrganizationFile["status"], { label: string; tone: StatusTone }> = {
+3
View File
@@ -20,6 +20,9 @@ const ACTION_LABEL = {
rename: "重命名",
relocate: "目录调整",
hardlink: "硬链接",
trash: "移入回收站",
delete: "永久删除",
restore: "从回收站还原",
} as const;
function Counts({ r }: { r: PublicOrganizationRecord }) {