// licadmin-devserver stellt das LIC-04-Backend-API (internal/adminapi) fuer // die Next.js-Verwaltungsoberflaeche bereit. Getrennt von cmd/core, da die // Verdrahtung von license.Validator (Ed25519-Public-Key) in die zentrale // Server-Topologie erst mit API-01/IAM-01 (Auth vor internen Endpunkten) // sinnvoll ist — dieser Server dient der Entwicklung/dem Betrieb der // Verwaltungsoberflaeche gegen eine echte Datenbank, ohne cmd/core // anzufassen (Kein Umbau angrenzender Bereiche). package main import ( "context" "crypto/ed25519" "encoding/base64" "log" "net/http" "os" "time" "gitea.perlbach24.de/scripte/nexarch/internal/adminapi" "gitea.perlbach24.de/scripte/nexarch/internal/db" "gitea.perlbach24.de/scripte/nexarch/internal/flag" "gitea.perlbach24.de/scripte/nexarch/internal/license" "gitea.perlbach24.de/scripte/nexarch/internal/usage" ) func main() { dsn := os.Getenv("NEXARCH_REGISTRY_DSN") if dsn == "" { log.Fatal("NEXARCH_REGISTRY_DSN nicht gesetzt") } pubKeyB64 := os.Getenv("NEXARCH_LICENSE_PUBLIC_KEY") if pubKeyB64 == "" { log.Fatal("NEXARCH_LICENSE_PUBLIC_KEY nicht gesetzt (base64, raw-url-encoding)") } pubKeyRaw, err := base64.RawURLEncoding.DecodeString(pubKeyB64) if err != nil || len(pubKeyRaw) != ed25519.PublicKeySize { log.Fatalf("NEXARCH_LICENSE_PUBLIC_KEY ungueltig: %v", err) } addr := os.Getenv("NEXARCH_LICADMIN_LISTEN_ADDR") if addr == "" { addr = ":8081" } ctx := context.Background() pool, err := db.Connect(ctx, dsn) if err != nil { log.Fatalf("db: %v", err) } defer pool.Close() licenseStore := license.NewStore(pool, license.NewValidator(ed25519.PublicKey(pubKeyRaw))) flagStore := flag.NewStore(pool) flagService := flag.NewService(flagStore, 5*time.Second) usageStore := usage.NewStore(pool) handler := adminapi.NewHandler(licenseStore, flagStore, flagService, usageStore) mux := http.NewServeMux() mux.HandleFunc("/admin/overview", withCORS(handler.OverviewHandler)) mux.HandleFunc("/admin/flags/toggle", withCORS(handler.ToggleFlagHandler)) mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) log.Printf("licadmin-devserver listening on %s", addr) log.Fatal(http.ListenAndServe(addr, mux)) } // withCORS erlaubt lokale Entwicklung des Next.js-Frontends auf einem // anderen Port als das Backend-API — ausschliesslich fuer diesen // Entwicklungsserver, keine Produktionshaertung. func withCORS(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") if r.Method == http.MethodOptions { w.WriteHeader(http.StatusOK) return } next(w, r) } }