Registry-DB (nur Tenant-Metadaten), Provisioning-Routine legt pro Mandant
eine physisch isolierte Postgres-DB an und registriert sie transaktional
(Rollback der DB bei fehlgeschlagener Registrierung). Schlanker HTTP-Handler
als Schnittstellen-Vorbereitung fuer API-01/TEN-02, kein eigenes REST-Grundgerüst.
Pruefungen:
1. Migration up/down geschrieben (0001_tenant_registry.{up,down}.sql) — nicht
gegen echte DB ausgefuehrt, da auf dieser Maschine kein Go/Postgres-Test-
Setup verfuegbar ist. Offen zur Ausfuehrung.
2. Integrationstest TestProvision_CreatesIsolatedDatabases geschrieben (zwei
Mandanten, prueft unterschiedliche db_name und current_database()) —
ebenfalls nicht ausgefuehrt, guarded per TEST_ADMIN_DSN env var. Offen.
3. Slug-Validierung (unit test TestValidateSlug) deckt SQL-Injection-Versuch
im Datenbanknamen ab — ebenfalls nicht lokal ausgefuehrt, da kein Go
Compiler auf dieser Maschine vorhanden ist. Offen.
Alle drei Pruefungen sind vorbereitet, aber NICHT durchgefuehrt worden —
zaehlen laut Vorgabe als offen bis auf einer Maschine mit Go+Postgres verifiziert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
46 lines
1.2 KiB
Go
46 lines
1.2 KiB
Go
package tenant
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
)
|
|
|
|
// Handler ist eine schlanke Vorbereitung der Schnittstelle fuer API-01
|
|
// (REST-API-Grundgerüst & Versionierung) und TEN-02 (Self-Service-Onboarding).
|
|
// Auth/Rate-Limiting/Versionierung selbst sind ausdruecklich nicht Teil von
|
|
// TEN-01 und werden dort nachgezogen.
|
|
type Handler struct {
|
|
provisioner *Provisioner
|
|
}
|
|
|
|
func NewHandler(p *Provisioner) *Handler {
|
|
return &Handler{provisioner: p}
|
|
}
|
|
|
|
type createTenantRequest struct {
|
|
Slug string `json:"slug"`
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
func (h *Handler) CreateTenant(w http.ResponseWriter, r *http.Request) {
|
|
var req createTenantRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "ungueltige Anfrage", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
t, err := h.provisioner.Provision(r.Context(), req.Slug, req.Name)
|
|
if err != nil {
|
|
if err == ErrInvalidSlug {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
http.Error(w, "tenant konnte nicht angelegt werden", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusCreated)
|
|
_ = json.NewEncoder(w).Encode(t)
|
|
}
|