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>
52 lines
1.4 KiB
Go
52 lines
1.4 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
// Config holds startup configuration for the core module.
|
|
// RegistryDSN points at the control-plane registry DB (tenant list,
|
|
// connection info, superadmin accounts) — see nexarch-state.json
|
|
// multi_tenancy: Modell C (physisch getrennte DB pro Mandant).
|
|
type Config struct {
|
|
ListenAddr string
|
|
// RegistryDSN verbindet zur Control-Plane-Registry-Datenbank.
|
|
RegistryDSN string
|
|
// AdminDSN verbindet zur Wartungsdatenbank (z.B. "postgres") und wird nur
|
|
// fuer CREATE/DROP DATABASE beim Tenant-Provisioning verwendet.
|
|
AdminDSN string
|
|
// TenantDSNTemplate enthaelt genau ein "%s" als Platzhalter fuer den
|
|
// Datenbanknamen einer neu provisionierten Tenant-Datenbank.
|
|
TenantDSNTemplate string
|
|
}
|
|
|
|
func Load() (Config, error) {
|
|
dsn := os.Getenv("NEXARCH_REGISTRY_DSN")
|
|
if dsn == "" {
|
|
return Config{}, fmt.Errorf("NEXARCH_REGISTRY_DSN not set")
|
|
}
|
|
|
|
adminDSN := os.Getenv("NEXARCH_ADMIN_DSN")
|
|
if adminDSN == "" {
|
|
return Config{}, fmt.Errorf("NEXARCH_ADMIN_DSN not set")
|
|
}
|
|
|
|
dsnTemplate := os.Getenv("NEXARCH_TENANT_DSN_TEMPLATE")
|
|
if dsnTemplate == "" {
|
|
return Config{}, fmt.Errorf("NEXARCH_TENANT_DSN_TEMPLATE not set")
|
|
}
|
|
|
|
addr := os.Getenv("NEXARCH_LISTEN_ADDR")
|
|
if addr == "" {
|
|
addr = ":8080"
|
|
}
|
|
|
|
return Config{
|
|
ListenAddr: addr,
|
|
RegistryDSN: dsn,
|
|
AdminDSN: adminDSN,
|
|
TenantDSNTemplate: dsnTemplate,
|
|
}, nil
|
|
}
|