feat(tenants): provision the product tenant with the registry UUID on create (#21)
ci / shared (push) Successful in 12s
ci / test (push) Failing after 16m8s
ci / image (push) Skipped

This commit was merged in pull request #21.
This commit is contained in:
2026-09-01 21:20:03 +00:00
parent 80565fdbf2
commit a048d47959
6 changed files with 255 additions and 3 deletions
+22
View File
@@ -7,6 +7,7 @@ import (
"regexp"
"time"
"gitea.meghsakha.com/platform/tenant-registry/internal/product"
"gitea.meghsakha.com/platform/tenant-registry/internal/store"
)
@@ -93,6 +94,27 @@ func (s *Server) createTenant(w http.ResponseWriter, r *http.Request) {
})
}
// Best-effort product provisioning, same contract as Keycloak above: the
// registry is the authority for tenant identity, so the product gets a row
// keyed by OUR uuid. A failure must not roll the tenant back — it is
// recorded as an audit event so the divergence is traceable and fixable.
// Without this the anchors drift and the product's gate rejects every
// request from the tenant because it cannot resolve the org slug.
if perr := s.productProvisioner().ProvisionTenant(ctx, product.Tenant{
ID: t.ID, Name: t.Name, Slug: t.Slug,
}); perr != nil {
s.emitAudit(ctx, r, store.AuditEvent{
TenantID: t.ID, Action: "product.provision_failed",
TargetID: t.ID, TargetType: "tenant",
Metadata: map[string]interface{}{"err": perr.Error()},
})
} else {
s.emitAudit(ctx, r, store.AuditEvent{
TenantID: t.ID, Action: "product.tenant_provisioned",
TargetID: t.ID, TargetType: "tenant",
})
}
writeJSON(w, http.StatusCreated, createTenantResp{Tenant: t, InviteURL: inviteURL})
}