Locks: admin-configurable expiry cap for manual user locks (deferred from #315 L4) #394
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Cordy/Cairn#394
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Deferred from #315 (design point L4, shipped v0.6.106 / PR #393 without it). Manual (
user-type) locks are currently indefinite — a lock set by a user who then goes on holiday stays until someone with rights breaks it. L4 ratified an optional instance-wide cap, off by default.What to build
Setting.
lockMaxHours(int, 0 = off/indefinite, the default) ininternal/settings— runtime setting via the existingGET/PUT /api/v1/settings, validated>= 0. Naming follows the existing settings style.Enforcement. In
internal/storage/filelock, treat auser-type lock as expired whenlockMaxHours > 0andnow > rec.At + cap. Two options, decide at implementation:MaxAge func() time.Durationhook onStore, consulted inRecord.live()foruserlocks (dav locks keep their ownExpires). Wired inmain.gofrom the settings store. Changing the setting immediately re-evaluates existing locks — no migration, no rewrite oflocks.json.Expiresat lock creation. Rejected in L4 discussion: a later cap change would not affect existing locks, and cap-off would strand old expiries.Option 1 is the recommendation — the cap is a policy lens over stored facts, not stored state.
Admin UI. One quiet-field row (design-system
.srowtreatment, 104px input + unit suffix "hours", 0 = "no limit" helper text) in the admin dashboard. Placement: Basic settings, near the other instance-behaviour toggles (final placement at implementation; Retention & holds is wrong — locks are not retention).API/UX detail. When a manual lock lapses via the cap, it simply stops being live (lazy, like dav expiry): chip disappears on next listing, writes pass. No notification in v1.
Tests.
live()respects the hook for user locks only; hook nil = indefinite (existing tests stay valid); cap change takes effect without restart; settings validation.Refs: #315 comment L1–L10 (id 3386),
internal/storage/filelock/filelock.go(Record.live),internal/settings, PR #393.