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>
49 lines
1.2 KiB
Go
49 lines
1.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"net/http"
|
|
|
|
"gitea.perlbach24.de/scripte/nexarch/internal/config"
|
|
"gitea.perlbach24.de/scripte/nexarch/internal/db"
|
|
"gitea.perlbach24.de/scripte/nexarch/internal/tenant"
|
|
)
|
|
|
|
func main() {
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
log.Fatalf("config: %v", err)
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
registryPool, err := db.Connect(ctx, cfg.RegistryDSN)
|
|
if err != nil {
|
|
log.Fatalf("registry db: %v", err)
|
|
}
|
|
defer registryPool.Close()
|
|
|
|
adminPool, err := db.Connect(ctx, cfg.AdminDSN)
|
|
if err != nil {
|
|
log.Fatalf("admin db: %v", err)
|
|
}
|
|
defer adminPool.Close()
|
|
|
|
registry := tenant.NewRegistry(registryPool)
|
|
provisioner := tenant.NewProvisioner(adminPool, registry, cfg.TenantDSNTemplate)
|
|
tenantHandler := tenant.NewHandler(provisioner)
|
|
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
// Vorlaeufiger Pfad ohne Versionierung/Auth — wird mit API-01/IAM-01 abgeloest.
|
|
mux.HandleFunc("/internal/tenants", tenantHandler.CreateTenant)
|
|
|
|
log.Printf("nexarch-core listening on %s", cfg.ListenAddr)
|
|
if err := http.ListenAndServe(cfg.ListenAddr, mux); err != nil {
|
|
log.Fatalf("server: %v", err)
|
|
}
|
|
}
|