forked from EduCraft/curriculum-project-hub
fix(filelib): 恢复撞名不再死锁,自动改名「(已恢复)」(ADR-0033)
- restore 前查活跃兄弟:撞名则恢复为「原名(已恢复[/ N])」(截断计入 128 长度预算),同事务落审计并记 renamedFrom;API 返回最终名 - BinView toast 提示改名;测试补撞名/二次恢复用例
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
# ADR 0033: Restore De-Duplicates The Node Name On Sibling Conflict
|
||||
|
||||
## Status
|
||||
|
||||
Accepted.
|
||||
|
||||
## Context
|
||||
|
||||
ADR-0031 defined restore as "clear `deletedAt` on that node only". It did not cover
|
||||
the case where a same-name sibling was created **after** the deletion: D14's partial
|
||||
unique index (active siblings, case-insensitive) then rejects the restore with a 409
|
||||
`conflict`, leaving the entry permanently stuck in the bin — unrecoverable for
|
||||
non-admin users (who cannot purge) and cryptic for admins.
|
||||
|
||||
## Decision
|
||||
|
||||
Restore never fails on a name conflict. Before clearing `deletedAt`, the service
|
||||
checks active siblings; if the node's name is taken, it restores as
|
||||
`原名(已恢复)`, then `原名(已恢复 2)`, …, first free key wins (suffix is included
|
||||
in the `NODE_NAME_MAX_LENGTH` budget by truncating the base). The rename is part of
|
||||
the same transaction and is recorded in the restore audit entry as
|
||||
`{ name, renamedFrom }`. The API returns the final name so the UI can tell the user.
|
||||
|
||||
Rationale: the bin's purpose is recovery; a restore that can deadlock on naming is a
|
||||
trap, not a safeguard. Users who care about the name can rename afterwards (they have
|
||||
MANAGE by definition of bin visibility).
|
||||
Reference in New Issue
Block a user