#286: Space lifecycle — Deactivate → Delete, contents to trash, name tombstone (v0.6.54) #289

Merged
Cordy merged 3 commits from feat/space286 into main 2026-08-19 22:02:57 +00:00
Owner

Implements the #268 decisions, per the signed-off mockup. Fixes the dogfood finding that a space owner had no way to delete their space.

spacestore

  • Space gains Deactivated / DeletedAt / KeepUntil. RoleFor: deactivated → owner-only read; tombstoned → nothing. SpacesForUser: members lose deactivated spaces, the owner keeps them; tombstones vanish. Since scope.go consumes exactly these two functions, visibility filtering needs zero scope changes.
  • SetDeactivated (reversible), DeleteTombstone (refuses non-deactivated with ErrActive, clears members, reserves the name until keepUntil). Create refuses tombstoned names (ErrTombstoned) until expiry — closes the name-reuse resurrection pitfall.
  • Lifecycle tests incl. tombstone expiry, on the existing newStore harness.

API (owner-or-admin; app-owned only, 501 on IdP-managed)

  • GET /api/v1/spaces (manageable spaces + retentionDays), GET …/{name}/state, POST …/deactivate|reactivate, DELETE /api/v1/spaces/{name}.
  • Delete requires deactivation (409), moves /spaces/<name> into the caller's trash as one recoverable entry (a hold inside refuses the move and aborts — hold.Wrap sits outside trash in the stack), tombstones for the retention window (trashAutoPurgeAfter, 90d fallback, wired in main.go). Audited: space-deactivate / space-reactivate / space-delete.

UI (fidelity-diffed against the mockup)

  • Space-root rows get a dedicated ⋯ menu: Details, then Deactivate (pause icon) or Reactivate (play) + red "Delete space…" — Delete only offered when deactivated.
  • Delete dialog: name in title, facts box (contents → Deleted files for {days} days; name reserved; holds protection), Cancel + filled red confirm.
  • File-listing guard message now points at the menu. Deviation vs mockup (noted at sign-off follow-up): no per-row "deactivated" pill in the listing yet — the state shows in the menu; pill can follow once row-DOM decoration is scouted.

Known edges (documented): restoring the trashed space folder restores files, not membership (the tombstone still blocks recreation); an early manual purge does not shorten the name reservation.

Implements the #268 decisions, per the signed-off mockup. Fixes the dogfood finding that a space owner had no way to delete their space. **spacestore** - `Space` gains `Deactivated` / `DeletedAt` / `KeepUntil`. `RoleFor`: deactivated → owner-only read; tombstoned → nothing. `SpacesForUser`: members lose deactivated spaces, the owner keeps them; tombstones vanish. Since scope.go consumes exactly these two functions, **visibility filtering needs zero scope changes**. - `SetDeactivated` (reversible), `DeleteTombstone` (refuses non-deactivated with `ErrActive`, clears members, reserves the name until keepUntil). `Create` refuses tombstoned names (`ErrTombstoned`) until expiry — closes the name-reuse resurrection pitfall. - Lifecycle tests incl. tombstone expiry, on the existing `newStore` harness. **API** (owner-or-admin; app-owned only, 501 on IdP-managed) - `GET /api/v1/spaces` (manageable spaces + retentionDays), `GET …/{name}/state`, `POST …/deactivate|reactivate`, `DELETE /api/v1/spaces/{name}`. - Delete requires deactivation (409), moves `/spaces/<name>` into the caller's trash as one recoverable entry (a hold inside refuses the move and aborts — hold.Wrap sits outside trash in the stack), tombstones for the retention window (`trashAutoPurgeAfter`, 90d fallback, wired in main.go). Audited: `space-deactivate` / `space-reactivate` / `space-delete`. **UI** (fidelity-diffed against the mockup) - Space-root rows get a dedicated ⋯ menu: Details, then Deactivate (pause icon) or Reactivate (play) + red "Delete space…" — Delete only offered when deactivated. - Delete dialog: name in title, facts box (contents → Deleted files for {days} days; name reserved; holds protection), Cancel + filled red confirm. - File-listing guard message now points at the menu. Deviation vs mockup (noted at sign-off follow-up): no per-row "deactivated" pill in the listing yet — the state shows in the menu; pill can follow once row-DOM decoration is scouted. Known edges (documented): restoring the trashed space folder restores files, not membership (the tombstone still blocks recreation); an early manual purge does not shorten the name reservation.
Cordy merged commit 5629ca847f into main 2026-08-19 22:02:57 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#289
No description provided.