Tenant Status Lifecycle
Every tenant progresses through a defined set of status states. The TenantStatus enum and the TenantController suspension/activation/deletion endpoints manage these transitions.
Status States
public enum TenantStatus {
PENDING, // Created but not provisioned
PROVISIONING, // Provisioning in progress
ACTIVE, // Fully provisioned and active
UPGRADING, // Tier upgrade in progress
SUSPENDED, // Temporarily suspended
PENDING_DELETION, // Marked for deletion, in grace period
FAILED, // Provisioning failed
DELETED // Soft deleted
}State Transition Diagram
PENDING --> PROVISIONING --> ACTIVE --> SUSPENDED --> ACTIVE
| | |
v v v
FAILED UPGRADING --> ACTIVE DELETED
| |
v v
(retry) --> FAILED
PROVISIONINGSuspend Tenant
Only ACTIVE tenants can be suspended. Suspension disables access but preserves all data and infrastructure:
curl -X POST http://localhost:8082/api/v1/tenants/{id}/suspend?reason=non-payment \
-H "Authorization: Bearer $TOKEN"The service validates the current status:
public TenantResponse suspendTenant(UUID id, String reason) {
Tenant tenant = findTenantById(id);
if (tenant.getStatus() != TenantStatus.ACTIVE) {
throw new TenantProvisioningException("Can only suspend active tenants");
}
tenant.setStatus(TenantStatus.SUSPENDED);
tenant = tenantRepository.save(tenant);
return tenantMapper.toResponse(tenant);
}Activate Tenant
Only SUSPENDED tenants can be reactivated:
curl -X POST http://localhost:8082/api/v1/tenants/{id}/activate \
-H "Authorization: Bearer $TOKEN"Delete Tenant
Deletion is a soft delete that marks the tenant with deleted=true and sets the status to DELETED:
curl -X DELETE http://localhost:8082/api/v1/tenants/{id} \
-H "Authorization: Bearer $TOKEN"The Tenant.markAsDeleted() method handles the state transition:
public void markAsDeleted() {
this.deleted = true;
this.deletedAt = Instant.now();
this.status = TenantStatus.DELETED;
}Advanced Deletion Workflow
For tenants requiring compliance review, legal holds, and grace periods, the TenantDeletionController at /api/v1/tenants/{tenantId}/deletion provides a full deletion workflow:
| Method | Path | Description |
|---|---|---|
POST | /deletion/request | Initiate deletion request |
POST | /deletion/confirm | Confirm with token |
POST | /deletion/cancel | Cancel pending deletion |
POST | /deletion/legal-hold | Place legal hold |
DELETE | /deletion/legal-hold | Clear legal hold |
POST | /deletion/compliance-review | Mark compliance reviewed |
POST | /deletion/execute | Force execute (admin) |
POST | /deletion/retry | Retry failed deletion |
GET | /deletion/timeline | Get deletion timeline |
The deletion workflow includes grace periods, confirmation tokens, legal hold management, GDPR compliance review, and retry capabilities for failed deletions.
Trial and Playground Lifecycle
Tenants can be in trial or playground mode with automatic expiration:
// Trial management
public boolean isTrialActive() {
return Boolean.TRUE.equals(isTrial)
&& trialExpiresAt != null
&& Instant.now().isBefore(trialExpiresAt)
&& status == TenantStatus.ACTIVE;
}
// Playground management
public boolean isPlaygroundActive() {
return Boolean.TRUE.equals(isPlayground)
&& playgroundExpiresAt != null
&& Instant.now().isBefore(playgroundExpiresAt)
&& status == TenantStatus.ACTIVE;
}Trials can be extended via tenant.extendTrial(additionalDays) and converted to paid subscriptions via tenant.convertFromTrial().
Source Files
| File | Path |
|---|---|
| TenantController | control-plane/tenant-service/src/main/java/com/matih/tenant/controller/TenantController.java |
| DeletionController | control-plane/tenant-service/src/main/java/com/matih/tenant/controller/TenantDeletionController.java |
| TenantService | control-plane/tenant-service/src/main/java/com/matih/tenant/service/TenantService.java |
| DeletionService | control-plane/tenant-service/src/main/java/com/matih/tenant/service/TenantDeletionService.java |
| Tenant entity | control-plane/tenant-service/src/main/java/com/matih/tenant/entity/Tenant.java |