Skip to content

feat(tenants): TenantStatus enum + status endpoint + optional mode#17

Merged
jlc488 merged 1 commit into
mainfrom
feat/tenants-status-enum
May 27, 2026
Merged

feat(tenants): TenantStatus enum + status endpoint + optional mode#17
jlc488 merged 1 commit into
mainfrom
feat/tenants-status-enum

Conversation

@jlc488
Copy link
Copy Markdown
Contributor

@jlc488 jlc488 commented May 27, 2026

Fourth PR in the admin-ui ↔ backend contract-gap series (after #14 menus, #15 audit-logs, #16 policies). The Tenants page needs a three-state lifecycle (ACTIVE / SUSPENDED / ARCHIVED) and a single setStatus endpoint, not the boolean active flag plus two separate /activate / /deactivate routes; it also doesn't send mode when provisioning a tenant.

Summary

Status enum

  • New TenantStatus enum in tenant-api: ACTIVE / SUSPENDED / ARCHIVED. Vocabulary matches the UI Tag set so wire shape and presentation line up without translation.

Schema (V10) — online-safe rewrite of platform_tenant

  1. ADD COLUMN status VARCHAR(16) (nullable).
  2. UPDATE back-fill: active = true → 'ACTIVE', active = false → 'SUSPENDED' (treat as "paused", not "soft-deleted").
  3. ALTER COLUMN status SET NOT NULL, swap idx_platform_tenant_activeidx_platform_tenant_status, DROP COLUMN active.

Entity / metadata

  • PlatformTenantEntity: active booleanstatus TenantStatus (@Enumerated(STRING)). All-args constructor updated.
  • TenantMetadata: active booleanstatus TenantStatus, with a null-check in the canonical constructor.

Service

  • TenantService gains setStatus(id, status) as the primary lifecycle method.
  • activate(id) / deactivate(id) demoted to default methods that dispatch through setStatus(ACTIVE) / setStatus(SUSPENDED). All prior callers keep working unchanged.
  • DefaultTenantService.create now persists status = ACTIVE on new tenants.

Controller

  • POST /tenants: mode is now optional (defaults to TenantMode.SINGLE when the UI doesn't send it).
  • PUT /tenants/{id}/status (new): the admin UI's single setter; body is { "status": "ACTIVE" | "SUSPENDED" | "ARCHIVED" }.
  • PUT /tenants/{id}/activate and /deactivate kept as backward-compatible shortcuts that route through setStatus.

Test plan

  • ./gradlew build green (55 tasks, all sample-app + tenant-core tests pass; migration runs cleanly against Testcontainers Postgres)
  • Manual: provision a tenant via the admin UI without mode, change status to SUSPENDED, archive

Closes the series

This was the last large gap. The Diagnostics + Settings field-name mismatches (cosmetic JSON-key renames) can land as a small follow-up PR or be absorbed on the admin-ui side, depending on which direction you prefer.

Closes the fourth contract gap with the admin UI. The Tenants page
needs three-state lifecycle (ACTIVE / SUSPENDED / ARCHIVED) and a
single setStatus endpoint, not the boolean active flag plus two
separate /activate /deactivate routes; it also doesn't send `mode`
when provisioning a tenant.

Status enum
-----------
- New TenantStatus enum in tenant-api: ACTIVE / SUSPENDED / ARCHIVED.
  Vocabulary matches the UI Tag set so wire shape and presentation
  line up without translation.

Schema (V10)
------------
- Three-step online-safe rewrite of platform_tenant:
    1. add nullable status VARCHAR(16),
    2. back-fill from active (true -> ACTIVE, false -> SUSPENDED),
    3. swap NOT NULL + indexes and drop active.
- New idx_platform_tenant_status replaces the old idx_..._active.

Entity / metadata
-----------------
- PlatformTenantEntity: active boolean -> status TenantStatus
  (@Enumerated STRING). All-args constructor updated.
- TenantMetadata: active boolean -> status TenantStatus, with
  null-check in the canonical constructor.

Service
-------
- TenantService gains setStatus(id, status) as the primary lifecycle
  method.
- activate(id) / deactivate(id) demoted to default methods that
  dispatch through setStatus(ACTIVE) / setStatus(SUSPENDED). All
  prior callers keep working.
- DefaultTenantService.create now persists status = ACTIVE on new
  tenants.

Controller
----------
- POST /tenants: mode is now optional (defaults to TenantMode.SINGLE
  when the UI doesn't send it).
- PUT /tenants/{id}/status (new): the admin UI's single setter; body
  is {"status": "ACTIVE" | "SUSPENDED" | "ARCHIVED"}.
- PUT /tenants/{id}/activate and /deactivate kept as backward-
  compatible shortcuts that route through setStatus.
@jlc488 jlc488 merged commit 08c71d9 into main May 27, 2026
1 check passed
@jlc488 jlc488 deleted the feat/tenants-status-enum branch May 30, 2026 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant