Seat lifecycle: 90-day window, Seats tab, audited manual release (#428) #429

Merged
Cordy merged 10 commits from seat-lifecycle-428 into main 2026-09-05 03:54:35 +00:00
Owner

Implements #428 (issue stays open for live verification and the parked check-in payload question).

  • A seat is a person who signed in within the last 90 days. Admit refreshes last-seen (throttled to one write per day); windowed counting feeds Status.SeatsUsed, the admission cap, and both check-in paths. Legacy first-seen timestamps count as last-seen (self-healing migration).
  • Seats() lists current holders newest-first; ReleaseSeat() forgets a holder immediately. New admin endpoints GET /api/v1/license/seats and POST /api/v1/license/seats/release; a release lands in the audit log as seat-release (actor = admin, path = freed holder).
  • Users & access gains tabs (Access | Seats) per the approved mockup: stat header with the 90-day sentence, per-holder rows with Active/Idle/Aging-out chips and last-seen, kebab release with confirm dialog, audit footer. Deep link #admin/users/seats works.
  • Licence page: licSeatsFoot restates the 90-day definition ×4 locales, plus a "manage seats in Users & access" link to the Seats tab.
  • Docs: CHANGELOG v0.6.129, licensing-faq seat definition updated.

TDD evidence in the tdd-428 run log: RED A (window assertions), RED B (api compile-red), RED C (Seats/ReleaseSeat compile-red) all watched failing before their implementations landed in the same run; full suite green after.

Implements #428 (issue stays open for live verification and the parked check-in payload question). - A seat is a person who signed in within the last 90 days. `Admit` refreshes last-seen (throttled to one write per day); windowed counting feeds `Status.SeatsUsed`, the admission cap, and both check-in paths. Legacy first-seen timestamps count as last-seen (self-healing migration). - `Seats()` lists current holders newest-first; `ReleaseSeat()` forgets a holder immediately. New admin endpoints `GET /api/v1/license/seats` and `POST /api/v1/license/seats/release`; a release lands in the audit log as `seat-release` (actor = admin, path = freed holder). - Users & access gains tabs (Access | Seats) per the approved mockup: stat header with the 90-day sentence, per-holder rows with Active/Idle/Aging-out chips and last-seen, kebab release with confirm dialog, audit footer. Deep link `#admin/users/seats` works. - Licence page: `licSeatsFoot` restates the 90-day definition ×4 locales, plus a "manage seats in Users & access" link to the Seats tab. - Docs: CHANGELOG v0.6.129, licensing-faq seat definition updated. TDD evidence in the tdd-428 run log: RED A (window assertions), RED B (api compile-red), RED C (Seats/ReleaseSeat compile-red) all watched failing before their implementations landed in the same run; full suite green after.
Seat lifecycle (#428): 90-day window, last-seen refresh, Seats tab, audited release
All checks were successful
ci / test-and-build (pull_request) Successful in 42s
63c63f7a83
A seat is a person who signed in within the last 90 days. Sign-ins refresh
last-seen (one write per day); aged-out seats free themselves; admins can
release a seat immediately (audit action seat-release). Users & access
gains Access|Seats tabs; the licence meter footer states the window and
links to the Seats tab. Red evidence for window aging, refresh, throttle,
release and the audit event is in this run's log, watched before the
implementation landed.
Cordy merged commit 3eb042bb7e into main 2026-09-05 03:54:35 +00:00
Cordy deleted branch seat-lifecycle-428 2026-09-05 03:54:37 +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#429
No description provided.