diff --git a/Makefile b/Makefile
index 2cbf5336..e3a0b67b 100755
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,6 @@ db_host=hyperfleet-db.$(namespace)
 db_port=5432
 db_user:=hyperfleet
 db_password:=foobar-bizz-buzz
-db_password_file=${PWD}/secrets/db.password
 db_sslmode:=disable
 db_image?=docker.io/library/postgres:14.2
 
@@ -152,20 +151,6 @@ install: check-gopath generate-all
 		)
 .PHONY: install
 
-# Initialize secrets directory with default values
-secrets:
-	@mkdir -p secrets
-	@printf "localhost" > secrets/db.host
-	@printf "$(db_name)" > secrets/db.name
-	@printf "$(db_password)" > secrets/db.password
-	@printf "$(db_port)" > secrets/db.port
-	@printf "$(db_user)" > secrets/db.user
-	@printf "ocm-hyperfleet-testing" > secrets/ocm-service.clientId
-	@printf "your-client-secret-here" > secrets/ocm-service.clientSecret
-	@printf "your-token-here" > secrets/ocm-service.token
-	@echo "Secrets directory initialized with default values"
-.PHONY: secrets
-
 # Runs the unit tests.
 #
 # Args:
@@ -173,8 +158,16 @@ secrets:
 #
 # Examples:
 #   make test TESTFLAGS="-run TestSomething"
-test: install secrets $(GOTESTSUM)
-	OCM_ENV=unit_testing $(GOTESTSUM) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -v $(TESTFLAGS) \
+test: install $(GOTESTSUM)
+	OCM_ENV=unit_testing \
+	HYPERFLEET_APP_NAME=hyperfleet-api-test \
+	HYPERFLEET_OCM_MOCK=true \
+	HYPERFLEET_OCM_DEBUG=false \
+	HYPERFLEET_OCM_BASE_URL=https://api.integration.openshift.com \
+	HYPERFLEET_SERVER_HTTPS_ENABLED=false \
+	HYPERFLEET_METRICS_HTTPS_ENABLED=false \
+	HYPERFLEET_AUTH_AUTHZ_ENABLED=true \
+	$(GOTESTSUM) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -v $(TESTFLAGS) \
 		./pkg/... \
 		./cmd/...
 .PHONY: test
@@ -186,8 +179,16 @@ test: install secrets $(GOTESTSUM)
 #
 # Examples:
 #   make test-unit-json TESTFLAGS="-run TestSomething"
-ci-test-unit: install secrets $(GOTESTSUM)
-	OCM_ENV=unit_testing $(GOTESTSUM) --jsonfile-timing-events=$(unit_test_json_output) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -v $(TESTFLAGS) \
+ci-test-unit: install $(GOTESTSUM)
+	OCM_ENV=unit_testing \
+	HYPERFLEET_APP_NAME=hyperfleet-api-test \
+	HYPERFLEET_OCM_MOCK=true \
+	HYPERFLEET_OCM_DEBUG=false \
+	HYPERFLEET_OCM_BASE_URL=https://api.integration.openshift.com \
+	HYPERFLEET_SERVER_HTTPS_ENABLED=false \
+	HYPERFLEET_METRICS_HTTPS_ENABLED=false \
+	HYPERFLEET_AUTH_AUTHZ_ENABLED=true \
+	$(GOTESTSUM) --jsonfile-timing-events=$(unit_test_json_output) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -v $(TESTFLAGS) \
 		./pkg/... \
 		./cmd/...
 .PHONY: ci-test-unit
@@ -202,8 +203,17 @@ ci-test-unit: install secrets $(GOTESTSUM)
 #   make test-integration TESTFLAGS="-run TestAccounts"     acts as TestAccounts* and run TestAccountsGet, TestAccountsPost, etc.
 #   make test-integration TESTFLAGS="-run TestAccountsGet"  runs TestAccountsGet
 #   make test-integration TESTFLAGS="-short"                skips long-run tests
-ci-test-integration: install secrets $(GOTESTSUM)
-	TESTCONTAINERS_RYUK_DISABLED=true OCM_ENV=integration_testing $(GOTESTSUM) --jsonfile-timing-events=$(integration_test_json_output) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -ldflags -s -v -timeout 1h $(TESTFLAGS) \
+ci-test-integration: install $(GOTESTSUM)
+	TESTCONTAINERS_RYUK_DISABLED=true \
+	OCM_ENV=integration_testing \
+	HYPERFLEET_APP_NAME=hyperfleet-api-integration-test \
+	HYPERFLEET_OCM_MOCK=true \
+	HYPERFLEET_OCM_DEBUG=false \
+	HYPERFLEET_OCM_BASE_URL=https://api.integration.openshift.com \
+	HYPERFLEET_SERVER_HTTPS_ENABLED=false \
+	HYPERFLEET_METRICS_HTTPS_ENABLED=false \
+	HYPERFLEET_AUTH_AUTHZ_ENABLED=true \
+	$(GOTESTSUM) --jsonfile-timing-events=$(integration_test_json_output) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -ldflags -s -v -timeout 1h $(TESTFLAGS) \
 			./test/integration
 .PHONY: ci-test-integration
 
@@ -217,8 +227,20 @@ ci-test-integration: install secrets $(GOTESTSUM)
 #   make test-integration TESTFLAGS="-run TestAccounts"     acts as TestAccounts* and run TestAccountsGet, TestAccountsPost, etc.
 #   make test-integration TESTFLAGS="-run TestAccountsGet"  runs TestAccountsGet
 #   make test-integration TESTFLAGS="-short"                skips long-run tests
-test-integration: install secrets $(GOTESTSUM)
-	TESTCONTAINERS_RYUK_DISABLED=true OCM_ENV=integration_testing $(GOTESTSUM) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -ldflags -s -v -timeout 1h $(TESTFLAGS) \
+test-integration: install $(GOTESTSUM)
+	TESTCONTAINERS_RYUK_DISABLED=true \
+	OCM_ENV=integration_testing \
+	HYPERFLEET_APP_NAME=hyperfleet-api-integration-test \
+	HYPERFLEET_OCM_MOCK=true \
+	HYPERFLEET_OCM_DEBUG=false \
+	HYPERFLEET_OCM_BASE_URL=https://api.integration.openshift.com \
+	HYPERFLEET_SERVER_HTTPS_ENABLED=false \
+	HYPERFLEET_METRICS_HTTPS_ENABLED=false \
+	HYPERFLEET_SERVER_AUTH_AUTHZ_ENABLED=false \
+	HYPERFLEET_DATABASE_NAME=$(db_name) \
+	HYPERFLEET_DATABASE_USERNAME=$(db_user) \
+	HYPERFLEET_DATABASE_PASSWORD=$(db_password) \
+	$(GOTESTSUM) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -ldflags -s -v -timeout 1h $(TESTFLAGS) \
 			./test/integration
 .PHONY: test-integration
 
@@ -268,8 +290,7 @@ run/docs:
 clean:
 	rm -rf \
 		$(binary) \
-		data/generated/openapi/*.json \
-		secrets \
+		data/generated/openapi/*.json
 .PHONY: clean
 
 .PHONY: cmds
@@ -284,8 +305,7 @@ cmds:
 
 
 .PHONY: db/setup
-db/setup: secrets
-	@echo $(db_password) > $(db_password_file)
+db/setup:
 	$(container_tool) run --name psql-hyperfleet -e POSTGRES_DB=$(db_name) -e POSTGRES_USER=$(db_user) -e POSTGRES_PASSWORD=$(db_password) -p $(db_port):5432 -d $(db_image)
 
 .PHONY: db/login
diff --git a/cmd/hyperfleet-api/environments/e_development.go b/cmd/hyperfleet-api/environments/e_development.go
index 6aaa7a1c..26c63adf 100755
--- a/cmd/hyperfleet-api/environments/e_development.go
+++ b/cmd/hyperfleet-api/environments/e_development.go
@@ -18,8 +18,6 @@ func (e *devEnvImpl) OverrideDatabase(c *Database) error {
 }
 
 func (e *devEnvImpl) OverrideConfig(c *config.ApplicationConfig) error {
-	c.Server.EnableJWT = false
-	c.Server.EnableHTTPS = false
 	return nil
 }
 
@@ -34,16 +32,3 @@ func (e *devEnvImpl) OverrideHandlers(h *Handlers) error {
 func (e *devEnvImpl) OverrideClients(c *Clients) error {
 	return nil
 }
-
-func (e *devEnvImpl) Flags() map[string]string {
-	return map[string]string{
-		"v":                      "10",
-		"enable-authz":           "false",
-		"ocm-debug":              "false",
-		"enable-ocm-mock":        "true",
-		"enable-https":           "false",
-		"enable-metrics-https":   "false",
-		"api-server-hostname":    "localhost",
-		"api-server-bindaddress": "localhost:8000",
-	}
-}
diff --git a/cmd/hyperfleet-api/environments/e_integration_testing.go b/cmd/hyperfleet-api/environments/e_integration_testing.go
index 8db7ea08..4cbbc461 100755
--- a/cmd/hyperfleet-api/environments/e_integration_testing.go
+++ b/cmd/hyperfleet-api/environments/e_integration_testing.go
@@ -38,16 +38,3 @@ func (e *integrationTestingEnvImpl) OverrideHandlers(h *Handlers) error {
 func (e *integrationTestingEnvImpl) OverrideClients(c *Clients) error {
 	return nil
 }
-
-func (e *integrationTestingEnvImpl) Flags() map[string]string {
-	return map[string]string{
-		"v":                    "0",
-		"logtostderr":          "true",
-		"ocm-base-url":         "https://api.integration.openshift.com",
-		"enable-https":         "false",
-		"enable-metrics-https": "false",
-		"enable-authz":         "true",
-		"ocm-debug":            "false",
-		"enable-ocm-mock":      "true",
-	}
-}
diff --git a/cmd/hyperfleet-api/environments/e_production.go b/cmd/hyperfleet-api/environments/e_production.go
index 05151e2f..e9bc0c2b 100755
--- a/cmd/hyperfleet-api/environments/e_production.go
+++ b/cmd/hyperfleet-api/environments/e_production.go
@@ -32,11 +32,3 @@ func (e *productionEnvImpl) OverrideHandlers(h *Handlers) error {
 func (e *productionEnvImpl) OverrideClients(c *Clients) error {
 	return nil
 }
-
-func (e *productionEnvImpl) Flags() map[string]string {
-	return map[string]string{
-		"v":               "1",
-		"ocm-debug":       "false",
-		"enable-ocm-mock": "false",
-	}
-}
diff --git a/cmd/hyperfleet-api/environments/e_unit_testing.go b/cmd/hyperfleet-api/environments/e_unit_testing.go
index 81127e3a..1bf6c849 100755
--- a/cmd/hyperfleet-api/environments/e_unit_testing.go
+++ b/cmd/hyperfleet-api/environments/e_unit_testing.go
@@ -38,16 +38,3 @@ func (e *unitTestingEnvImpl) OverrideHandlers(h *Handlers) error {
 func (e *unitTestingEnvImpl) OverrideClients(c *Clients) error {
 	return nil
 }
-
-func (e *unitTestingEnvImpl) Flags() map[string]string {
-	return map[string]string{
-		"v":                    "0",
-		"logtostderr":          "true",
-		"ocm-base-url":         "https://api.integration.openshift.com",
-		"enable-https":         "false",
-		"enable-metrics-https": "false",
-		"enable-authz":         "true",
-		"ocm-debug":            "false",
-		"enable-ocm-mock":      "true",
-	}
-}
diff --git a/cmd/hyperfleet-api/environments/framework.go b/cmd/hyperfleet-api/environments/framework.go
index deaf8f7f..3361da4a 100755
--- a/cmd/hyperfleet-api/environments/framework.go
+++ b/cmd/hyperfleet-api/environments/framework.go
@@ -2,10 +2,8 @@ package environments
 
 import (
 	"os"
-	"strings"
 
 	"github.com/golang/glog"
-	"github.com/spf13/pflag"
 
 	"github.com/openshift-hyperfleet/hyperfleet-api/cmd/hyperfleet-api/environments/registry"
 	"github.com/openshift-hyperfleet/hyperfleet-api/pkg/client/ocm"
@@ -17,8 +15,8 @@ func init() {
 	once.Do(func() {
 		environment = &Env{}
 
-		// Create the configuration
-		environment.Config = config.NewApplicationConfig()
+		// DO NOT create Config here
+		// Config will be provided by commands via Initialize()
 		environment.Name = GetEnvironmentStrFromEnv()
 
 		environments = map[string]EnvironmentImpl{
@@ -31,10 +29,8 @@ func init() {
 }
 
 // EnvironmentImpl defines a set of behaviors for an OCM environment.
-// Each environment provides a set of flags for basic set/override of the environment
-// and configuration functions for each component type.
+// Each environment provides configuration functions for each component type.
 type EnvironmentImpl interface {
-	Flags() map[string]string
 	OverrideConfig(c *config.ApplicationConfig) error
 	OverrideServices(s *Services) error
 	OverrideDatabase(s *Database) error
@@ -54,16 +50,9 @@ func Environment() *Env {
 	return environment
 }
 
-// AddFlags Adds environment flags, using the environment's config struct, to the flagset 'flags'
-func (e *Env) AddFlags(flags *pflag.FlagSet) error {
-	e.Config.AddFlags(flags)
-	return setConfigDefaults(flags, environments[e.Name].Flags())
-}
-
-// Initialize loads the environment's resources
-// This should be called after the e.Config has been set appropriately though AddFlags and pasing, done elsewhere
-// The environment does NOT handle flag parsing
-func (e *Env) Initialize() error {
+// Initialize loads the environment's resources with pre-loaded configuration
+// Configuration must be loaded by the caller using config.LoadConfig()
+func (e *Env) Initialize(appConfig *config.ApplicationConfig) error {
 	glog.Infof("Initializing %s environment", e.Name)
 
 	envImpl, found := environments[e.Name]
@@ -71,20 +60,20 @@ func (e *Env) Initialize() error {
 		glog.Fatalf("Unknown runtime environment: %s", e.Name)
 	}
 
+	// Store the provided config
+	e.Config = appConfig
+
+	// Allow environment to apply runtime overrides (e.g., DB_DEBUG for tests)
 	if err := envImpl.OverrideConfig(e.Config); err != nil {
 		glog.Fatalf("Failed to configure ApplicationConfig: %s", err)
 	}
 
-	messages := environment.Config.ReadFiles()
-	if len(messages) != 0 {
-		glog.Fatalf("unable to read configuration files:\n%s", strings.Join(messages, "\n"))
-	}
-
-	// each env will set db explicitly because the DB impl has a `once` init section
+	// Initialize database with config
 	if err := envImpl.OverrideDatabase(&e.Database); err != nil {
 		glog.Fatalf("Failed to configure Database: %s", err)
 	}
 
+	// Initialize clients
 	err := e.LoadClients()
 	if err != nil {
 		return err
@@ -93,16 +82,19 @@ func (e *Env) Initialize() error {
 		glog.Fatalf("Failed to configure Clients: %s", err)
 	}
 
+	// Initialize services
 	e.LoadServices()
 	if err := envImpl.OverrideServices(&e.Services); err != nil {
 		glog.Fatalf("Failed to configure Services: %s", err)
 	}
 
+	// Seed data
 	seedErr := e.Seed()
 	if seedErr != nil {
 		return seedErr
 	}
 
+	// Initialize handlers
 	if err := envImpl.OverrideHandlers(&e.Handlers); err != nil {
 		glog.Fatalf("Failed to configure Handlers: %s", err)
 	}
@@ -161,13 +153,3 @@ func (e *Env) Teardown() {
 		}
 	}
 }
-
-func setConfigDefaults(flags *pflag.FlagSet, defaults map[string]string) error {
-	for name, value := range defaults {
-		if err := flags.Set(name, value); err != nil {
-			glog.Errorf("Error setting flag %s: %v", name, err)
-			return err
-		}
-	}
-	return nil
-}
diff --git a/cmd/hyperfleet-api/environments/framework_test.go b/cmd/hyperfleet-api/environments/framework_test.go
index 0beaffb3..f53650c9 100755
--- a/cmd/hyperfleet-api/environments/framework_test.go
+++ b/cmd/hyperfleet-api/environments/framework_test.go
@@ -1,11 +1,14 @@
 package environments
 
 import (
+	"os"
 	"os/exec"
 	"reflect"
 	"testing"
 
 	"github.com/spf13/pflag"
+
+	"github.com/openshift-hyperfleet/hyperfleet-api/pkg/config"
 )
 
 func BenchmarkGetDynos(b *testing.B) {
@@ -23,16 +26,36 @@ func BenchmarkGetDynos(b *testing.B) {
 }
 
 func TestLoadServices(t *testing.T) {
-	env := Environment()
-	err := env.AddFlags(pflag.CommandLine)
+	// Set required environment variables for testing
+	os.Setenv("HYPERFLEET_APP_NAME", "hyperfleet-api-test")
+	os.Setenv("HYPERFLEET_OCM_MOCK", "true")
+	os.Setenv("HYPERFLEET_OCM_DEBUG", "false")
+	os.Setenv("HYPERFLEET_OCM_BASE_URL", "https://api.integration.openshift.com")
+	os.Setenv("HYPERFLEET_SERVER_HTTPS_ENABLED", "false")
+	os.Setenv("HYPERFLEET_METRICS_HTTPS_ENABLED", "false")
+	os.Setenv("HYPERFLEET_AUTH_AUTHZ_ENABLED", "true")
+
+	// Create config
+	appConfig := config.NewApplicationConfig()
+
+	// Create viper and configure flags
+	v := config.NewCommandConfig()
+	appConfig.ConfigureFlags(v, pflag.CommandLine)
+
+	pflag.Parse()
+
+	// Load config
+	loadedConfig, err := config.LoadConfig(v, pflag.CommandLine)
 	if err != nil {
-		t.Errorf("Unable to add flags for testing environment: %s", err.Error())
+		t.Errorf("Failed to load configuration: %v", err)
 		return
 	}
-	pflag.Parse()
-	err = env.Initialize()
+
+	// Initialize environment with loaded config
+	env := Environment()
+	err = env.Initialize(loadedConfig)
 	if err != nil {
-		t.Errorf("Unable to load testing environment: %s", err.Error())
+		t.Errorf("Unable to initialize testing environment: %s", err.Error())
 		return
 	}
 
diff --git a/cmd/hyperfleet-api/migrate/cmd.go b/cmd/hyperfleet-api/migrate/cmd.go
index adcbb71b..c9f9f801 100755
--- a/cmd/hyperfleet-api/migrate/cmd.go
+++ b/cmd/hyperfleet-api/migrate/cmd.go
@@ -2,40 +2,54 @@ package migrate
 
 import (
 	"context"
-	"flag"
 
 	"github.com/golang/glog"
 	"github.com/openshift-hyperfleet/hyperfleet-api/pkg/db/db_session"
 	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
 
 	"github.com/openshift-hyperfleet/hyperfleet-api/pkg/config"
 	"github.com/openshift-hyperfleet/hyperfleet-api/pkg/db"
 )
 
-var dbConfig = config.NewDatabaseConfig()
-
 // NewMigrateCommand migrate sub-command handles running migrations
 func NewMigrateCommand() *cobra.Command {
+	// Create viper instance for this command (isolated from other commands)
+	v := config.NewCommandConfig()
+
 	cmd := &cobra.Command{
 		Use:   "migrate",
 		Short: "Run hyperfleet service data migrations",
 		Long:  "Run hyperfleet service data migrations",
-		Run:   runMigrate,
+		Run: func(cmd *cobra.Command, args []string) {
+			// v is captured in closure, available here
+			runMigrateWithConfig(v, cmd, args)
+		},
 	}
 
-	dbConfig.AddFlags(cmd.PersistentFlags())
-	cmd.PersistentFlags().AddGoFlagSet(flag.CommandLine)
+	// Create config and configure flags (defines and binds in one step)
+	migrateConfig := config.NewMigrateConfig()
+	migrateConfig.ConfigureFlags(v, cmd.PersistentFlags())
+
 	return cmd
 }
 
-func runMigrate(_ *cobra.Command, _ []string) {
-	err := dbConfig.ReadFiles()
+func runMigrateWithConfig(v *viper.Viper, cmd *cobra.Command, args []string) {
+	// Load configuration using command's viper instance
+	migrateConfig, err := config.LoadMigrateConfig(v, cmd.Flags())
 	if err != nil {
-		glog.Fatal(err)
+		glog.Fatalf("Failed to load configuration: %v", err)
 	}
 
-	connection := db_session.NewProdFactory(dbConfig)
+	glog.Infof("Running database migrations...")
+
+	// Create database connection factory
+	connection := db_session.NewProdFactory(migrateConfig.Database)
+
+	// Run migrations
 	if err := db.Migrate(connection.New(context.Background())); err != nil {
-		glog.Fatal(err)
+		glog.Fatalf("Migration failed: %v", err)
 	}
+
+	glog.Infof("Migrations completed successfully")
 }
diff --git a/cmd/hyperfleet-api/servecmd/cmd.go b/cmd/hyperfleet-api/servecmd/cmd.go
index dce3fd3f..ed624cda 100755
--- a/cmd/hyperfleet-api/servecmd/cmd.go
+++ b/cmd/hyperfleet-api/servecmd/cmd.go
@@ -3,28 +3,49 @@ package servecmd
 import (
 	"github.com/golang/glog"
 	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
 
 	"github.com/openshift-hyperfleet/hyperfleet-api/cmd/hyperfleet-api/environments"
 	"github.com/openshift-hyperfleet/hyperfleet-api/cmd/hyperfleet-api/server"
+	"github.com/openshift-hyperfleet/hyperfleet-api/pkg/config"
 )
 
 func NewServeCommand() *cobra.Command {
+	// Create viper instance for this command (isolated from other commands)
+	v := config.NewCommandConfig()
+
 	cmd := &cobra.Command{
 		Use:   "serve",
 		Short: "Serve the hyperfleet",
 		Long:  "Serve the hyperfleet.",
-		Run:   runServe,
-	}
-	err := environments.Environment().AddFlags(cmd.PersistentFlags())
-	if err != nil {
-		glog.Fatalf("Unable to add environment flags to serve command: %s", err.Error())
+		Run: func(cmd *cobra.Command, args []string) {
+			// v is captured in closure, available here
+			runServeWithViper(v, cmd, args)
+		},
 	}
 
+	// Create config and configure flags (defines and binds in one step)
+	serveConfig := config.NewServeConfig()
+	serveConfig.ConfigureFlags(v, cmd.PersistentFlags())
+
 	return cmd
 }
 
-func runServe(cmd *cobra.Command, args []string) {
-	err := environments.Environment().Initialize()
+func runServeWithViper(v *viper.Viper, cmd *cobra.Command, args []string) {
+	// Load configuration using command's viper instance
+	serveConfig, err := config.LoadServeConfig(v, cmd.Flags())
+	if err != nil {
+		glog.Fatalf("Failed to load configuration: %v", err)
+	}
+
+	// Display merged configuration
+	serveConfig.DisplayConfig()
+
+	// Convert to ApplicationConfig for environment initialization
+	appConfig := serveConfig.ToApplicationConfig()
+
+	// Initialize environment with loaded config
+	err = environments.Environment().Initialize(appConfig)
 	if err != nil {
 		glog.Fatalf("Unable to initialize environment: %s", err.Error())
 	}
diff --git a/cmd/hyperfleet-api/server/api_server.go b/cmd/hyperfleet-api/server/api_server.go
index 58fce4ab..84b7a832 100755
--- a/cmd/hyperfleet-api/server/api_server.go
+++ b/cmd/hyperfleet-api/server/api_server.go
@@ -35,7 +35,7 @@ func NewAPIServer() Server {
 	// referring to the router as type http.Handler allows us to add middleware via more handlers
 	var mainHandler http.Handler = mainRouter
 
-	if env().Config.Server.EnableJWT {
+	if env().Config.Server.Auth.JWT.Enabled {
 		// Create the logger for the authentication handler:
 		authnLogger, err := sdk.NewGlogLoggerBuilder().
 			InfoV(glog.Level(1)).
@@ -46,10 +46,11 @@ func NewAPIServer() Server {
 		// Create the handler that verifies that tokens are valid:
 		mainHandler, err = authentication.NewHandler().
 			Logger(authnLogger).
-			KeysFile(env().Config.Server.JwkCertFile).
-			KeysURL(env().Config.Server.JwkCertURL).
-			ACLFile(env().Config.Server.ACLFile).
+			KeysFile(env().Config.Server.Auth.JWT.CertFile).
+			KeysURL(env().Config.Server.Auth.JWT.CertURL).
+			ACLFile(env().Config.Server.Auth.Authz.ACLFile).
 			Public("^/api/hyperfleet/?$").
+			Public("^/api/hyperfleet/config/?$").
 			Public("^/api/hyperfleet/v1/?$").
 			Public("^/api/hyperfleet/v1/openapi/?$").
 			Public("^/api/hyperfleet/v1/openapi.html/?$").
@@ -96,7 +97,7 @@ func NewAPIServer() Server {
 	mainHandler = removeTrailingSlash(mainHandler)
 
 	s.httpServer = &http.Server{
-		Addr:    env().Config.Server.BindAddress,
+		Addr:    env().Config.Server.GetBindAddress(),
 		Handler: mainHandler,
 	}
 
@@ -107,20 +108,20 @@ func NewAPIServer() Server {
 // Useful for breaking up ListenAndServer (Start) when you require the server to be listening before continuing
 func (s apiServer) Serve(listener net.Listener) {
 	var err error
-	if env().Config.Server.EnableHTTPS {
+	if env().Config.Server.HTTPS.Enabled {
 		// Check https cert and key path path
-		if env().Config.Server.HTTPSCertFile == "" || env().Config.Server.HTTPSKeyFile == "" {
+		if env().Config.Server.HTTPS.CertFile == "" || env().Config.Server.HTTPS.KeyFile == "" {
 			check(
-				fmt.Errorf("unspecified required --https-cert-file, --https-key-file"),
+				fmt.Errorf("unspecified required --server-https-cert-file, --server-https-key-file"),
 				"Can't start https server",
 			)
 		}
 
 		// Serve with TLS
-		glog.Infof("Serving with TLS at %s", env().Config.Server.BindAddress)
-		err = s.httpServer.ServeTLS(listener, env().Config.Server.HTTPSCertFile, env().Config.Server.HTTPSKeyFile)
+		glog.Infof("Serving with TLS at %s", env().Config.Server.GetBindAddress())
+		err = s.httpServer.ServeTLS(listener, env().Config.Server.HTTPS.CertFile, env().Config.Server.HTTPS.KeyFile)
 	} else {
-		glog.Infof("Serving without TLS at %s", env().Config.Server.BindAddress)
+		glog.Infof("Serving without TLS at %s", env().Config.Server.GetBindAddress())
 		err = s.httpServer.Serve(listener)
 	}
 
@@ -132,7 +133,7 @@ func (s apiServer) Serve(listener net.Listener) {
 // Listen only start the listener, not the server.
 // Useful for breaking up ListenAndServer (Start) when you require the server to be listening before continuing
 func (s apiServer) Listen() (listener net.Listener, err error) {
-	return net.Listen("tcp", env().Config.Server.BindAddress)
+	return net.Listen("tcp", env().Config.Server.GetBindAddress())
 }
 
 // Start listening on the configured port and start the server. This is a convenience wrapper for Listen() and Serve(listener Listener)
diff --git a/cmd/hyperfleet-api/server/healthcheck_server.go b/cmd/hyperfleet-api/server/healthcheck_server.go
index f6772346..ac39c726 100755
--- a/cmd/hyperfleet-api/server/healthcheck_server.go
+++ b/cmd/hyperfleet-api/server/healthcheck_server.go
@@ -31,7 +31,7 @@ func NewHealthCheckServer() *healthCheckServer {
 
 	srv := &http.Server{
 		Handler: router,
-		Addr:    env().Config.HealthCheck.BindAddress,
+		Addr:    env().Config.HealthCheck.GetBindAddress(),
 	}
 
 	return &healthCheckServer{
@@ -42,18 +42,18 @@ func NewHealthCheckServer() *healthCheckServer {
 func (s healthCheckServer) Start() {
 	var err error
 	if env().Config.HealthCheck.EnableHTTPS {
-		if env().Config.Server.HTTPSCertFile == "" || env().Config.Server.HTTPSKeyFile == "" {
+		if env().Config.Server.HTTPS.CertFile == "" || env().Config.Server.HTTPS.KeyFile == "" {
 			check(
-				fmt.Errorf("unspecified required --https-cert-file, --https-key-file"),
+				fmt.Errorf("unspecified required --server-https-cert-file, --server-https-key-file"),
 				"Can't start https server",
 			)
 		}
 
 		// Serve with TLS
-		glog.Infof("Serving HealthCheck with TLS at %s", env().Config.HealthCheck.BindAddress)
-		err = s.httpServer.ListenAndServeTLS(env().Config.Server.HTTPSCertFile, env().Config.Server.HTTPSKeyFile)
+		glog.Infof("Serving HealthCheck with TLS at %s", env().Config.HealthCheck.GetBindAddress())
+		err = s.httpServer.ListenAndServeTLS(env().Config.Server.HTTPS.CertFile, env().Config.Server.HTTPS.KeyFile)
 	} else {
-		glog.Infof("Serving HealthCheck without TLS at %s", env().Config.HealthCheck.BindAddress)
+		glog.Infof("Serving HealthCheck without TLS at %s", env().Config.HealthCheck.GetBindAddress())
 		err = s.httpServer.ListenAndServe()
 	}
 	check(err, "HealthCheck server terminated with errors")
diff --git a/cmd/hyperfleet-api/server/metrics_server.go b/cmd/hyperfleet-api/server/metrics_server.go
index 6fa14b02..942469d3 100755
--- a/cmd/hyperfleet-api/server/metrics_server.go
+++ b/cmd/hyperfleet-api/server/metrics_server.go
@@ -25,7 +25,7 @@ func NewMetricsServer() Server {
 
 	s := &metricsServer{}
 	s.httpServer = &http.Server{
-		Addr:    env().Config.Metrics.BindAddress,
+		Addr:    env().Config.Metrics.GetBindAddress(),
 		Handler: mainHandler,
 	}
 	return s
@@ -48,18 +48,18 @@ func (s metricsServer) Start() {
 	log := logger.NewOCMLogger(context.Background())
 	var err error
 	if env().Config.Metrics.EnableHTTPS {
-		if env().Config.Server.HTTPSCertFile == "" || env().Config.Server.HTTPSKeyFile == "" {
+		if env().Config.Server.HTTPS.CertFile == "" || env().Config.Server.HTTPS.KeyFile == "" {
 			check(
-				fmt.Errorf("unspecified required --https-cert-file, --https-key-file"),
+				fmt.Errorf("unspecified required --server-https-cert-file, --server-https-key-file"),
 				"Can't start https server",
 			)
 		}
 
 		// Serve with TLS
-		log.Infof("Serving Metrics with TLS at %s", env().Config.Server.BindAddress)
-		err = s.httpServer.ListenAndServeTLS(env().Config.Server.HTTPSCertFile, env().Config.Server.HTTPSKeyFile)
+		log.Infof("Serving Metrics with TLS at %s", env().Config.Metrics.GetBindAddress())
+		err = s.httpServer.ListenAndServeTLS(env().Config.Server.HTTPS.CertFile, env().Config.Server.HTTPS.KeyFile)
 	} else {
-		log.Infof("Serving Metrics without TLS at %s", env().Config.Metrics.BindAddress)
+		log.Infof("Serving Metrics without TLS at %s", env().Config.Metrics.GetBindAddress())
 		err = s.httpServer.ListenAndServe()
 	}
 	check(err, "Metrics server terminated with errors")
diff --git a/cmd/hyperfleet-api/server/routes.go b/cmd/hyperfleet-api/server/routes.go
index 3b867baf..09cf0f5a 100755
--- a/cmd/hyperfleet-api/server/routes.go
+++ b/cmd/hyperfleet-api/server/routes.go
@@ -45,7 +45,7 @@ func (s *apiServer) routes() *mux.Router {
 
 	var authMiddleware auth.JWTMiddleware
 	authMiddleware = &auth.MiddlewareMock{}
-	if env().Config.Server.EnableJWT {
+	if env().Config.Server.Auth.JWT.Enabled {
 		var err error
 		authMiddleware, err = auth.NewAuthMiddleware()
 		check(err, "Unable to create auth middleware")
@@ -75,6 +75,10 @@ func (s *apiServer) routes() *mux.Router {
 	apiRouter := mainRouter.PathPrefix("/api/hyperfleet").Subrouter()
 	apiRouter.HandleFunc("", metadataHandler.Get).Methods(http.MethodGet)
 
+	//  /api/hyperfleet/config
+	configHandler := handlers.NewConfigHandler(env().Config)
+	apiRouter.HandleFunc("/config", configHandler.Get).Methods(http.MethodGet)
+
 	//  /api/hyperfleet/v1
 	apiV1Router := apiRouter.PathPrefix("/v1").Subrouter()
 
diff --git a/configs/config.yaml b/configs/config.yaml
new file mode 100644
index 00000000..3c03ca07
--- /dev/null
+++ b/configs/config.yaml
@@ -0,0 +1,63 @@
+# HyperFleet API Configuration
+# This is a sample configuration file showing all available options
+
+# Application configuration
+app:
+  name: "hyperfleet-api"
+  version: "1.0.0"
+
+# Server configuration
+server:
+  hostname: ""
+  host: "localhost"
+  port: 8000
+  timeout:
+    read: 5s
+    write: 30s
+  https:
+    enabled: false
+    cert_file: ""
+    key_file: ""
+
+  # Authentication and Authorization
+  auth:
+    jwt:
+      enabled: false
+      cert_file: ""
+      cert_url: "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/certs"
+    authz:
+      enabled: false
+      acl_file: ""
+
+# Database configuration
+database:
+  dialect: "postgres"
+  host: "localhost"
+  port: 5432
+  name: "hyperfleet"
+  username: "hyperfleet"
+  password: "foobar-bizz-buzz"
+  sslmode: "disable"
+  rootcert_file: ""
+  debug: false
+  max_open_connections: 50
+
+# Metrics configuration
+metrics:
+  host: "localhost"
+  port: 8080
+
+# Health check configuration
+health_check:
+  host: "localhost"
+  port: 8083
+
+# OCM (OpenShift Cluster Manager) configuration
+ocm:
+  base_url: ""
+  client_id: ""
+  client_secret: ""
+  self_token: ""
+  token_url: ""
+  debug: false
+  enable_mock: true
diff --git a/docs/config.md b/docs/config.md
new file mode 100644
index 00000000..deebbaa4
--- /dev/null
+++ b/docs/config.md
@@ -0,0 +1,384 @@
+# HyperFleet API Configuration Documentation
+
+This document describes all configuration options available for the HyperFleet API service.
+
+## Configuration Sources
+
+The HyperFleet API follows the [HyperFleet Configuration Standard](../configuration-standard.md) and loads configuration from multiple sources with the following precedence (highest to lowest):
+
+1. **Command-line flags** (highest priority)
+2. **Environment variables** (prefixed with `HYPERFLEET_`)
+3. **Configuration files** (YAML format)
+4. **Default values** (lowest priority)
+
+## Configuration File Location
+
+The configuration file path is determined by:
+
+1. Path specified via `--config` flag (if provided)
+2. Path specified via `HYPERFLEET_CONFIG` environment variable
+3. Default paths (first found is used):
+   - Development: `./configs/config.yaml`
+   - Production: `/etc/hyperfleet/config.yaml`
+
+If no configuration file is found, the application continues with flags, environment variables, and defaults only.
+
+## Global Configuration Options
+
+### Application Settings
+
+| Field | Flag | Environment Variable | Type | Default | Description | Required |
+|-------|------|---------------------|------|---------|-------------|----------|
+| `app.name` | `--name`, `-n` | `HYPERFLEET_APP_NAME` | string | `""` | Component name | Yes |
+| `app.version` | `--version`, `-v` | `HYPERFLEET_APP_VERSION` | string | `"1.0.0"` | Component version | No |
+
+**Example:**
+```yaml
+app:
+  name: hyperfleet-api
+  version: 1.0.0
+```
+
+```bash
+# Via flags
+./hyperfleet-api serve --name hyperfleet-api --version 1.0.0
+
+# Via environment variables
+export HYPERFLEET_APP_NAME=hyperfleet-api
+export HYPERFLEET_APP_VERSION=1.0.0
+```
+
+## Server Configuration
+
+### Server Settings
+
+| Field | Flag | Environment Variable | Type | Default | Description | Validation |
+|-------|------|---------------------|------|---------|-------------|------------|
+| `server.hostname` | `--server-hostname` | `HYPERFLEET_SERVER_HOSTNAME` | string | `""` | Server's public hostname | |
+| `server.host` | `--server-host` | `HYPERFLEET_SERVER_HOST` | string | `"localhost"` | Server bind host | Required |
+| `server.port` | `--server-port`, `-p` | `HYPERFLEET_SERVER_PORT` | int | `8000` | Server bind port | Required, 1-65535 |
+| `server.timeout.read` | `--server-timeout-read` | `HYPERFLEET_SERVER_TIMEOUT_READ` | duration | `5s` | HTTP server read timeout | |
+| `server.timeout.write` | `--server-timeout-write` | `HYPERFLEET_SERVER_TIMEOUT_WRITE` | duration | `30s` | HTTP server write timeout | |
+
+**Example:**
+```yaml
+server:
+  hostname: ""
+  host: localhost
+  port: 8000
+  timeout:
+    read: 5s
+    write: 30s
+```
+
+```bash
+# Via flags
+./hyperfleet-api serve --server-host 0.0.0.0 --server-port 8000
+
+# Via environment variables
+export HYPERFLEET_SERVER_HOST=0.0.0.0
+export HYPERFLEET_SERVER_PORT=8000
+```
+
+### HTTPS Configuration
+
+| Field | Flag | Environment Variable | Type | Default | Description |
+|-------|------|---------------------|------|---------|-------------|
+| `server.https.enabled` | `--server-https-enabled` | `HYPERFLEET_SERVER_HTTPS_ENABLED` | bool | `false` | Enable HTTPS |
+| `server.https.cert_file` | `--server-https-cert-file` | `HYPERFLEET_SERVER_HTTPS_CERT_FILE` | string | `""` | Path to TLS certificate file |
+| `server.https.key_file` | `--server-https-key-file` | `HYPERFLEET_SERVER_HTTPS_KEY_FILE` | string | `""` | Path to TLS key file |
+
+**Example:**
+```yaml
+server:
+  https:
+    enabled: true
+    cert_file: /etc/certs/tls.crt
+    key_file: /etc/certs/tls.key
+```
+
+```bash
+# Via flags
+./hyperfleet-api serve --server-https-enabled --server-https-cert-file /etc/certs/tls.crt --server-https-key-file /etc/certs/tls.key
+
+# Via environment variables
+export HYPERFLEET_SERVER_HTTPS_ENABLED=true
+export HYPERFLEET_SERVER_HTTPS_CERT_FILE=/etc/certs/tls.crt
+export HYPERFLEET_SERVER_HTTPS_KEY_FILE=/etc/certs/tls.key
+```
+
+### JWT Authentication Configuration
+
+| Field | Flag | Environment Variable | Type | Default | Description |
+|-------|------|---------------------|------|---------|-------------|
+| `server.auth.jwt.enabled` | `--auth-jwt-enabled` | `HYPERFLEET_SERVER_AUTH_JWT_ENABLED` | bool | `true` | Enable JWT authentication |
+| `server.auth.jwt.cert_file` | `--auth-jwt-cert-file` | `HYPERFLEET_SERVER_AUTH_JWT_CERT_FILE` | string | `""` | JWK certificate file path |
+| `server.auth.jwt.cert_url` | `--auth-jwt-cert-url` | `HYPERFLEET_SERVER_AUTH_JWT_CERT_URL` | string | `https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/certs` | JWK certificate URL |
+
+**Example:**
+```yaml
+server:
+  auth:
+    jwt:
+      enabled: true
+      cert_file: ""
+      cert_url: https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/certs
+```
+
+### Authorization Configuration
+
+| Field | Flag | Environment Variable | Type | Default | Description |
+|-------|------|---------------------|------|---------|-------------|
+| `server.auth.authz.enabled` | `--auth-authz-enabled` | `HYPERFLEET_SERVER_AUTH_AUTHZ_ENABLED` | bool | `true` | Enable authorization |
+| `server.auth.authz.acl_file` | `--auth-authz-acl-file` | `HYPERFLEET_SERVER_AUTH_AUTHZ_ACL_FILE` | string | `""` | Access control list file |
+
+**Example:**
+```yaml
+server:
+  auth:
+    authz:
+      enabled: true
+      acl_file: /etc/config/acl.yaml
+```
+
+## Database Configuration
+
+| Field | Flag | Environment Variable | Type | Default | Description | Validation |
+|-------|------|---------------------|------|---------|-------------|------------|
+| `database.dialect` | | `HYPERFLEET_DATABASE_DIALECT` | string | `"postgres"` | Database dialect | Required |
+| `database.host` | `--db-host` | `HYPERFLEET_DATABASE_HOST` | string | `""` | Database host | |
+| `database.port` | `--db-port` | `HYPERFLEET_DATABASE_PORT` | int | `0` | Database port | 0-65535 |
+| `database.name` | `--db-name`, `-d` | `HYPERFLEET_DATABASE_NAME` | string | `""` | Database name | |
+| `database.username` | `--db-username`, `-u` | `HYPERFLEET_DATABASE_USERNAME` | string | `""` | Database username | |
+| `database.password` | `--db-password` | `HYPERFLEET_DATABASE_PASSWORD` | string | `""` | Database password (prefer env var) | |
+| `database.sslmode` | `--db-sslmode` | `HYPERFLEET_DATABASE_SSLMODE` | string | `"disable"` | SSL mode | disable, require, verify-ca, verify-full |
+| `database.rootcert_file` | `--db-rootcert` | `HYPERFLEET_DATABASE_ROOTCERT_FILE` | string | `"secrets/db.rootcert"` | Root certificate file | |
+| `database.debug` | `--db-debug` | `HYPERFLEET_DATABASE_DEBUG` | bool | `false` | Enable database debug mode | |
+| `database.max_open_connections` | `--db-max-open-connections` | `HYPERFLEET_DATABASE_MAX_OPEN_CONNECTIONS` | int | `50` | Maximum open connections | Min: 1 |
+
+### File-based Secrets
+
+For enhanced security, database credentials can be loaded from files:
+
+| Field | Flag | Default |
+|-------|------|---------|
+| `database.host_file` | `--db-host-file` | `secrets/db.host` |
+| `database.port_file` | `--db-port-file` | `secrets/db.port` |
+| `database.name_file` | `--db-name-file` | `secrets/db.name` |
+| `database.username_file` | `--db-username-file` | `secrets/db.user` |
+| `database.password_file` | `--db-password-file` | `secrets/db.password` |
+
+**Note:** File-based values are only used if the corresponding direct value is not set.
+
+**Example:**
+```yaml
+database:
+  dialect: postgres
+  host: db.example.com
+  port: 5432
+  name: hyperfleet
+  username: hyperfleet_user
+  # Password should be set via environment variable or file
+  sslmode: require
+  max_open_connections: 50
+```
+
+```bash
+# Via environment variables (recommended for credentials)
+export HYPERFLEET_DATABASE_HOST=db.example.com
+export HYPERFLEET_DATABASE_PORT=5432
+export HYPERFLEET_DATABASE_NAME=hyperfleet
+export HYPERFLEET_DATABASE_USERNAME=hyperfleet_user
+export HYPERFLEET_DATABASE_PASSWORD=super_secret_password
+```
+
+## Metrics Configuration
+
+| Field | Flag | Environment Variable | Type | Default | Description | Validation |
+|-------|------|---------------------|------|---------|-------------|------------|
+| `metrics.host` | `--metrics-host` | `HYPERFLEET_METRICS_HOST` | string | `"localhost"` | Metrics server bind host | |
+| `metrics.port` | `--metrics-port` | `HYPERFLEET_METRICS_PORT` | int | `8080` | Metrics server bind port | 1-65535 |
+| `metrics.enable_https` | `--metrics-https-enabled` | `HYPERFLEET_METRICS_ENABLE_HTTPS` | bool | `false` | Enable HTTPS for metrics | |
+| `metrics.label_metrics_inclusion_duration` | `--metrics-label-inclusion-duration` | `HYPERFLEET_METRICS_LABEL_METRICS_INCLUSION_DURATION` | duration | `168h` | Label metrics inclusion duration | |
+
+**Example:**
+```yaml
+metrics:
+  host: localhost
+  port: 8080
+  enable_https: false
+  label_metrics_inclusion_duration: 168h  # 7 days
+```
+
+## Health Check Configuration
+
+| Field | Flag | Environment Variable | Type | Default | Description | Validation |
+|-------|------|---------------------|------|---------|-------------|------------|
+| `health_check.host` | `--health-check-host` | `HYPERFLEET_HEALTH_CHECK_HOST` | string | `"localhost"` | Health check server bind host | |
+| `health_check.port` | `--health-check-port` | `HYPERFLEET_HEALTH_CHECK_PORT` | int | `8083` | Health check server bind port | 1-65535 |
+| `health_check.enable_https` | `--health-check-https-enabled` | `HYPERFLEET_HEALTH_CHECK_ENABLE_HTTPS` | bool | `false` | Enable HTTPS for health check | |
+
+**Example:**
+```yaml
+health_check:
+  host: localhost
+  port: 8083
+  enable_https: false
+```
+
+## OCM (OpenShift Cluster Manager) Configuration
+
+| Field | Flag | Environment Variable | Type | Default | Description |
+|-------|------|---------------------|------|---------|-------------|
+| `ocm.base_url` | `--ocm-base-url` | `HYPERFLEET_OCM_BASE_URL` | string | `https://api.integration.openshift.com` | OCM API base URL |
+| `ocm.token_url` | `--ocm-token-url` | `HYPERFLEET_OCM_TOKEN_URL` | string | `https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token` | OCM token URL |
+| `ocm.debug` | `--ocm-debug` | `HYPERFLEET_OCM_DEBUG` | bool | `false` | Enable OCM debug mode |
+| `ocm.enable_mock` | `--ocm-mock` | `HYPERFLEET_OCM_ENABLE_MOCK` | bool | `true` | Enable mock OCM client |
+
+### File-based Secrets
+
+OCM credentials can be loaded from files:
+
+| Field | Flag | Default |
+|-------|------|---------|
+| `ocm.client_id_file` | `--ocm-client-id-file` | `secrets/ocm-service.clientId` |
+| `ocm.client_secret_file` | `--ocm-client-secret-file` | `secrets/ocm-service.clientSecret` |
+| `ocm.self_token_file` | `--ocm-self-token-file` | `""` |
+
+**Example:**
+```yaml
+ocm:
+  base_url: https://api.integration.openshift.com
+  token_url: https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token
+  debug: false
+  enable_mock: false
+  client_id_file: secrets/ocm-service.clientId
+  client_secret_file: secrets/ocm-service.clientSecret
+```
+
+## Configuration Validation
+
+The service performs validation on startup and will fail to start if:
+
+- Required fields are missing (e.g., `app.name`)
+- Values are outside valid ranges (e.g., port numbers)
+- Unknown fields are present in the configuration file
+- Required files cannot be read
+
+Validation errors include helpful hints showing how to provide the correct values via flags, environment variables, or configuration files.
+
+**Example validation error:**
+```
+Configuration validation failed:
+  - Field 'Config.App.Name' failed validation: required
+    Value:
+    Please provide via:
+      • Flag: --name or -n
+      • Environment variable: HYPERFLEET_APP_NAME
+      • Config file: app.name
+```
+
+## Configuration Display
+
+On startup, the merged configuration is displayed in the logs with sensitive values redacted. The following fields are automatically redacted:
+
+- `database.password`
+- `ocm.client_secret`
+- `ocm.self_token`
+
+Redacted values are shown as `***` to indicate they are set but not displayed.
+
+## Complete Configuration Example
+
+```yaml
+# Application configuration
+app:
+  name: hyperfleet-api
+  version: 1.0.0
+
+# Server configuration
+server:
+  hostname: ""
+  host: 0.0.0.0
+  port: 8000
+  timeout:
+    read: 5s
+    write: 30s
+  https:
+    enabled: false
+    cert_file: ""
+    key_file: ""
+  auth:
+    jwt:
+      enabled: true
+      cert_file: ""
+      cert_url: https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/certs
+    authz:
+      enabled: true
+      acl_file: ""
+
+# Database configuration
+database:
+  dialect: postgres
+  host: db.example.com
+  port: 5432
+  name: hyperfleet
+  username: hyperfleet_user
+  sslmode: require
+  debug: false
+  max_open_connections: 50
+  # File-based secrets
+  host_file: secrets/db.host
+  port_file: secrets/db.port
+  name_file: secrets/db.name
+  username_file: secrets/db.user
+  password_file: secrets/db.password
+  rootcert_file: secrets/db.rootcert
+
+# Metrics configuration
+metrics:
+  host: localhost
+  port: 8080
+  enable_https: false
+  label_metrics_inclusion_duration: 168h
+
+# Health check configuration
+health_check:
+  host: localhost
+  port: 8083
+  enable_https: false
+
+# OCM configuration
+ocm:
+  base_url: https://api.integration.openshift.com
+  token_url: https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token
+  debug: false
+  enable_mock: false
+  client_id_file: secrets/ocm-service.clientId
+  client_secret_file: secrets/ocm-service.clientSecret
+  self_token_file: ""
+```
+
+## Environment-Specific Configuration
+
+The HyperFleet API supports multiple runtime environments controlled via the `OCM_ENV` environment variable:
+
+- `development` (default)
+- `integration-testing`
+- `unit-testing`
+- `production`
+
+Each environment can have specific default configurations that override the base defaults.
+
+## Best Practices
+
+1. **Never commit secrets**: Use environment variables or file-based secrets for sensitive data
+2. **Use configuration files for non-sensitive defaults**: Keep your deployment-specific settings in YAML files
+3. **Override at runtime**: Use flags for quick testing and overrides
+4. **Validate early**: The application will fail fast on invalid configuration
+5. **Document exceptions**: If you add custom configuration options, document them in this file
+
+## See Also
+
+- [HyperFleet Configuration Standard](../configuration-standard.md)
+- [Configuration Implementation Example](https://github.com/rh-amarin/viper-cobra-validation-poc)
diff --git a/go.mod b/go.mod
index 88bdc019..33b3c6bc 100755
--- a/go.mod
+++ b/go.mod
@@ -13,6 +13,7 @@ require (
 	github.com/getkin/kin-openapi v0.133.0
 	github.com/ghodss/yaml v1.0.0
 	github.com/go-gormigrate/gormigrate/v2 v2.0.0
+	github.com/go-playground/validator/v10 v10.30.1
 	github.com/golang-jwt/jwt/v4 v4.5.2
 	github.com/golang/glog v1.2.5
 	github.com/google/uuid v1.6.0
@@ -26,7 +27,9 @@ require (
 	github.com/prometheus/client_golang v1.16.0
 	github.com/segmentio/ksuid v1.0.2
 	github.com/spf13/cobra v0.0.5
-	github.com/spf13/pflag v1.0.5
+	github.com/spf13/pflag v1.0.10
+	github.com/spf13/viper v1.21.0
+	github.com/stretchr/testify v1.11.1
 	github.com/testcontainers/testcontainers-go v0.33.0
 	github.com/testcontainers/testcontainers-go/modules/postgres v0.33.0
 	github.com/yaacov/tree-search-language v0.0.0-20190923184055-1c2dad2e354b
@@ -52,6 +55,7 @@ require (
 	github.com/containerd/log v0.1.0 // indirect
 	github.com/containerd/platforms v0.2.1 // indirect
 	github.com/cpuguy83/dockercfg v0.3.2 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
 	github.com/distribution/reference v0.6.0 // indirect
 	github.com/docker/distribution v2.8.1+incompatible // indirect
@@ -59,12 +63,17 @@ require (
 	github.com/docker/go-connections v0.6.0 // indirect
 	github.com/docker/go-units v0.5.0 // indirect
 	github.com/felixge/httpsnoop v1.0.4 // indirect
+	github.com/fsnotify/fsnotify v1.9.0 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.12 // indirect
 	github.com/go-logr/logr v1.4.3 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-ole/go-ole v1.2.6 // indirect
 	github.com/go-openapi/jsonpointer v0.21.0 // indirect
 	github.com/go-openapi/swag v0.23.0 // indirect
+	github.com/go-playground/locales v0.14.1 // indirect
+	github.com/go-playground/universal-translator v0.18.1 // indirect
 	github.com/go-sql-driver/mysql v1.8.1 // indirect
+	github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/google/go-cmp v0.7.0 // indirect
 	github.com/gorilla/css v1.0.0 // indirect
@@ -80,6 +89,7 @@ require (
 	github.com/klauspost/compress v1.18.0 // indirect
 	github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
 	github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
+	github.com/leodido/go-urn v1.4.0 // indirect
 	github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
 	github.com/magiconair/properties v1.8.10 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
@@ -101,16 +111,23 @@ require (
 	github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
 	github.com/opencontainers/go-digest v1.0.0 // indirect
 	github.com/opencontainers/image-spec v1.1.1 // indirect
+	github.com/pelletier/go-toml/v2 v2.2.4 // indirect
 	github.com/perimeterx/marshmallow v1.1.5 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
 	github.com/prometheus/client_model v0.3.0 // indirect
 	github.com/prometheus/common v0.42.0 // indirect
 	github.com/prometheus/procfs v0.10.1 // indirect
+	github.com/sagikazarmark/locafero v0.11.0 // indirect
 	github.com/shirou/gopsutil/v3 v3.23.12 // indirect
 	github.com/shoenig/go-m1cpu v0.1.6 // indirect
 	github.com/sirupsen/logrus v1.9.3 // indirect
 	github.com/smartystreets/goconvey v1.8.1 // indirect
+	github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
+	github.com/spf13/afero v1.15.0 // indirect
+	github.com/spf13/cast v1.10.0 // indirect
+	github.com/subosito/gotenv v1.6.0 // indirect
 	github.com/tklauser/go-sysconf v0.3.12 // indirect
 	github.com/tklauser/numcpus v0.6.1 // indirect
 	github.com/urfave/negroni v1.0.0 // indirect
@@ -123,11 +140,12 @@ require (
 	go.opentelemetry.io/otel/metric v1.38.0 // indirect
 	go.opentelemetry.io/otel/sdk v1.38.0 // indirect
 	go.opentelemetry.io/otel/trace v1.38.0 // indirect
-	golang.org/x/crypto v0.41.0 // indirect
-	golang.org/x/net v0.43.0 // indirect
-	golang.org/x/sync v0.17.0 // indirect
-	golang.org/x/sys v0.36.0 // indirect
-	golang.org/x/text v0.29.0 // indirect
+	go.yaml.in/yaml/v3 v3.0.4 // indirect
+	golang.org/x/crypto v0.46.0 // indirect
+	golang.org/x/net v0.47.0 // indirect
+	golang.org/x/sync v0.19.0 // indirect
+	golang.org/x/sys v0.39.0 // indirect
+	golang.org/x/text v0.32.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20251014184007-4626949a642f // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20251014184007-4626949a642f // indirect
diff --git a/go.sum b/go.sum
index f143ba0a..7792f700 100755
--- a/go.sum
+++ b/go.sum
@@ -141,8 +141,14 @@ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2Vvl
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
+github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
+github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
+github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
 github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ=
 github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE=
 github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
@@ -169,6 +175,14 @@ github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1
 github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
 github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
 github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=
+github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
 github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
@@ -178,6 +192,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
 github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
+github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
+github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
 github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -399,6 +415,8 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq
 github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
 github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
 github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -502,6 +520,8 @@ github.com/openshift-online/ocm-sdk-go v0.1.334 h1:45WSkXEsmpGekMa9kO6NpEG8PW5/g
 github.com/openshift-online/ocm-sdk-go v0.1.334/go.mod h1:KYOw8kAKAHyPrJcQoVR82CneQ4ofC02Na4cXXaTq4Nw=
 github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
+github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
 github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
 github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@@ -551,6 +571,8 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
 github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
 github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
+github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/segmentio/ksuid v1.0.2 h1:9yBfKyw4ECGTdALaF09Snw3sLJmYIX6AbPJrAy6MrDc=
 github.com/segmentio/ksuid v1.0.2/go.mod h1:BXuJDr2byAiHuQaQtSKoXh1J0YmUDurywOXgB2w+OSU=
@@ -573,15 +595,23 @@ github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGB
 github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
 github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
 github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
+github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
+github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
+github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
+github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
 github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
-github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
+github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
+github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@@ -597,6 +627,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
 github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
+github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
 github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw=
 github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8=
 github.com/testcontainers/testcontainers-go/modules/postgres v0.33.0 h1:c+Gt+XLJjqFAejgX4hSpnHIpC9eAhvgI/TFWL/PbrFI=
@@ -665,6 +697,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E
 go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
+go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -683,8 +717,8 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y
 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
-golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
+golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
+golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -762,8 +796,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
-golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
+golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
+golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -782,8 +816,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
-golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
+golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -848,13 +882,13 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
-golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
+golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
-golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
+golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
+golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -863,8 +897,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
-golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
+golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
+golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/pkg/config/app.go b/pkg/config/app.go
new file mode 100644
index 00000000..1b13aca8
--- /dev/null
+++ b/pkg/config/app.go
@@ -0,0 +1,24 @@
+package config
+
+import (
+	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
+)
+
+type AppConfig struct {
+	Name    string `mapstructure:"name" json:"name" validate:"required"`
+	Version string `mapstructure:"version" json:"version"`
+}
+
+func NewAppConfig() *AppConfig {
+	return &AppConfig{
+		Name:    "",
+		Version: "1.0.0",
+	}
+}
+
+// defineAndBindFlags defines app flags and binds them to viper keys in a single pass
+func (c *AppConfig) defineAndBindFlags(v *viper.Viper, fs *pflag.FlagSet) {
+	defineAndBindStringFlag(v, fs, "app.name", "name", "n", c.Name, "Component name (REQUIRED)")
+	defineAndBindStringFlag(v, fs, "app.version", "version", "", c.Version, "Component version")
+}
diff --git a/pkg/config/config.go b/pkg/config/config.go
index f7c44ffd..6eb882ee 100755
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -1,27 +1,95 @@
 package config
 
 import (
+	"encoding/json"
 	"flag"
 	"fmt"
 	"os"
-	"path/filepath"
-	"runtime"
-	"strconv"
+	"reflect"
 	"strings"
+	"time"
 
+	"github.com/go-playground/validator/v10"
+	"github.com/golang/glog"
 	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
 )
 
+const (
+	EnvPrefix             = "HYPERFLEET"
+	DefaultConfigFileProd = "/etc/hyperfleet/config.yaml"
+	DefaultConfigFileDev  = "./configs/config.yaml"
+	ConfigEnvVar          = "HYPERFLEET_CONFIG"
+)
+
+// NewCommandConfig creates and configures a new Viper instance for a command
+// Each command should have its own viper instance to avoid configuration pollution
+func NewCommandConfig() *viper.Viper {
+	v := viper.New()
+	v.SetEnvPrefix(EnvPrefix)
+	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
+	v.AutomaticEnv()
+	return v
+}
+
+// Flag definition helpers that define flags and bind them to viper keys in a single pass
+
+func defineAndBindStringFlag(v *viper.Viper, fs *pflag.FlagSet, viperKey, flagName, shorthand, defaultVal, usage string) {
+	// Define the flag
+	if shorthand != "" {
+		fs.StringP(flagName, shorthand, defaultVal, usage)
+	} else {
+		fs.String(flagName, defaultVal, usage)
+	}
+	// Bind to viper key
+	bindFlag(v, fs, viperKey, flagName)
+}
+
+func defineAndBindIntFlag(v *viper.Viper, fs *pflag.FlagSet, viperKey, flagName, shorthand string, defaultVal int, usage string) {
+	// Define the flag
+	if shorthand != "" {
+		fs.IntP(flagName, shorthand, defaultVal, usage)
+	} else {
+		fs.Int(flagName, defaultVal, usage)
+	}
+	// Bind to viper key
+	bindFlag(v, fs, viperKey, flagName)
+}
+
+func defineAndBindBoolFlag(v *viper.Viper, fs *pflag.FlagSet, viperKey, flagName, shorthand string, defaultVal bool, usage string) {
+	// Define the flag
+	if shorthand != "" {
+		fs.BoolP(flagName, shorthand, defaultVal, usage)
+	} else {
+		fs.Bool(flagName, defaultVal, usage)
+	}
+	// Bind to viper key
+	bindFlag(v, fs, viperKey, flagName)
+}
+
+func defineAndBindDurationFlag(v *viper.Viper, fs *pflag.FlagSet, viperKey, flagName, shorthand string, defaultVal time.Duration, usage string) {
+	// Define the flag
+	if shorthand != "" {
+		fs.DurationP(flagName, shorthand, defaultVal, usage)
+	} else {
+		fs.Duration(flagName, defaultVal, usage)
+	}
+	// Bind to viper key
+	bindFlag(v, fs, viperKey, flagName)
+}
+
 type ApplicationConfig struct {
-	Server      *ServerConfig      `json:"server"`
-	Metrics     *MetricsConfig     `json:"metrics"`
-	HealthCheck *HealthCheckConfig `json:"health_check"`
-	Database    *DatabaseConfig    `json:"database"`
-	OCM         *OCMConfig         `json:"ocm"`
+	App         *AppConfig         `mapstructure:"app" json:"app" validate:"required"`
+	Server      *ServerConfig      `mapstructure:"server" json:"server" validate:"required"`
+	Metrics     *MetricsConfig     `mapstructure:"metrics" json:"metrics" validate:"required"`
+	HealthCheck *HealthCheckConfig `mapstructure:"health_check" json:"health_check" validate:"required"`
+	Database    *DatabaseConfig    `mapstructure:"database" json:"database" validate:"required"`
+	OCM         *OCMConfig         `mapstructure:"ocm" json:"ocm" validate:"required"`
 }
 
 func NewApplicationConfig() *ApplicationConfig {
 	return &ApplicationConfig{
+		App:         NewAppConfig(),
 		Server:      NewServerConfig(),
 		Metrics:     NewMetricsConfig(),
 		HealthCheck: NewHealthCheckConfig(),
@@ -30,99 +98,310 @@ func NewApplicationConfig() *ApplicationConfig {
 	}
 }
 
-func (c *ApplicationConfig) AddFlags(flagset *pflag.FlagSet) {
+// defineAndBindFlags defines application flags and binds them to viper keys in a single pass
+func (c *ApplicationConfig) defineAndBindFlags(v *viper.Viper, flagset *pflag.FlagSet) {
+	// Global flags
+	// Note: config flag is defined but NOT bound to viper (special case)
+	flagset.String("config", "", "Config file path")
+
+	// Define and bind sub-config flags
+	c.App.defineAndBindFlags(v, flagset)
+	c.Server.defineAndBindFlags(v, flagset)
+	c.Metrics.defineAndBindFlags(v, flagset)
+	c.HealthCheck.defineAndBindFlags(v, flagset)
+	c.Database.defineAndBindFlags(v, flagset)
+	c.OCM.defineAndBindFlags(v, flagset)
+}
+
+// ConfigureFlags defines configuration flags and binds them to viper for precedence handling
+func (c *ApplicationConfig) ConfigureFlags(v *viper.Viper, flagset *pflag.FlagSet) {
 	flagset.AddGoFlagSet(flag.CommandLine)
-	c.Server.AddFlags(flagset)
-	c.Metrics.AddFlags(flagset)
-	c.HealthCheck.AddFlags(flagset)
-	c.Database.AddFlags(flagset)
-	c.OCM.AddFlags(flagset)
-}
-
-func (c *ApplicationConfig) ReadFiles() []string {
-	readFiles := []struct {
-		f    func() error
-		name string
-	}{
-		{c.Server.ReadFiles, "Server"},
-		{c.Database.ReadFiles, "Database"},
-		{c.OCM.ReadFiles, "OCM"},
-		{c.Metrics.ReadFiles, "Metrics"},
-		{c.HealthCheck.ReadFiles, "HealthCheck"},
-	}
-	var messages []string
-	for _, rf := range readFiles {
-		if err := rf.f(); err != nil {
-			msg := fmt.Sprintf("%s %s", rf.name, err.Error())
-			messages = append(messages, msg)
+	c.defineAndBindFlags(v, flagset)
+}
+
+// bindFlag is a simple helper to bind an existing flag to a viper key
+func bindFlag(v *viper.Viper, fs *pflag.FlagSet, viperKey, flagName string) {
+	if err := v.BindPFlag(viperKey, fs.Lookup(flagName)); err != nil {
+		panic(fmt.Sprintf("failed to bind flag %s to %s: %v", flagName, viperKey, err))
+	}
+}
+
+// LoadConfig loads configuration from multiple sources with proper precedence:
+// 1. Command-line flags (highest priority)
+// 2. Environment variables (HYPERFLEET_ prefix)
+// 3. Configuration files
+// 4. Defaults (lowest priority)
+//
+// The viper instance should already be configured and have flags bound via ConfigureFlags()
+func LoadConfig(v *viper.Viper, flags *pflag.FlagSet) (*ApplicationConfig, error) {
+	// Create config instance
+	// Note: Viper is already configured with env support and flags are already bound
+	config := NewApplicationConfig()
+
+	// Determine config file path
+	configFile := getConfigFilePath(flags, v)
+
+	// Load config file if it exists
+	if configFile != "" {
+		v.SetConfigFile(configFile)
+		if err := v.ReadInConfig(); err != nil {
+			if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
+				return nil, fmt.Errorf("error reading config file %s: %w", configFile, err)
+			}
+			glog.Infof("Config file not found: %s, continuing with flags and environment variables", configFile)
+		} else {
+			glog.Infof("Loaded configuration from: %s", configFile)
 		}
 	}
-	return messages
+
+	// Unmarshal into config struct
+	// Viper now contains: config file values < env vars < bound flags
+	// This gives us the correct precedence automatically
+	if err := v.UnmarshalExact(config); err != nil {
+		return nil, fmt.Errorf("error unmarshaling config: %w", err)
+	}
+
+	// Validate configuration
+	if err := config.Validate(); err != nil {
+		return nil, err
+	}
+
+	return config, nil
 }
 
-// Read the contents of file into integer value
-func readFileValueInt(file string, val *int) error {
-	fileContents, err := ReadFile(file)
-	if err != nil {
-		return err
+// getConfigFilePath determines the config file path based on precedence:
+// 1. --config flag
+// 2. HYPERFLEET_CONFIG environment variable
+// 3. Default paths
+func getConfigFilePath(flags *pflag.FlagSet, v *viper.Viper) string {
+	// Check --config flag first
+	if flags != nil {
+		if configFlag := flags.Lookup("config"); configFlag != nil && configFlag.Changed {
+			return configFlag.Value.String()
+		}
 	}
 
-	*val, err = strconv.Atoi(fileContents)
-	return err
+	// Check environment variable
+	if configEnv := os.Getenv(ConfigEnvVar); configEnv != "" {
+		return configEnv
+	}
+
+	// Try default paths in order
+	defaultPaths := []string{
+		DefaultConfigFileDev,  // Try development path first
+		DefaultConfigFileProd, // Then production path
+	}
+
+	for _, path := range defaultPaths {
+		if _, err := os.Stat(path); err == nil {
+			return path
+		}
+	}
+
+	// No config file found
+	return ""
 }
 
-// Read the contents of file into string value
-func readFileValueString(file string, val *string) error {
-	fileContents, err := ReadFile(file)
-	if err != nil {
-		return err
+// Validate validates the configuration using struct tags
+func (c *ApplicationConfig) Validate() error {
+	validate := validator.New()
+
+	if err := validate.Struct(c); err != nil {
+		return formatValidationError(err)
+	}
+
+	return nil
+}
+
+// formatValidationError formats validation errors following the HyperFleet standard
+func formatValidationError(err error) error {
+	if validationErrors, ok := err.(validator.ValidationErrors); ok {
+		var messages []string
+		messages = append(messages, "Configuration validation failed:")
+
+		for _, fieldError := range validationErrors {
+			fieldPath := getFieldPath(fieldError)
+
+			msg := fmt.Sprintf("  - Field '%s' failed validation: %s", fieldPath, fieldError.Tag())
+
+			if fieldError.Param() != "" {
+				msg += fmt.Sprintf(" (param: %s)", fieldError.Param())
+			}
+
+			msg += fmt.Sprintf("\n    Value: %v", fieldError.Value())
+			msg += getHelpfulHint(fieldPath, fieldError.Tag())
+
+			messages = append(messages, msg)
+		}
+
+		return fmt.Errorf("%s", strings.Join(messages, "\n"))
 	}
 
-	*val = strings.TrimSuffix(fileContents, "\n")
 	return err
 }
 
-// Read the contents of file into boolean value
-func readFileValueBool(file string, val *bool) error {
-	fileContents, err := ReadFile(file)
+// getFieldPath extracts the full field path from a validation error
+func getFieldPath(fieldError validator.FieldError) string {
+	namespace := fieldError.Namespace()
+	// Remove the root struct name (ApplicationConfig)
+	parts := strings.Split(namespace, ".")
+	if len(parts) > 1 {
+		return "Config." + strings.Join(parts[1:], ".")
+	}
+	return namespace
+}
+
+// getHelpfulHint provides hints for how to fix validation errors
+func getHelpfulHint(fieldPath, tag string) string {
+	// Convert field path to flag and env var names
+	// E.g., "Config.App.Name" -> "app.name"
+	parts := strings.Split(fieldPath, ".")
+	if len(parts) <= 1 {
+		return ""
+	}
+
+	// Remove "Config" prefix
+	configParts := parts[1:]
+
+	// Convert to lowercase and join with dots
+	var lowerParts []string
+	for _, part := range configParts {
+		lowerParts = append(lowerParts, strings.ToLower(part))
+	}
+	configPath := strings.Join(lowerParts, ".")
+
+	// Create flag name (replace dots and underscores with hyphens)
+	flagName := "--" + strings.ReplaceAll(strings.ReplaceAll(configPath, ".", "-"), "_", "-")
+
+	// Create env var name (uppercase, replace dots with underscores)
+	envVarName := EnvPrefix + "_" + strings.ToUpper(strings.ReplaceAll(configPath, ".", "_"))
+
+	hint := "\n    Please provide via:\n"
+	hint += fmt.Sprintf("      • Flag: %s\n", flagName)
+	hint += fmt.Sprintf("      • Environment variable: %s\n", envVarName)
+	hint += fmt.Sprintf("      • Config file: %s", configPath)
+
+	return hint
+}
+
+// DisplayConfig logs the merged configuration at startup
+// Sensitive values are redacted
+func (c *ApplicationConfig) DisplayConfig() {
+	glog.Info("=== Merged Configuration ===")
+
+	// Create a copy for display with sensitive values redacted
+	displayCopy := c.redactSensitiveValues()
+
+	// Convert to JSON for pretty display
+	jsonBytes, err := json.MarshalIndent(displayCopy, "", "  ")
 	if err != nil {
-		return err
+		glog.Errorf("Error marshaling config for display: %v", err)
+		return
 	}
 
-	*val, err = strconv.ParseBool(fileContents)
-	return err
+	glog.Infof("\n%s", string(jsonBytes))
+	glog.Info("============================")
 }
 
-func ReadFile(file string) (string, error) {
-	// If the value is in quotes, unquote it
-	unquotedFile, err := strconv.Unquote(file)
+// redactSensitiveValues creates a copy of the config with sensitive values redacted
+// It uses reflection to automatically redact any field whose name contains
+// sensitive keywords (password, secret, token, key, cert)
+func (c *ApplicationConfig) redactSensitiveValues() *ApplicationConfig {
+	// Marshal to JSON and back to create a deep copy
+	jsonBytes, err := json.Marshal(c)
 	if err != nil {
-		// values without quotes will raise an error, ignore it.
-		unquotedFile = file
+		glog.Errorf("Error marshaling config for redaction: %v", err)
+		return c
 	}
 
-	// If no file is provided, leave val unchanged.
-	if unquotedFile == "" {
-		return "", nil
+	var copy ApplicationConfig
+	if err := json.Unmarshal(jsonBytes, &copy); err != nil {
+		glog.Errorf("Error unmarshaling config for redaction: %v", err)
+		return c
 	}
 
-	// Ensure the absolute file path is used
-	absFilePath := unquotedFile
-	if !filepath.IsAbs(unquotedFile) {
-		absFilePath = filepath.Join(GetProjectRootDir(), unquotedFile)
+	// Recursively redact sensitive fields
+	redactSensitiveFields(reflect.ValueOf(&copy).Elem())
+
+	return &copy
+}
+
+// redactSensitiveFields recursively walks through a struct and redacts
+// any string field whose name matches sensitive patterns
+func redactSensitiveFields(v reflect.Value) {
+	if !v.IsValid() {
+		return
 	}
 
-	// Read the file
-	buf, err := os.ReadFile(absFilePath)
+	switch v.Kind() {
+	case reflect.Ptr:
+		if !v.IsNil() {
+			redactSensitiveFields(v.Elem())
+		}
+
+	case reflect.Struct:
+		t := v.Type()
+		for i := 0; i < v.NumField(); i++ {
+			field := v.Field(i)
+			fieldType := t.Field(i)
+
+			// Skip unexported fields
+			if !field.CanSet() {
+				continue
+			}
+
+			// Check if this field is sensitive
+			if isSensitiveField(fieldType.Name) {
+				// Redact string fields
+				if field.Kind() == reflect.String && field.String() != "" {
+					field.SetString("***")
+				}
+			} else {
+				// Recursively process nested structs and pointers
+				redactSensitiveFields(field)
+			}
+		}
+
+	case reflect.Slice, reflect.Array:
+		for i := 0; i < v.Len(); i++ {
+			redactSensitiveFields(v.Index(i))
+		}
+
+	case reflect.Map:
+		for _, key := range v.MapKeys() {
+			mapValue := v.MapIndex(key)
+			if mapValue.Kind() == reflect.Ptr || mapValue.Kind() == reflect.Struct {
+				redactSensitiveFields(mapValue)
+			}
+		}
+	}
+}
+
+// GetJSONConfig returns the configuration as a JSON string
+// Sensitive values are redacted
+func (c *ApplicationConfig) GetJSONConfig() (string, error) {
+	displayCopy := c.redactSensitiveValues()
+
+	jsonBytes, err := json.MarshalIndent(displayCopy, "", "  ")
 	if err != nil {
-		return "", err
+		return "", fmt.Errorf("error marshaling config to JSON: %w", err)
 	}
-	return string(buf), nil
+
+	return string(jsonBytes), nil
 }
 
-// GetProjectRootDir Return project root path based on the relative path of this file
-func GetProjectRootDir() string {
-	_, b, _, _ := runtime.Caller(0)
-	basepath := filepath.Dir(filepath.Join(b, "..", ".."))
-	return basepath
+// isSensitiveField checks if a field name contains sensitive data keywords
+func isSensitiveField(fieldName string) bool {
+	sensitiveFields := []string{
+		"password", "secret", "token", "key", "cert",
+	}
+
+	lowerName := strings.ToLower(fieldName)
+	for _, sensitive := range sensitiveFields {
+		if strings.Contains(lowerName, sensitive) {
+			return true
+		}
+	}
+
+	return false
 }
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
old mode 100755
new mode 100644
index 0cc470fe..2e494a58
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -1,80 +1,438 @@
 package config
 
 import (
-	"log"
 	"os"
+	"path/filepath"
 	"testing"
 
-	. "github.com/onsi/gomega"
+	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
-func TestConfigReadStringFile(t *testing.T) {
-	RegisterTestingT(t)
+// testLoadConfig is a helper that loads config (flags must already be configured and parsed)
+func testLoadConfig(v *viper.Viper, flags *pflag.FlagSet) (*ApplicationConfig, error) {
+	return LoadConfig(v, flags)
+}
+
+// TestConfigPrecedence_CommandLineOverridesEnvVar tests that command-line flags
+// have higher precedence than environment variables
+func TestConfigPrecedence_CommandLineOverridesEnvVar(t *testing.T) {
+	// Set environment variable
+	os.Setenv("HYPERFLEET_APP_NAME", "env-name")
+	defer os.Unsetenv("HYPERFLEET_APP_NAME")
+
+	// Create flag set
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewApplicationConfig()
+
+	// Configure flags (define and bind)
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	// Parse command-line flag (simulating --name=cli-name)
+	err := flags.Parse([]string{"--name=cli-name"})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := testLoadConfig(v, flags)
+	require.NoError(t, err)
+
+	// Command-line flag should win
+	assert.Equal(t, "cli-name", loadedCfg.App.Name, "Command-line flag should override environment variable")
+}
+
+// TestConfigPrecedence_EnvVarOverridesConfigFile tests that environment variables
+// have higher precedence than config file values
+func TestConfigPrecedence_EnvVarOverridesConfigFile(t *testing.T) {
+	// Create temporary config file
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: file-name
+  version: 1.0.0
+server:
+  host: localhost
+  port: 8000
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Set environment variable
+	os.Setenv("HYPERFLEET_APP_NAME", "env-name")
+	defer os.Unsetenv("HYPERFLEET_APP_NAME")
+
+	// Create flag set and specify config file
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewApplicationConfig()
+
+	// Configure flags (define and bind)
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := testLoadConfig(v, flags)
+	require.NoError(t, err)
+
+	// Environment variable should win over config file
+	assert.Equal(t, "env-name", loadedCfg.App.Name, "Environment variable should override config file")
+}
+
+// TestConfigPrecedence_ConfigFileOverridesDefaults tests that config file values
+// have higher precedence than default values
+func TestConfigPrecedence_ConfigFileOverridesDefaults(t *testing.T) {
+	// Create temporary config file with custom port
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: file-name
+  version: 2.0.0
+server:
+  host: localhost
+  port: 9999
+  auth:
+    jwt:
+      enabled: false
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Create flag set and specify config file
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewApplicationConfig()
+
+	// Configure flags (define and bind)
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := testLoadConfig(v, flags)
+	require.NoError(t, err)
+
+	// Config file values should override defaults
+	assert.Equal(t, "file-name", loadedCfg.App.Name, "Config file should override default app name")
+	assert.Equal(t, "2.0.0", loadedCfg.App.Version, "Config file should override default version")
+	assert.Equal(t, 9999, loadedCfg.Server.Port, "Config file should override default port")
+	assert.Equal(t, false, loadedCfg.Server.Auth.JWT.Enabled, "Config file should override default auth")
+}
+
+// TestConfigPrecedence_FullPrecedenceChain tests the complete precedence chain:
+// CLI > Env Var > Config File > Defaults
+func TestConfigPrecedence_FullPrecedenceChain(t *testing.T) {
+	// Create temporary config file
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: file-name
+  version: 2.0.0
+server:
+  host: file-host
+  port: 7000
+metrics:
+  host: localhost
+  port: 7070
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+  port: 5432
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
 
-	stringFile, err := createConfigFile("string", "example\n")
-	defer os.Remove(stringFile.Name()) //nolint:errcheck
-	if err != nil {
-		log.Fatal(err)
-	}
+	// Set environment variables
+	os.Setenv("HYPERFLEET_APP_VERSION", "env-version")
+	os.Setenv("HYPERFLEET_SERVER_PORT", "8888")
+	defer os.Unsetenv("HYPERFLEET_APP_VERSION")
+	defer os.Unsetenv("HYPERFLEET_SERVER_PORT")
 
-	var stringConfig string
-	err = readFileValueString(stringFile.Name(), &stringConfig)
-	Expect(err).NotTo(HaveOccurred())
-	Expect(stringConfig).To(Equal("example"))
+	// Create flag set with command-line values
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewApplicationConfig()
+
+	// Configure flags (define and bind)
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{
+		"--config=" + configFile,
+		"--name=cli-name", // CLI overrides all
+		// version: env var should override file
+		// server-host: file should override default
+		// server-port: env var should override file
+		"--metrics-port=9090", // CLI overrides all
+	})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := testLoadConfig(v, flags)
+	require.NoError(t, err)
+
+	// Verify precedence
+	assert.Equal(t, "cli-name", loadedCfg.App.Name, "CLI should have highest precedence")
+	assert.Equal(t, "env-version", loadedCfg.App.Version, "Env var should override config file")
+	assert.Equal(t, "file-host", loadedCfg.Server.Host, "Config file should override default")
+	assert.Equal(t, 8888, loadedCfg.Server.Port, "Env var should override config file")
+	assert.Equal(t, 9090, loadedCfg.Metrics.Port, "CLI should override all")
 }
 
-func TestConfigReadIntFile(t *testing.T) {
-	RegisterTestingT(t)
+// TestConfigFile_SpecifiedByFlag tests that config file can be specified via --config flag
+func TestConfigFile_SpecifiedByFlag(t *testing.T) {
+	// Create temporary config file
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "custom-config.yaml")
+
+	configYAML := `
+app:
+  name: custom-app
+  version: 3.0.0
+server:
+  host: localhost
+  port: 8000
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Create flag set with --config flag
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewApplicationConfig()
+
+	// Configure flags (define and bind)
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
 
-	intFile, err := createConfigFile("int", "123")
-	defer os.Remove(intFile.Name()) //nolint:errcheck
-	if err != nil {
-		log.Fatal(err)
-	}
+	err = flags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
 
-	var intConfig int
-	err = readFileValueInt(intFile.Name(), &intConfig)
-	Expect(err).NotTo(HaveOccurred())
-	Expect(intConfig).To(Equal(123))
+	// Load config
+	loadedCfg, err := testLoadConfig(v, flags)
+	require.NoError(t, err)
+
+	// Verify config was loaded from the specified file
+	assert.Equal(t, "custom-app", loadedCfg.App.Name)
+	assert.Equal(t, "3.0.0", loadedCfg.App.Version)
 }
 
-func TestConfigReadBoolFile(t *testing.T) {
-	RegisterTestingT(t)
+// TestConfigFile_SpecifiedByEnvVar tests that config file can be specified via HYPERFLEET_CONFIG env var
+func TestConfigFile_SpecifiedByEnvVar(t *testing.T) {
+	// Create temporary config file
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "env-config.yaml")
+
+	configYAML := `
+app:
+  name: env-config-app
+  version: 4.0.0
+server:
+  host: localhost
+  port: 8000
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Set HYPERFLEET_CONFIG environment variable
+	os.Setenv("HYPERFLEET_CONFIG", configFile)
+	defer os.Unsetenv("HYPERFLEET_CONFIG")
+
+	// Create flag set without --config flag
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewApplicationConfig()
 
-	boolFile, err := createConfigFile("bool", "true")
-	defer os.Remove(boolFile.Name()) //nolint:errcheck
-	if err != nil {
-		log.Fatal(err)
-	}
+	// Configure flags (define and bind)
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
 
-	var boolConfig = false
-	err = readFileValueBool(boolFile.Name(), &boolConfig)
-	Expect(err).NotTo(HaveOccurred())
-	Expect(boolConfig).To(Equal(true))
+	err = flags.Parse([]string{})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := testLoadConfig(v, flags)
+	require.NoError(t, err)
+
+	// Verify config was loaded from the env-specified file
+	assert.Equal(t, "env-config-app", loadedCfg.App.Name)
+	assert.Equal(t, "4.0.0", loadedCfg.App.Version)
 }
 
-func TestConfigReadQuotedFile(t *testing.T) {
-	RegisterTestingT(t)
+// TestConfigFile_FlagOverridesEnvVar tests that --config flag takes precedence over HYPERFLEET_CONFIG env var
+func TestConfigFile_FlagOverridesEnvVar(t *testing.T) {
+	tmpDir := t.TempDir()
+
+	// Create config file for env var
+	envConfigFile := filepath.Join(tmpDir, "env-config.yaml")
+	envConfigYAML := `
+app:
+  name: env-config
+  version: 1.0.0
+server:
+  host: localhost
+  port: 8000
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(envConfigFile, []byte(envConfigYAML), 0o644)
+	require.NoError(t, err)
 
-	stringFile, err := createConfigFile("string", "example")
-	defer os.Remove(stringFile.Name()) //nolint:errcheck
-	if err != nil {
-		log.Fatal(err)
-	}
+	// Create config file for flag
+	flagConfigFile := filepath.Join(tmpDir, "flag-config.yaml")
+	flagConfigYAML := `
+app:
+  name: flag-config
+  version: 2.0.0
+server:
+  host: localhost
+  port: 8000
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err = os.WriteFile(flagConfigFile, []byte(flagConfigYAML), 0o644)
+	require.NoError(t, err)
 
-	quotedFileName := "\"" + stringFile.Name() + "\""
-	val, err := ReadFile(quotedFileName)
-	Expect(err).NotTo(HaveOccurred())
-	Expect(val).To(Equal("example"))
+	// Set env var to one file
+	os.Setenv("HYPERFLEET_CONFIG", envConfigFile)
+	defer os.Unsetenv("HYPERFLEET_CONFIG")
+
+	// Create flag set with different config file
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewApplicationConfig()
+
+	// Configure flags (define and bind)
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{"--config=" + flagConfigFile})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := testLoadConfig(v, flags)
+	require.NoError(t, err)
+
+	// Flag should win over env var
+	assert.Equal(t, "flag-config", loadedCfg.App.Name, "--config flag should override HYPERFLEET_CONFIG env var")
 }
-func createConfigFile(namePrefix, contents string) (*os.File, error) {
-	configFile, err := os.CreateTemp("", namePrefix)
-	if err != nil {
-		return nil, err
-	}
-	if _, err = configFile.Write([]byte(contents)); err != nil {
-		return configFile, err
-	}
-	err = configFile.Close()
-	return configFile, err
+
+// TestConfigPrecedence_DatabasePassword tests password precedence specifically
+func TestConfigPrecedence_DatabasePassword(t *testing.T) {
+	// Create temporary config file
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: test
+  version: 1.0.0
+server:
+  host: localhost
+  port: 8000
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+  password: file-password
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Set environment variable
+	os.Setenv("HYPERFLEET_DATABASE_PASSWORD", "env-password")
+	defer os.Unsetenv("HYPERFLEET_DATABASE_PASSWORD")
+
+	// Create flag set
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewApplicationConfig()
+
+	// Configure flags (define and bind)
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{
+		"--config=" + configFile,
+		"--db-password=cli-password",
+	})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := testLoadConfig(v, flags)
+	require.NoError(t, err)
+
+	// CLI password should win
+	assert.Equal(t, "cli-password", loadedCfg.Database.Password, "CLI password should override env and file")
 }
diff --git a/pkg/config/db.go b/pkg/config/db.go
index 65c95aed..3c377aa9 100755
--- a/pkg/config/db.go
+++ b/pkg/config/db.go
@@ -4,26 +4,20 @@ import (
 	"fmt"
 
 	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
 )
 
 type DatabaseConfig struct {
-	Dialect            string `json:"dialect"`
-	SSLMode            string `json:"sslmode"`
-	Debug              bool   `json:"debug"`
-	MaxOpenConnections int    `json:"max_connections"`
-
-	Host     string `json:"host"`
-	Port     int    `json:"port"`
-	Name     string `json:"name"`
-	Username string `json:"username"`
-	Password string `json:"password"`
-
-	HostFile     string `json:"host_file"`
-	PortFile     string `json:"port_file"`
-	NameFile     string `json:"name_file"`
-	UsernameFile string `json:"username_file"`
-	PasswordFile string `json:"password_file"`
-	RootCertFile string `json:"certificate_file"`
+	Dialect            string `mapstructure:"dialect" json:"dialect" validate:"required"`
+	Host               string `mapstructure:"host" json:"host" validate:""`
+	Port               int    `mapstructure:"port" json:"port" validate:"min=0,max=65535"`
+	Name               string `mapstructure:"name" json:"name" validate:""`
+	Username           string `mapstructure:"username" json:"username" validate:""`
+	Password           string `mapstructure:"password" json:"password" validate:""`
+	SSLMode            string `mapstructure:"sslmode" json:"sslmode" validate:"oneof=disable require verify-ca verify-full"`
+	RootCertFile       string `mapstructure:"rootcert_file" json:"rootcert_file" validate:""`
+	Debug              bool   `mapstructure:"debug" json:"debug"`
+	MaxOpenConnections int    `mapstructure:"max_open_connections" json:"max_open_connections" validate:"min=1"`
 }
 
 func NewDatabaseConfig() *DatabaseConfig {
@@ -32,57 +26,31 @@ func NewDatabaseConfig() *DatabaseConfig {
 		SSLMode:            "disable",
 		Debug:              false,
 		MaxOpenConnections: 50,
-
-		HostFile:     "secrets/db.host",
-		PortFile:     "secrets/db.port",
-		NameFile:     "secrets/db.name",
-		UsernameFile: "secrets/db.user",
-		PasswordFile: "secrets/db.password",
-		RootCertFile: "secrets/db.rootcert",
 	}
 }
 
-func (c *DatabaseConfig) AddFlags(fs *pflag.FlagSet) {
-	fs.StringVar(&c.HostFile, "db-host-file", c.HostFile, "Database host string file")
-	fs.StringVar(&c.PortFile, "db-port-file", c.PortFile, "Database port file")
-	fs.StringVar(&c.UsernameFile, "db-user-file", c.UsernameFile, "Database username file")
-	fs.StringVar(&c.PasswordFile, "db-password-file", c.PasswordFile, "Database password file")
-	fs.StringVar(&c.NameFile, "db-name-file", c.NameFile, "Database name file")
-	fs.StringVar(&c.RootCertFile, "db-rootcert", c.RootCertFile, "Database root certificate file")
-	fs.StringVar(&c.SSLMode, "db-sslmode", c.SSLMode, "Database ssl mode (disable | require | verify-ca | verify-full)")
-	fs.BoolVar(&c.Debug, "enable-db-debug", c.Debug, " framework's debug mode")
-	fs.IntVar(&c.MaxOpenConnections, "db-max-open-connections", c.MaxOpenConnections, "Maximum open DB connections for this instance")
-}
-
-func (c *DatabaseConfig) ReadFiles() error {
-	err := readFileValueString(c.HostFile, &c.Host)
-	if err != nil {
-		return err
-	}
-
-	err = readFileValueInt(c.PortFile, &c.Port)
-	if err != nil {
-		return err
-	}
-
-	err = readFileValueString(c.UsernameFile, &c.Username)
-	if err != nil {
-		return err
-	}
-
-	err = readFileValueString(c.PasswordFile, &c.Password)
-	if err != nil {
-		return err
-	}
-
-	err = readFileValueString(c.NameFile, &c.Name)
-	return err
+// defineAndBindFlags defines database flags and binds them to viper keys in a single pass
+func (c *DatabaseConfig) defineAndBindFlags(v *viper.Viper, fs *pflag.FlagSet) {
+	// Direct database connection parameters
+	defineAndBindStringFlag(v, fs, "database.host", "db-host", "", c.Host, "Database host")
+	defineAndBindIntFlag(v, fs, "database.port", "db-port", "", c.Port, "Database port")
+	defineAndBindStringFlag(v, fs, "database.username", "db-username", "u", c.Username, "Database username")
+	defineAndBindStringFlag(v, fs, "database.password", "db-password", "", c.Password, "Database password (prefer using env var)")
+	defineAndBindStringFlag(v, fs, "database.name", "db-name", "d", c.Name, "Database name")
+
+	// Connection options
+	defineAndBindStringFlag(v, fs, "database.rootcert_file", "db-rootcert", "", c.RootCertFile, "Database root certificate file")
+	defineAndBindStringFlag(v, fs, "database.sslmode", "db-sslmode", "", c.SSLMode, "Database SSL mode (disable | require | verify-ca | verify-full)")
+	defineAndBindBoolFlag(v, fs, "database.debug", "db-debug", "", c.Debug, "Enable database debug mode")
+	defineAndBindIntFlag(v, fs, "database.max_open_connections", "db-max-open-connections", "", c.MaxOpenConnections, "Maximum open DB connections")
 }
 
+// ConnectionString returns the database connection string
 func (c *DatabaseConfig) ConnectionString(withSSL bool) string {
 	return c.ConnectionStringWithName(c.Name, withSSL)
 }
 
+// ConnectionStringWithName returns the database connection string with a specific database name
 func (c *DatabaseConfig) ConnectionStringWithName(name string, withSSL bool) string {
 	var cmd string
 	if withSSL {
@@ -100,20 +68,21 @@ func (c *DatabaseConfig) ConnectionStringWithName(name string, withSSL bool) str
 	return cmd
 }
 
+// LogSafeConnectionString returns a connection string with sensitive data redacted
 func (c *DatabaseConfig) LogSafeConnectionString(withSSL bool) string {
 	return c.LogSafeConnectionStringWithName(c.Name, withSSL)
 }
 
+// LogSafeConnectionStringWithName returns a connection string with sensitive data redacted
 func (c *DatabaseConfig) LogSafeConnectionStringWithName(name string, withSSL bool) string {
 	if withSSL {
 		return fmt.Sprintf(
 			"host=%s port=%d user=%s password='<REDACTED>' dbname=%s sslmode=%s sslrootcert='<REDACTED>'",
 			c.Host, c.Port, c.Username, name, c.SSLMode,
 		)
-	} else {
-		return fmt.Sprintf(
-			"host=%s port=%d user=%s password='<REDACTED>' dbname=%s",
-			c.Host, c.Port, c.Username, name,
-		)
 	}
+	return fmt.Sprintf(
+		"host=%s port=%d user=%s password='<REDACTED>' dbname=%s",
+		c.Host, c.Port, c.Username, name,
+	)
 }
diff --git a/pkg/config/health_check.go b/pkg/config/health_check.go
index e3aaa793..a1f91824 100755
--- a/pkg/config/health_check.go
+++ b/pkg/config/health_check.go
@@ -1,26 +1,41 @@
 package config
 
 import (
+	"fmt"
+
 	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
 )
 
 type HealthCheckConfig struct {
-	BindAddress string `json:"bind_address"`
-	EnableHTTPS bool   `json:"enable_https"`
+	Host        string `mapstructure:"host" json:"host" validate:""`
+	Port        int    `mapstructure:"port" json:"port" validate:"min=1,max=65535"`
+	EnableHTTPS bool   `mapstructure:"enable_https" json:"enable_https"`
+
+	// Legacy field for backward compatibility
+	BindAddress string `mapstructure:"bind_address" json:"bind_address,omitempty"`
 }
 
 func NewHealthCheckConfig() *HealthCheckConfig {
 	return &HealthCheckConfig{
-		BindAddress: "localhost:8083",
+		Host:        "localhost",
+		Port:        8083,
 		EnableHTTPS: false,
+		BindAddress: "localhost:8083",
 	}
 }
 
-func (c *HealthCheckConfig) AddFlags(fs *pflag.FlagSet) {
-	fs.StringVar(&c.BindAddress, "health-check-server-bindaddress", c.BindAddress, "Health check server bind adddress")
-	fs.BoolVar(&c.EnableHTTPS, "enable-health-check-https", c.EnableHTTPS, "Enable HTTPS for health check server")
+// defineAndBindFlags defines & binds flags to viper keys in a single pass
+func (c *HealthCheckConfig) defineAndBindFlags(v *viper.Viper, fs *pflag.FlagSet) {
+	defineAndBindStringFlag(v, fs, "health_check.host", "health-check-host", "", c.Host, "Health check server bind host")
+	defineAndBindIntFlag(v, fs, "health_check.port", "health-check-port", "", c.Port, "Health check server bind port")
+	defineAndBindBoolFlag(v, fs, "health_check.enable_https", "health-check-https-enabled", "", c.EnableHTTPS, "Enable HTTPS for health check server")
 }
 
-func (c *HealthCheckConfig) ReadFiles() error {
-	return nil
+// GetBindAddress returns the bind address in host:port format
+func (c *HealthCheckConfig) GetBindAddress() string {
+	if c.BindAddress != "" {
+		return c.BindAddress
+	}
+	return fmt.Sprintf("%s:%d", c.Host, c.Port)
 }
diff --git a/pkg/config/metrics.go b/pkg/config/metrics.go
index b01c3c3c..a742446c 100755
--- a/pkg/config/metrics.go
+++ b/pkg/config/metrics.go
@@ -1,31 +1,46 @@
 package config
 
 import (
+	"fmt"
 	"time"
 
 	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
 )
 
 type MetricsConfig struct {
-	BindAddress                   string        `json:"bind_address"`
-	EnableHTTPS                   bool          `json:"enable_https"`
-	LabelMetricsInclusionDuration time.Duration `json:"label_metrics_inclusion_duration"`
+	Host                          string        `mapstructure:"host" json:"host" validate:""`
+	Port                          int           `mapstructure:"port" json:"port" validate:"min=1,max=65535"`
+	EnableHTTPS                   bool          `mapstructure:"enable_https" json:"enable_https"`
+	LabelMetricsInclusionDuration time.Duration `mapstructure:"label_metrics_inclusion_duration" json:"label_metrics_inclusion_duration"`
+
+	// Legacy field for backward compatibility
+	BindAddress string `mapstructure:"bind_address" json:"bind_address,omitempty"`
 }
 
 func NewMetricsConfig() *MetricsConfig {
 	return &MetricsConfig{
-		BindAddress:                   "localhost:8080",
+		Host:                          "localhost",
+		Port:                          8080,
 		EnableHTTPS:                   false,
 		LabelMetricsInclusionDuration: 7 * 24 * time.Hour,
+		BindAddress:                   "localhost:8080",
 	}
 }
 
-func (s *MetricsConfig) AddFlags(fs *pflag.FlagSet) {
-	fs.StringVar(&s.BindAddress, "metrics-server-bindaddress", s.BindAddress, "Metrics server bind adddress")
-	fs.BoolVar(&s.EnableHTTPS, "enable-metrics-https", s.EnableHTTPS, "Enable HTTPS for metrics server")
-	fs.DurationVar(&s.LabelMetricsInclusionDuration, "label-metrics-inclusion-duration", 7*24*time.Hour, "A cluster's last telemetry date needs be within in this duration in order to have labels collected")
+// defineAndBindFlags defines & binds flags to viper keys in a single pass
+func (s *MetricsConfig) defineAndBindFlags(v *viper.Viper, fs *pflag.FlagSet) {
+	defineAndBindStringFlag(v, fs, "metrics.host", "metrics-host", "", s.Host, "Metrics server bind host")
+	defineAndBindIntFlag(v, fs, "metrics.port", "metrics-port", "", s.Port, "Metrics server bind port")
+	defineAndBindBoolFlag(v, fs, "metrics.enable_https", "metrics-https-enabled", "", s.EnableHTTPS, "Enable HTTPS for metrics server")
+	defineAndBindDurationFlag(v, fs, "metrics.label_metrics_inclusion_duration", "metrics-label-inclusion-duration", "", s.LabelMetricsInclusionDuration,
+		"A cluster's last telemetry date needs to be within this duration to have labels collected")
 }
 
-func (s *MetricsConfig) ReadFiles() error {
-	return nil
+// GetBindAddress returns the bind address in host:port format
+func (s *MetricsConfig) GetBindAddress() string {
+	if s.BindAddress != "" {
+		return s.BindAddress
+	}
+	return fmt.Sprintf("%s:%d", s.Host, s.Port)
 }
diff --git a/pkg/config/migrate_config.go b/pkg/config/migrate_config.go
new file mode 100644
index 00000000..e8af4160
--- /dev/null
+++ b/pkg/config/migrate_config.go
@@ -0,0 +1,155 @@
+package config
+
+import (
+	"encoding/json"
+	"flag"
+	"fmt"
+	"reflect"
+
+	"github.com/go-playground/validator/v10"
+	"github.com/golang/glog"
+	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
+)
+
+// MigrateConfig holds configuration for the migrate command
+// Only requires App and Database configuration
+type MigrateConfig struct {
+	App      *AppConfig      `mapstructure:"app" json:"app" validate:"required"`
+	Database *DatabaseConfig `mapstructure:"database" json:"database" validate:"required"`
+}
+
+// NewMigrateConfig creates a new MigrateConfig with default values
+func NewMigrateConfig() *MigrateConfig {
+	return &MigrateConfig{
+		App:      NewAppConfig(),
+		Database: NewDatabaseConfig(),
+	}
+}
+
+// defineAndBindFlags defines migrate command flags and binds them to viper keys in a single pass
+func (c *MigrateConfig) defineAndBindFlags(v *viper.Viper, flagset *pflag.FlagSet) {
+	// Global flags
+	// Note: config flag is defined but NOT bound to viper (special case)
+	flagset.String("config", "", "Config file path")
+
+	// Define and bind sub-config flags (only App and Database for migrate)
+	c.App.defineAndBindFlags(v, flagset)
+	c.Database.defineAndBindFlags(v, flagset)
+}
+
+// ConfigureFlags defines configuration flags and binds them to viper for precedence handling
+func (c *MigrateConfig) ConfigureFlags(v *viper.Viper, flagset *pflag.FlagSet) {
+	flagset.AddGoFlagSet(flag.CommandLine)
+	c.defineAndBindFlags(v, flagset)
+}
+
+// LoadMigrateConfig loads configuration for the migrate command from multiple sources with proper precedence:
+// 1. Command-line flags (highest priority)
+// 2. Environment variables (HYPERFLEET_ prefix)
+// 3. Configuration files
+// 4. Defaults (lowest priority)
+//
+// The viper instance should already be configured and have flags bound via ConfigureFlags()
+func LoadMigrateConfig(v *viper.Viper, flags *pflag.FlagSet) (*MigrateConfig, error) {
+	// Create config instance
+	// Note: Viper is already configured with env support and flags are already bound
+	config := NewMigrateConfig()
+
+	// Determine config file path
+	configFile := getConfigFilePath(flags, v)
+
+	// Load config file if it exists
+	if configFile != "" {
+		v.SetConfigFile(configFile)
+		if err := v.ReadInConfig(); err != nil {
+			if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
+				return nil, fmt.Errorf("error reading config file %s: %w", configFile, err)
+			}
+			glog.Infof("Config file not found: %s, continuing with flags and environment variables", configFile)
+		} else {
+			glog.Infof("Loaded configuration from: %s", configFile)
+		}
+	}
+
+	// Unmarshal into config struct
+	// Viper now contains: config file values < env vars < bound flags
+	// This gives us the correct precedence automatically
+	// Note: Using Unmarshal (not UnmarshalExact) to allow extra fields in config file
+	// (e.g., shared config files with server, metrics, etc. will be ignored)
+	if err := v.Unmarshal(config); err != nil {
+		return nil, fmt.Errorf("error unmarshaling config: %w", err)
+	}
+
+	// Validate configuration
+	if err := config.Validate(); err != nil {
+		return nil, err
+	}
+
+	return config, nil
+}
+
+// Validate validates the migrate configuration using struct tags
+// Only App and Database are required for migrate command
+func (c *MigrateConfig) Validate() error {
+	validate := validator.New()
+
+	if err := validate.Struct(c); err != nil {
+		return formatValidationError(err)
+	}
+
+	return nil
+}
+
+// DisplayConfig logs the merged configuration at startup
+// Sensitive values are redacted
+func (c *MigrateConfig) DisplayConfig() {
+	glog.Info("=== Merged Configuration (Migrate Command) ===")
+
+	// Create a copy for display with sensitive values redacted
+	displayCopy := c.redactSensitiveValues()
+
+	// Convert to JSON for pretty display
+	jsonBytes, err := json.MarshalIndent(displayCopy, "", "  ")
+	if err != nil {
+		glog.Errorf("Error marshaling config for display: %v", err)
+		return
+	}
+
+	glog.Infof("\n%s", string(jsonBytes))
+	glog.Info("===============================================")
+}
+
+// GetJSONConfig returns the configuration as a JSON string
+// Sensitive values are redacted
+func (c *MigrateConfig) GetJSONConfig() (string, error) {
+	displayCopy := c.redactSensitiveValues()
+
+	jsonBytes, err := json.MarshalIndent(displayCopy, "", "  ")
+	if err != nil {
+		return "", fmt.Errorf("error marshaling config to JSON: %w", err)
+	}
+
+	return string(jsonBytes), nil
+}
+
+// redactSensitiveValues creates a copy of the config with sensitive values redacted
+func (c *MigrateConfig) redactSensitiveValues() *MigrateConfig {
+	// Marshal to JSON and back to create a deep copy
+	jsonBytes, err := json.Marshal(c)
+	if err != nil {
+		glog.Errorf("Error marshaling config for redaction: %v", err)
+		return c
+	}
+
+	var copy MigrateConfig
+	if err := json.Unmarshal(jsonBytes, &copy); err != nil {
+		glog.Errorf("Error unmarshaling config for redaction: %v", err)
+		return c
+	}
+
+	// Recursively redact sensitive fields using the shared function from config.go
+	redactSensitiveFields(reflect.ValueOf(&copy).Elem())
+
+	return &copy
+}
diff --git a/pkg/config/migrate_config_test.go b/pkg/config/migrate_config_test.go
new file mode 100644
index 00000000..e209cf71
--- /dev/null
+++ b/pkg/config/migrate_config_test.go
@@ -0,0 +1,301 @@
+package config
+
+import (
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/spf13/pflag"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+// TestMigrateConfig_MinimalRequiredConfig tests that migrate only requires App and Database
+func TestMigrateConfig_MinimalRequiredConfig(t *testing.T) {
+	// Create minimal config file with only required sections
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: migrate-test
+  version: 1.0.0
+database:
+  dialect: postgres
+  host: localhost
+  port: 5432
+  name: hyperfleet
+  username: hyperfleet
+  password: secret
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Create flag set
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewMigrateConfig()
+
+	// Create viper and configure flags
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := LoadMigrateConfig(v, flags)
+	require.NoError(t, err)
+
+	// Verify required fields loaded
+	assert.Equal(t, "migrate-test", loadedCfg.App.Name)
+	assert.Equal(t, "postgres", loadedCfg.Database.Dialect)
+	assert.Equal(t, "localhost", loadedCfg.Database.Host)
+}
+
+// TestMigrateConfig_IgnoresExtraConfigSections tests that migrate ignores extra config sections
+// This allows using shared config files with serve (backward compatibility)
+func TestMigrateConfig_IgnoresExtraConfigSections(t *testing.T) {
+	// Create full config file (as used by serve command)
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: full-config-test
+  version: 1.0.0
+server:
+  host: localhost
+  port: 8000
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+  host: localhost
+  port: 5432
+  name: hyperfleet
+  username: hyperfleet
+  password: secret
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Create flag set
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewMigrateConfig()
+
+	// Create viper and configure flags
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
+
+	// Load config - should not fail even with extra sections (they're ignored)
+	loadedCfg, err := LoadMigrateConfig(v, flags)
+	require.NoError(t, err)
+
+	// Verify required fields loaded correctly
+	assert.Equal(t, "full-config-test", loadedCfg.App.Name)
+	assert.Equal(t, "postgres", loadedCfg.Database.Dialect)
+	assert.Equal(t, "localhost", loadedCfg.Database.Host)
+
+	// Extra sections (server, metrics, health_check, ocm) are ignored
+	// MigrateConfig only has App and Database fields
+}
+
+// TestMigrateConfig_Precedence tests command-line flags override environment variables
+func TestMigrateConfig_Precedence(t *testing.T) {
+	// Set environment variable
+	os.Setenv("HYPERFLEET_DATABASE_HOST", "env-host")
+	defer os.Unsetenv("HYPERFLEET_DATABASE_HOST")
+
+	// Create minimal config file
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: precedence-test
+  version: 1.0.0
+database:
+  dialect: postgres
+  host: file-host
+  port: 5432
+  name: hyperfleet
+  username: hyperfleet
+  password: secret
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Create flag set with command-line value
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewMigrateConfig()
+
+	// Create viper and configure flags
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{
+		"--config=" + configFile,
+		"--db-host=cli-host",
+	})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := LoadMigrateConfig(v, flags)
+	require.NoError(t, err)
+
+	// CLI should win
+	assert.Equal(t, "cli-host", loadedCfg.Database.Host, "CLI flag should override env and file")
+}
+
+// TestMigrateConfig_EnvVarOverridesFile tests environment variable precedence
+func TestMigrateConfig_EnvVarOverridesFile(t *testing.T) {
+	// Create minimal config file
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: file-name
+  version: 1.0.0
+database:
+  dialect: postgres
+  host: localhost
+  port: 5432
+  name: hyperfleet
+  username: hyperfleet
+  password: file-password
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Set environment variable
+	os.Setenv("HYPERFLEET_DATABASE_PASSWORD", "env-password")
+	defer os.Unsetenv("HYPERFLEET_DATABASE_PASSWORD")
+
+	// Create flag set
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewMigrateConfig()
+
+	// Create viper and configure flags
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := LoadMigrateConfig(v, flags)
+	require.NoError(t, err)
+
+	// Env var should override file
+	assert.Equal(t, "env-password", loadedCfg.Database.Password, "Environment variable should override config file")
+}
+
+// TestMigrateConfig_ValidatesRequiredDatabaseDialect tests that database dialect is validated
+func TestMigrateConfig_ValidatesRequiredDatabaseDialect(t *testing.T) {
+	// Create config file with database section but missing dialect
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: incomplete-test
+  version: 1.0.0
+database:
+  dialect: ""
+  host: localhost
+  port: 5432
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Create flag set
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewMigrateConfig()
+
+	// Create viper and configure flags
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
+
+	// Load config - should fail validation due to empty dialect
+	_, err = LoadMigrateConfig(v, flags)
+	require.Error(t, err, "Should fail when database dialect is empty")
+	assert.Contains(t, err.Error(), "Dialect")
+}
+
+// TestMigrateConfig_FlagsOnly tests loading from flags without config file
+func TestMigrateConfig_FlagsOnly(t *testing.T) {
+	// Create flag set with all required flags
+	// Note: dialect doesn't have a flag, it uses the default value "postgres"
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewMigrateConfig()
+
+	// Create viper and configure flags
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err := flags.Parse([]string{
+		"--name=flags-only-test",
+		"--version=2.0.0",
+		"--db-host=localhost",
+		"--db-port=5432",
+		"--db-name=hyperfleet",
+		"--db-username=admin",
+		"--db-password=secret123",
+	})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := LoadMigrateConfig(v, flags)
+	require.NoError(t, err)
+
+	// Verify config loaded from flags
+	assert.Equal(t, "flags-only-test", loadedCfg.App.Name)
+	assert.Equal(t, "postgres", loadedCfg.Database.Dialect) // Uses default value
+	assert.Equal(t, "localhost", loadedCfg.Database.Host)
+	assert.Equal(t, "admin", loadedCfg.Database.Username)
+}
+
+// TestMigrateConfig_DisplayConfig tests that DisplayConfig doesn't panic
+func TestMigrateConfig_DisplayConfig(t *testing.T) {
+	// Create minimal config
+	cfg := NewMigrateConfig()
+	cfg.App.Name = "display-test"
+	cfg.Database.Dialect = "postgres"
+	cfg.Database.Password = "secret-password"
+
+	// Should not panic
+	assert.NotPanics(t, func() {
+		cfg.DisplayConfig()
+	})
+}
+
+// TestMigrateConfig_GetJSONConfig tests JSON output with redaction
+func TestMigrateConfig_GetJSONConfig(t *testing.T) {
+	// Create minimal config with sensitive data
+	cfg := NewMigrateConfig()
+	cfg.App.Name = "json-test"
+	cfg.Database.Dialect = "postgres"
+	cfg.Database.Password = "super-secret-password"
+
+	// Get JSON
+	jsonStr, err := cfg.GetJSONConfig()
+	require.NoError(t, err)
+
+	// Verify JSON contains app name but password is redacted
+	assert.Contains(t, jsonStr, "json-test")
+	assert.NotContains(t, jsonStr, "super-secret-password")
+	assert.Contains(t, jsonStr, "***") // Redacted password
+}
diff --git a/pkg/config/ocm.go b/pkg/config/ocm.go
index 1f7c6ab9..823f1e38 100755
--- a/pkg/config/ocm.go
+++ b/pkg/config/ocm.go
@@ -2,55 +2,38 @@ package config
 
 import (
 	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
 )
 
 type OCMConfig struct {
-	BaseURL          string `json:"base_url"`
-	ClientID         string `json:"client-id"`
-	ClientIDFile     string `json:"client-id_file"`
-	ClientSecret     string `json:"client-secret"`
-	ClientSecretFile string `json:"client-secret_file"`
-	SelfToken        string `json:"self_token"`
-	SelfTokenFile    string `json:"self_token_file"`
-	TokenURL         string `json:"token_url"`
-	Debug            bool   `json:"debug"`
-	EnableMock       bool   `json:"enable_mock"`
+	BaseURL      string `mapstructure:"base_url" json:"base_url" validate:""`
+	ClientID     string `mapstructure:"client_id" json:"client_id" validate:""`
+	ClientSecret string `mapstructure:"client_secret" json:"client_secret" validate:""`
+	SelfToken    string `mapstructure:"self_token" json:"self_token" validate:""`
+	TokenURL     string `mapstructure:"token_url" json:"token_url" validate:""`
+	Debug        bool   `mapstructure:"debug" json:"debug"`
+	EnableMock   bool   `mapstructure:"enable_mock" json:"enable_mock"`
 }
 
 func NewOCMConfig() *OCMConfig {
 	return &OCMConfig{
-		BaseURL:          "https://api.integration.openshift.com",
-		TokenURL:         "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token",
-		ClientIDFile:     "secrets/ocm-service.clientId",
-		ClientSecretFile: "secrets/ocm-service.clientSecret",
-		SelfTokenFile:    "",
-		Debug:            false,
-		EnableMock:       true,
+		BaseURL:    "https://api.integration.openshift.com",
+		TokenURL:   "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token",
+		Debug:      false,
+		EnableMock: true,
 	}
 }
 
-func (c *OCMConfig) AddFlags(fs *pflag.FlagSet) {
-	fs.StringVar(&c.ClientIDFile, "ocm-client-id-file", c.ClientIDFile, "File containing OCM API privileged account client-id")
-	fs.StringVar(&c.ClientSecretFile, "ocm-client-secret-file", c.ClientSecretFile, "File containing OCM API privileged account client-secret")
-	fs.StringVar(&c.SelfTokenFile, "self-token-file", c.SelfTokenFile, "File containing OCM API privileged offline SSO token")
-	fs.StringVar(&c.BaseURL, "ocm-base-url", c.BaseURL, "The base URL of the OCM API, integration by default")
-	fs.StringVar(&c.TokenURL, "ocm-token-url", c.TokenURL, "The base URL that OCM uses to request tokens, stage by default")
-	fs.BoolVar(&c.Debug, "ocm-debug", c.Debug, "Debug flag for OCM API")
-	fs.BoolVar(&c.EnableMock, "enable-ocm-mock", c.EnableMock, "Enable mock ocm clients")
-}
+// defineAndBindFlags defines & binds flags to viper keys in a single pass
+func (c *OCMConfig) defineAndBindFlags(v *viper.Viper, fs *pflag.FlagSet) {
+	// OCM connection parameters
+	defineAndBindStringFlag(v, fs, "ocm.base_url", "ocm-base-url", "", c.BaseURL, "OCM API base URL")
+	defineAndBindStringFlag(v, fs, "ocm.token_url", "ocm-token-url", "", c.TokenURL, "OCM token URL")
+	defineAndBindStringFlag(v, fs, "ocm.client_id", "ocm-client-id", "", c.ClientID, "OCM client ID")
+	defineAndBindStringFlag(v, fs, "ocm.client_secret", "ocm-client-secret", "", c.ClientSecret, "OCM client secret (prefer using env var)")
+	defineAndBindStringFlag(v, fs, "ocm.self_token", "ocm-self-token", "", c.SelfToken, "OCM self token (prefer using env var)")
 
-func (c *OCMConfig) ReadFiles() error {
-	if c.EnableMock {
-		return nil
-	}
-	err := readFileValueString(c.ClientIDFile, &c.ClientID)
-	if err != nil {
-		return err
-	}
-	err = readFileValueString(c.ClientSecretFile, &c.ClientSecret)
-	if err != nil {
-		return err
-	}
-	err = readFileValueString(c.SelfTokenFile, &c.SelfToken)
-	return err
+	// Options
+	defineAndBindBoolFlag(v, fs, "ocm.debug", "ocm-debug", "", c.Debug, "Enable OCM debug mode")
+	defineAndBindBoolFlag(v, fs, "ocm.enable_mock", "ocm-mock", "", c.EnableMock, "Enable mock OCM client")
 }
diff --git a/pkg/config/serve_config.go b/pkg/config/serve_config.go
new file mode 100644
index 00000000..926a4ea9
--- /dev/null
+++ b/pkg/config/serve_config.go
@@ -0,0 +1,178 @@
+package config
+
+import (
+	"encoding/json"
+	"flag"
+	"fmt"
+	"reflect"
+
+	"github.com/go-playground/validator/v10"
+	"github.com/golang/glog"
+	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
+)
+
+// ServeConfig holds configuration for the serve command
+// Requires all configuration sections (App, Server, Metrics, HealthCheck, Database, OCM)
+type ServeConfig struct {
+	App         *AppConfig         `mapstructure:"app" json:"app" validate:"required"`
+	Server      *ServerConfig      `mapstructure:"server" json:"server" validate:"required"`
+	Metrics     *MetricsConfig     `mapstructure:"metrics" json:"metrics" validate:"required"`
+	HealthCheck *HealthCheckConfig `mapstructure:"health_check" json:"health_check" validate:"required"`
+	Database    *DatabaseConfig    `mapstructure:"database" json:"database" validate:"required"`
+	OCM         *OCMConfig         `mapstructure:"ocm" json:"ocm" validate:"required"`
+}
+
+// NewServeConfig creates a new ServeConfig with default values
+func NewServeConfig() *ServeConfig {
+	return &ServeConfig{
+		App:         NewAppConfig(),
+		Server:      NewServerConfig(),
+		Metrics:     NewMetricsConfig(),
+		HealthCheck: NewHealthCheckConfig(),
+		Database:    NewDatabaseConfig(),
+		OCM:         NewOCMConfig(),
+	}
+}
+
+// defineAndBindFlags defines serve command flags and binds them to viper keys in a single pass
+func (c *ServeConfig) defineAndBindFlags(v *viper.Viper, flagset *pflag.FlagSet) {
+	// Global flags
+	// Note: config flag is defined but NOT bound to viper (special case)
+	flagset.String("config", "", "Config file path")
+
+	// Define and bind sub-config flags (all required for serve)
+	c.App.defineAndBindFlags(v, flagset)
+	c.Server.defineAndBindFlags(v, flagset)
+	c.Metrics.defineAndBindFlags(v, flagset)
+	c.HealthCheck.defineAndBindFlags(v, flagset)
+	c.Database.defineAndBindFlags(v, flagset)
+	c.OCM.defineAndBindFlags(v, flagset)
+}
+
+// ConfigureFlags defines configuration flags and binds them to viper for precedence handling
+func (c *ServeConfig) ConfigureFlags(v *viper.Viper, flagset *pflag.FlagSet) {
+	flagset.AddGoFlagSet(flag.CommandLine)
+	c.defineAndBindFlags(v, flagset)
+}
+
+// LoadServeConfig loads configuration for the serve command from multiple sources with proper precedence:
+// 1. Command-line flags (highest priority)
+// 2. Environment variables (HYPERFLEET_ prefix)
+// 3. Configuration files
+// 4. Defaults (lowest priority)
+//
+// The viper instance should already be configured and have flags bound via ConfigureFlags()
+func LoadServeConfig(v *viper.Viper, flags *pflag.FlagSet) (*ServeConfig, error) {
+	// Create config instance
+	// Note: Viper is already configured with env support and flags are already bound
+	config := NewServeConfig()
+
+	// Determine config file path
+	configFile := getConfigFilePath(flags, v)
+
+	// Load config file if it exists
+	if configFile != "" {
+		v.SetConfigFile(configFile)
+		if err := v.ReadInConfig(); err != nil {
+			if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
+				return nil, fmt.Errorf("error reading config file %s: %w", configFile, err)
+			}
+			glog.Infof("Config file not found: %s, continuing with flags and environment variables", configFile)
+		} else {
+			glog.Infof("Loaded configuration from: %s", configFile)
+		}
+	}
+
+	// Unmarshal into config struct
+	// Viper now contains: config file values < env vars < bound flags
+	// This gives us the correct precedence automatically
+	if err := v.UnmarshalExact(config); err != nil {
+		return nil, fmt.Errorf("error unmarshaling config: %w", err)
+	}
+
+	// Validate configuration
+	if err := config.Validate(); err != nil {
+		return nil, err
+	}
+
+	return config, nil
+}
+
+// Validate validates the serve configuration using struct tags
+// All sections (App, Server, Metrics, HealthCheck, Database, OCM) are required for serve command
+func (c *ServeConfig) Validate() error {
+	validate := validator.New()
+
+	if err := validate.Struct(c); err != nil {
+		return formatValidationError(err)
+	}
+
+	return nil
+}
+
+// DisplayConfig logs the merged configuration at startup
+// Sensitive values are redacted
+func (c *ServeConfig) DisplayConfig() {
+	glog.Info("=== Merged Configuration (Serve Command) ===")
+
+	// Create a copy for display with sensitive values redacted
+	displayCopy := c.redactSensitiveValues()
+
+	// Convert to JSON for pretty display
+	jsonBytes, err := json.MarshalIndent(displayCopy, "", "  ")
+	if err != nil {
+		glog.Errorf("Error marshaling config for display: %v", err)
+		return
+	}
+
+	glog.Infof("\n%s", string(jsonBytes))
+	glog.Info("============================================")
+}
+
+// GetJSONConfig returns the configuration as a JSON string
+// Sensitive values are redacted
+func (c *ServeConfig) GetJSONConfig() (string, error) {
+	displayCopy := c.redactSensitiveValues()
+
+	jsonBytes, err := json.MarshalIndent(displayCopy, "", "  ")
+	if err != nil {
+		return "", fmt.Errorf("error marshaling config to JSON: %w", err)
+	}
+
+	return string(jsonBytes), nil
+}
+
+// redactSensitiveValues creates a copy of the config with sensitive values redacted
+func (c *ServeConfig) redactSensitiveValues() *ServeConfig {
+	// Marshal to JSON and back to create a deep copy
+	jsonBytes, err := json.Marshal(c)
+	if err != nil {
+		glog.Errorf("Error marshaling config for redaction: %v", err)
+		return c
+	}
+
+	var copy ServeConfig
+	if err := json.Unmarshal(jsonBytes, &copy); err != nil {
+		glog.Errorf("Error unmarshaling config for redaction: %v", err)
+		return c
+	}
+
+	// Recursively redact sensitive fields using the shared function from config.go
+	redactSensitiveFields(reflect.ValueOf(&copy).Elem())
+
+	return &copy
+}
+
+// ToApplicationConfig converts ServeConfig to ApplicationConfig for compatibility
+// with existing code (e.g., environments.Initialize())
+func (c *ServeConfig) ToApplicationConfig() *ApplicationConfig {
+	return &ApplicationConfig{
+		App:         c.App,
+		Server:      c.Server,
+		Metrics:     c.Metrics,
+		HealthCheck: c.HealthCheck,
+		Database:    c.Database,
+		OCM:         c.OCM,
+	}
+}
diff --git a/pkg/config/serve_config_test.go b/pkg/config/serve_config_test.go
new file mode 100644
index 00000000..aa2caf6d
--- /dev/null
+++ b/pkg/config/serve_config_test.go
@@ -0,0 +1,305 @@
+package config
+
+import (
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/spf13/pflag"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+// TestServeConfig_FullConfig tests that serve requires all configuration sections
+func TestServeConfig_FullConfig(t *testing.T) {
+	// Create full config file with all required sections
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: serve-test
+  version: 1.0.0
+server:
+  host: localhost
+  port: 8000
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+  host: localhost
+  port: 5432
+  name: hyperfleet
+  username: hyperfleet
+  password: secret
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Create flag set
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewServeConfig()
+
+	// Create viper and configure flags
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := LoadServeConfig(v, flags)
+	require.NoError(t, err)
+
+	// Verify all fields loaded
+	assert.Equal(t, "serve-test", loadedCfg.App.Name)
+	assert.Equal(t, 8000, loadedCfg.Server.Port)
+	assert.Equal(t, 8080, loadedCfg.Metrics.Port)
+	assert.Equal(t, 8083, loadedCfg.HealthCheck.Port)
+	assert.Equal(t, "postgres", loadedCfg.Database.Dialect)
+	assert.Equal(t, "https://api.integration.openshift.com", loadedCfg.OCM.BaseURL)
+}
+
+// TestServeConfig_Precedence tests command-line flags override environment variables
+func TestServeConfig_Precedence(t *testing.T) {
+	// Set environment variables
+	os.Setenv("HYPERFLEET_SERVER_PORT", "9999")
+	defer os.Unsetenv("HYPERFLEET_SERVER_PORT")
+
+	// Create full config file
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: precedence-test
+  version: 1.0.0
+server:
+  host: localhost
+  port: 7000
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Create flag set with command-line value
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewServeConfig()
+
+	// Create viper and configure flags
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{
+		"--config=" + configFile,
+		"--server-port=8888",
+	})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := LoadServeConfig(v, flags)
+	require.NoError(t, err)
+
+	// CLI should win
+	assert.Equal(t, 8888, loadedCfg.Server.Port, "CLI flag should override env and file")
+}
+
+// TestServeConfig_EnvVarOverridesFile tests environment variable precedence
+func TestServeConfig_EnvVarOverridesFile(t *testing.T) {
+	// Create full config file
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: file-name
+  version: 1.0.0
+server:
+  host: localhost
+  port: 8000
+metrics:
+  host: localhost
+  port: 7070
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Set environment variable
+	os.Setenv("HYPERFLEET_METRICS_PORT", "9090")
+	defer os.Unsetenv("HYPERFLEET_METRICS_PORT")
+
+	// Create flag set
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := NewServeConfig()
+
+	// Create viper and configure flags
+	v := NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
+
+	// Load config
+	loadedCfg, err := LoadServeConfig(v, flags)
+	require.NoError(t, err)
+
+	// Env var should override file
+	assert.Equal(t, 9090, loadedCfg.Metrics.Port, "Environment variable should override config file")
+}
+
+// TestServeConfig_ToApplicationConfig tests conversion to ApplicationConfig
+func TestServeConfig_ToApplicationConfig(t *testing.T) {
+	// Create serve config
+	cfg := NewServeConfig()
+	cfg.App.Name = "conversion-test"
+	cfg.Server.Port = 8000
+	cfg.Metrics.Port = 8080
+	cfg.HealthCheck.Port = 8083
+	cfg.Database.Dialect = "postgres"
+	cfg.OCM.BaseURL = "https://api.test.com"
+
+	// Convert to ApplicationConfig
+	appConfig := cfg.ToApplicationConfig()
+
+	// Verify conversion
+	assert.Equal(t, "conversion-test", appConfig.App.Name)
+	assert.Equal(t, 8000, appConfig.Server.Port)
+	assert.Equal(t, 8080, appConfig.Metrics.Port)
+	assert.Equal(t, 8083, appConfig.HealthCheck.Port)
+	assert.Equal(t, "postgres", appConfig.Database.Dialect)
+	assert.Equal(t, "https://api.test.com", appConfig.OCM.BaseURL)
+
+	// Verify they share the same underlying config objects
+	assert.Same(t, cfg.App, appConfig.App)
+	assert.Same(t, cfg.Server, appConfig.Server)
+	assert.Same(t, cfg.Metrics, appConfig.Metrics)
+	assert.Same(t, cfg.HealthCheck, appConfig.HealthCheck)
+	assert.Same(t, cfg.Database, appConfig.Database)
+	assert.Same(t, cfg.OCM, appConfig.OCM)
+}
+
+// TestServeConfig_DisplayConfig tests that DisplayConfig doesn't panic
+func TestServeConfig_DisplayConfig(t *testing.T) {
+	// Create full config
+	cfg := NewServeConfig()
+	cfg.App.Name = "display-test"
+	cfg.Server.Port = 8000
+	cfg.Database.Password = "secret-password"
+	cfg.OCM.ClientSecret = "secret-token"
+
+	// Should not panic
+	assert.NotPanics(t, func() {
+		cfg.DisplayConfig()
+	})
+}
+
+// TestServeConfig_GetJSONConfig tests JSON output with redaction
+func TestServeConfig_GetJSONConfig(t *testing.T) {
+	// Create full config with sensitive data
+	cfg := NewServeConfig()
+	cfg.App.Name = "json-test"
+	cfg.Server.Port = 8000
+	cfg.Database.Password = "super-secret-password"
+	cfg.OCM.ClientSecret = "super-secret-token"
+
+	// Get JSON
+	jsonStr, err := cfg.GetJSONConfig()
+	require.NoError(t, err)
+
+	// Verify JSON contains app name but sensitive data is redacted
+	assert.Contains(t, jsonStr, "json-test")
+	assert.NotContains(t, jsonStr, "super-secret-password")
+	assert.NotContains(t, jsonStr, "super-secret-token")
+	assert.Contains(t, jsonStr, "***") // Redacted values
+}
+
+// TestServeConfig_SameFileAsMapping tests that same config file works for serve
+func TestServeConfig_SameFileAsMigrate(t *testing.T) {
+	// Create full config file that would be used by both commands
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: shared-config
+  version: 1.0.0
+server:
+  host: localhost
+  port: 8000
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+  host: localhost
+  port: 5432
+  name: hyperfleet
+  username: hyperfleet
+  password: secret
+ocm:
+  base_url: https://api.integration.openshift.com
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Load as ServeConfig
+	serveFlags := pflag.NewFlagSet("serve", pflag.ContinueOnError)
+	serveCfg := NewServeConfig()
+	serveViper := NewCommandConfig()
+	serveCfg.ConfigureFlags(serveViper, serveFlags)
+	err = serveFlags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
+	serveConfig, err := LoadServeConfig(serveViper, serveFlags)
+	require.NoError(t, err)
+
+	// Load as MigrateConfig
+	migrateFlags := pflag.NewFlagSet("migrate", pflag.ContinueOnError)
+	migrateCfg := NewMigrateConfig()
+	migrateViper := NewCommandConfig()
+	migrateCfg.ConfigureFlags(migrateViper, migrateFlags)
+	err = migrateFlags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
+	migrateConfig, err := LoadMigrateConfig(migrateViper, migrateFlags)
+	require.NoError(t, err)
+
+	// Verify both loaded the same shared values (App and Database)
+	assert.Equal(t, "shared-config", serveConfig.App.Name)
+	assert.Equal(t, "shared-config", migrateConfig.App.Name)
+	assert.Equal(t, "postgres", serveConfig.Database.Dialect)
+	assert.Equal(t, "postgres", migrateConfig.Database.Dialect)
+
+	// Serve has all sections loaded
+	assert.NotNil(t, serveConfig.Server)
+	assert.NotNil(t, serveConfig.Metrics)
+	assert.NotNil(t, serveConfig.HealthCheck)
+	assert.NotNil(t, serveConfig.OCM)
+
+	// Migrate only has App and Database (other sections are ignored from config file)
+	assert.NotNil(t, migrateConfig.App)
+	assert.NotNil(t, migrateConfig.Database)
+}
diff --git a/pkg/config/server.go b/pkg/config/server.go
index 9258fd81..4803c5cb 100755
--- a/pkg/config/server.go
+++ b/pkg/config/server.go
@@ -1,58 +1,111 @@
 package config
 
 import (
+	"fmt"
 	"time"
 
 	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
 )
 
 type ServerConfig struct {
-	Hostname      string        `json:"hostname"`
-	BindAddress   string        `json:"bind_address"`
-	ReadTimeout   time.Duration `json:"read_timeout"`
-	WriteTimeout  time.Duration `json:"write_timeout"`
-	HTTPSCertFile string        `json:"https_cert_file"`
-	HTTPSKeyFile  string        `json:"https_key_file"`
-	EnableHTTPS   bool          `json:"enable_https"`
-	EnableJWT     bool          `json:"enable_jwt"`
-	EnableAuthz   bool          `json:"enable_authz"`
-	JwkCertFile   string        `json:"jwk_cert_file"`
-	JwkCertURL    string        `json:"jwk_cert_url"`
-	ACLFile       string        `json:"acl_file"`
+	Hostname      string        `mapstructure:"hostname" json:"hostname" validate:""`
+	Host          string        `mapstructure:"host" json:"host" validate:"required"`
+	Port          int           `mapstructure:"port" json:"port" validate:"required,min=1,max=65535"`
+	Timeout       TimeoutConfig `mapstructure:"timeout" json:"timeout"`
+	HTTPS         HTTPSConfig   `mapstructure:"https" json:"https"`
+	Auth          AuthConfig    `mapstructure:"auth" json:"auth"`
+
+	// Legacy field for backward compatibility (combines host:port)
+	BindAddress string `mapstructure:"bind_address" json:"bind_address,omitempty" validate:""`
+}
+
+type TimeoutConfig struct {
+	Read  time.Duration `mapstructure:"read" json:"read" validate:""`
+	Write time.Duration `mapstructure:"write" json:"write" validate:""`
+}
+
+type HTTPSConfig struct {
+	Enabled  bool   `mapstructure:"enabled" json:"enabled"`
+	CertFile string `mapstructure:"cert_file" json:"cert_file"`
+	KeyFile  string `mapstructure:"key_file" json:"key_file"`
+}
+
+type AuthConfig struct {
+	JWT   JWTConfig   `mapstructure:"jwt" json:"jwt"`
+	Authz AuthzConfig `mapstructure:"authz" json:"authz"`
+}
+
+type JWTConfig struct {
+	Enabled  bool   `mapstructure:"enabled" json:"enabled"`
+	CertFile string `mapstructure:"cert_file" json:"cert_file"`
+	CertURL  string `mapstructure:"cert_url" json:"cert_url"`
+}
+
+type AuthzConfig struct {
+	Enabled bool   `mapstructure:"enabled" json:"enabled"`
+	ACLFile string `mapstructure:"acl_file" json:"acl_file"`
 }
 
 func NewServerConfig() *ServerConfig {
 	return &ServerConfig{
-		Hostname:      "",
-		BindAddress:   "localhost:8000",
-		ReadTimeout:   5 * time.Second,
-		WriteTimeout:  30 * time.Second,
-		EnableHTTPS:   false,
-		EnableJWT:     true,
-		EnableAuthz:   true,
-		JwkCertFile:   "",
-		JwkCertURL:    "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/certs",
-		ACLFile:       "",
-		HTTPSCertFile: "",
-		HTTPSKeyFile:  "",
+		Hostname: "",
+		Host:     "localhost",
+		Port:     8000,
+		Timeout: TimeoutConfig{
+			Read:  5 * time.Second,
+			Write: 30 * time.Second,
+		},
+		HTTPS: HTTPSConfig{
+			Enabled:  false,
+			CertFile: "",
+			KeyFile:  "",
+		},
+		Auth: AuthConfig{
+			JWT: JWTConfig{
+				Enabled:  true,
+				CertFile: "",
+				CertURL:  "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/certs",
+			},
+			Authz: AuthzConfig{
+				Enabled: true,
+				ACLFile: "",
+			},
+		},
+		BindAddress: "localhost:8000",
 	}
 }
 
-func (s *ServerConfig) AddFlags(fs *pflag.FlagSet) {
-	fs.StringVar(&s.BindAddress, "api-server-bindaddress", s.BindAddress, "API server bind adddress")
-	fs.StringVar(&s.Hostname, "api-server-hostname", s.Hostname, "Server's public hostname")
-	fs.DurationVar(&s.ReadTimeout, "http-read-timeout", s.ReadTimeout, "HTTP server read timeout")
-	fs.DurationVar(&s.WriteTimeout, "http-write-timeout", s.WriteTimeout, "HTTP server write timeout")
-	fs.StringVar(&s.HTTPSCertFile, "https-cert-file", s.HTTPSCertFile, "The path to the tls.crt file.")
-	fs.StringVar(&s.HTTPSKeyFile, "https-key-file", s.HTTPSKeyFile, "The path to the tls.key file.")
-	fs.BoolVar(&s.EnableHTTPS, "enable-https", s.EnableHTTPS, "Enable HTTPS rather than HTTP")
-	fs.BoolVar(&s.EnableJWT, "enable-jwt", s.EnableJWT, "Enable JWT authentication validation")
-	fs.BoolVar(&s.EnableAuthz, "enable-authz", s.EnableAuthz, "Enable Authorization on endpoints, should only be disabled for debug")
-	fs.StringVar(&s.JwkCertFile, "jwk-cert-file", s.JwkCertFile, "JWK Certificate file")
-	fs.StringVar(&s.JwkCertURL, "jwk-cert-url", s.JwkCertURL, "JWK Certificate URL")
-	fs.StringVar(&s.ACLFile, "acl-file", s.ACLFile, "Access control list file")
+// defineAndBindFlags defines & binds flags to viper keys in a single pass
+func (s *ServerConfig) defineAndBindFlags(v *viper.Viper, fs *pflag.FlagSet) {
+	// Server flags
+	defineAndBindStringFlag(v, fs, "server.host", "server-host", "", s.Host, "Server bind host")
+	defineAndBindIntFlag(v, fs, "server.port", "server-port", "p", s.Port, "Server bind port")
+	defineAndBindStringFlag(v, fs, "server.hostname", "server-hostname", "", s.Hostname, "Server's public hostname")
+
+	// Timeout flags
+	defineAndBindDurationFlag(v, fs, "server.timeout.read", "server-timeout-read", "", s.Timeout.Read, "HTTP server read timeout")
+	defineAndBindDurationFlag(v, fs, "server.timeout.write", "server-timeout-write", "", s.Timeout.Write, "HTTP server write timeout")
+
+	// HTTPS flags
+	defineAndBindBoolFlag(v, fs, "server.https.enabled", "server-https-enabled", "", s.HTTPS.Enabled, "Enable HTTPS rather than HTTP")
+	defineAndBindStringFlag(v, fs, "server.https.cert_file", "server-https-cert-file", "", s.HTTPS.CertFile, "Path to the tls.crt file")
+	defineAndBindStringFlag(v, fs, "server.https.key_file", "server-https-key-file", "", s.HTTPS.KeyFile, "Path to the tls.key file")
+
+	// JWT flags
+	defineAndBindBoolFlag(v, fs, "server.auth.jwt.enabled", "auth-jwt-enabled", "", s.Auth.JWT.Enabled, "Enable JWT authentication validation")
+	defineAndBindStringFlag(v, fs, "server.auth.jwt.cert_file", "auth-jwt-cert-file", "", s.Auth.JWT.CertFile, "JWK Certificate file")
+	defineAndBindStringFlag(v, fs, "server.auth.jwt.cert_url", "auth-jwt-cert-url", "", s.Auth.JWT.CertURL, "JWK Certificate URL")
+
+	// Authz flags
+	defineAndBindBoolFlag(v, fs, "server.auth.authz.enabled", "auth-authz-enabled", "", s.Auth.Authz.Enabled, "Enable Authorization on endpoints")
+	defineAndBindStringFlag(v, fs, "server.auth.authz.acl_file", "auth-authz-acl-file", "", s.Auth.Authz.ACLFile, "Access control list file")
 }
 
-func (s *ServerConfig) ReadFiles() error {
-	return nil
+// GetBindAddress returns the bind address in host:port format
+func (s *ServerConfig) GetBindAddress() string {
+	if s.BindAddress != "" {
+		return s.BindAddress
+	}
+	return fmt.Sprintf("%s:%d", s.Host, s.Port)
 }
diff --git a/pkg/handlers/config.go b/pkg/handlers/config.go
new file mode 100644
index 00000000..ce17f016
--- /dev/null
+++ b/pkg/handlers/config.go
@@ -0,0 +1,60 @@
+/*
+Copyright (c) 2018 Red Hat, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package handlers
+
+import (
+	"net/http"
+
+	"github.com/openshift-hyperfleet/hyperfleet-api/pkg/api"
+	"github.com/openshift-hyperfleet/hyperfleet-api/pkg/config"
+	"github.com/openshift-hyperfleet/hyperfleet-api/pkg/logger"
+)
+
+type configHandler struct {
+	config *config.ApplicationConfig
+}
+
+func NewConfigHandler(cfg *config.ApplicationConfig) *configHandler {
+	return &configHandler{
+		config: cfg,
+	}
+}
+
+// Get sends the merged configuration response with sensitive values redacted.
+func (h configHandler) Get(w http.ResponseWriter, r *http.Request) {
+	// Set the content type:
+	w.Header().Set("Content-Type", "application/json")
+
+	// Get redacted configuration JSON
+	jsonConfig, err := h.config.GetJSONConfig()
+	if err != nil {
+		log := logger.NewOCMLogger(r.Context())
+		log.Extra("endpoint", r.URL.Path).Extra("method", r.Method).Extra("error", err.Error()).
+			Error("Failed to generate configuration JSON")
+		api.SendPanic(w, r)
+		return
+	}
+
+	// Send the response:
+	_, err = w.Write([]byte(jsonConfig))
+	if err != nil {
+		log := logger.NewOCMLogger(r.Context())
+		log.Extra("endpoint", r.URL.Path).Extra("method", r.Method).Extra("error", err.Error()).
+			Error("Failed to send configuration response body")
+		return
+	}
+}
diff --git a/pkg/handlers/config_test.go b/pkg/handlers/config_test.go
new file mode 100644
index 00000000..daf24b1e
--- /dev/null
+++ b/pkg/handlers/config_test.go
@@ -0,0 +1,207 @@
+package handlers
+
+import (
+	"encoding/json"
+	"math/rand"
+	"net/http"
+	"net/http/httptest"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/spf13/pflag"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/openshift-hyperfleet/hyperfleet-api/pkg/config"
+)
+
+var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
+
+func randSeq(n int) string {
+	b := make([]rune, n)
+	for i := range b {
+		b[i] = letters[rand.Intn(len(letters))]
+	}
+	return string(b)
+}
+
+// TestConfigEndpoint_ReturnsExpectedValues tests that the /config endpoint returns correct values
+func TestConfigEndpoint_ReturnsExpectedValues(t *testing.T) {
+	// Create a config with known values
+	cfg := config.NewApplicationConfig()
+	cfg.App.Name = "test-app"
+	cfg.App.Version = "5.0.0"
+	cfg.Server.Port = 9000
+	cfg.Database.Host = "db.example.com"
+	cfg.Database.Password = randSeq(10)
+	cfg.OCM.ClientSecret = randSeq(10)
+	cfg.Server.Auth.JWT.CertURL = "https://example.com/certs" // Should be redacted (contains 'cert')
+
+	// Create handler
+	handler := NewConfigHandler(cfg)
+
+	// Create test request
+	req := httptest.NewRequest("GET", "/api/hyperfleet/config", nil)
+	w := httptest.NewRecorder()
+
+	// Call handler
+	handler.Get(w, req)
+
+	// Verify response
+	assert.Equal(t, http.StatusOK, w.Code, "Should return 200 OK")
+	assert.Equal(t, "application/json", w.Header().Get("Content-Type"), "Should return JSON")
+
+	// Parse response body
+	var response config.ApplicationConfig
+	err := json.Unmarshal(w.Body.Bytes(), &response)
+	require.NoError(t, err, "Response should be valid JSON")
+
+	// Verify non-sensitive values are present
+	assert.Equal(t, "test-app", response.App.Name, "App name should be present")
+	assert.Equal(t, "5.0.0", response.App.Version, "App version should be present")
+	assert.Equal(t, 9000, response.Server.Port, "Server port should be present")
+	assert.Equal(t, "db.example.com", response.Database.Host, "Database host should be present")
+
+	// Verify sensitive values are redacted
+	assert.Equal(t, "***", response.Database.Password, "Database password should be redacted")
+	assert.Equal(t, "***", response.OCM.ClientSecret, "OCM client secret should be redacted")
+	assert.Equal(t, "***", response.Server.Auth.JWT.CertURL, "JWT cert URL should be redacted")
+}
+
+// TestConfigEndpoint_SensitiveFieldsRedacted tests various sensitive field patterns
+func TestConfigEndpoint_SensitiveFieldsRedacted(t *testing.T) {
+	cfg := config.NewApplicationConfig()
+	cfg.Database.Password = randSeq(10)
+	cfg.OCM.ClientSecret = randSeq(10)
+	cfg.OCM.SelfToken = "token-789"
+	cfg.Server.Auth.JWT.CertFile = "/path/to/cert.pem"
+	cfg.Server.Auth.JWT.CertURL = "https://certs.example.com"
+	cfg.Server.HTTPS.CertFile = "/path/to/server-cert.pem"
+	cfg.Server.HTTPS.KeyFile = "/path/to/server-key.pem"
+	cfg.Database.RootCertFile = "/path/to/root-cert.pem"
+
+	// Create handler
+	handler := NewConfigHandler(cfg)
+
+	// Create test request
+	req := httptest.NewRequest("GET", "/api/hyperfleet/config", nil)
+	w := httptest.NewRecorder()
+
+	// Call handler
+	handler.Get(w, req)
+
+	// Parse response
+	var response config.ApplicationConfig
+	err := json.Unmarshal(w.Body.Bytes(), &response)
+	require.NoError(t, err)
+
+	// All sensitive fields should be redacted
+	assert.Equal(t, "***", response.Database.Password, "Password should be redacted")
+	assert.Equal(t, "***", response.OCM.ClientSecret, "ClientSecret should be redacted")
+	assert.Equal(t, "***", response.OCM.SelfToken, "SelfToken should be redacted")
+	assert.Equal(t, "***", response.Server.Auth.JWT.CertFile, "CertFile should be redacted")
+	assert.Equal(t, "***", response.Server.Auth.JWT.CertURL, "CertURL should be redacted")
+	assert.Equal(t, "***", response.Server.HTTPS.CertFile, "HTTPS CertFile should be redacted")
+	assert.Equal(t, "***", response.Server.HTTPS.KeyFile, "KeyFile should be redacted")
+	assert.Equal(t, "***", response.Database.RootCertFile, "RootCertFile should be redacted")
+}
+
+// TestConfigEndpoint_EmptySensitiveFieldsNotRedacted tests that empty sensitive fields remain empty
+func TestConfigEndpoint_EmptySensitiveFieldsNotRedacted(t *testing.T) {
+	cfg := config.NewApplicationConfig()
+	// Leave sensitive fields empty
+
+	// Create handler
+	handler := NewConfigHandler(cfg)
+
+	// Create test request
+	req := httptest.NewRequest("GET", "/api/hyperfleet/config", nil)
+	w := httptest.NewRecorder()
+
+	// Call handler
+	handler.Get(w, req)
+
+	// Parse response
+	var response config.ApplicationConfig
+	err := json.Unmarshal(w.Body.Bytes(), &response)
+	require.NoError(t, err)
+
+	// Empty fields should remain empty, not "***"
+	assert.Empty(t, response.Database.Password, "Empty password should remain empty")
+	assert.Empty(t, response.OCM.ClientSecret, "Empty client secret should remain empty")
+}
+
+// TestConfigEndpoint_IntegrationWithLoadConfig tests the full integration
+func TestConfigEndpoint_IntegrationWithLoadConfig(t *testing.T) {
+	// Create temporary config file
+	tmpDir := t.TempDir()
+	configFile := filepath.Join(tmpDir, "config.yaml")
+
+	configYAML := `
+app:
+  name: integration-test
+  version: 6.0.0
+server:
+  host: file-host
+  port: 7777
+metrics:
+  host: localhost
+  port: 8080
+health_check:
+  host: localhost
+  port: 8083
+database:
+  dialect: postgres
+  password: secret123
+  username: testuser
+ocm:
+  base_url: https://api.integration.openshift.com
+  client_secret: ocmsecret
+`
+	err := os.WriteFile(configFile, []byte(configYAML), 0o644)
+	require.NoError(t, err)
+
+	// Override with environment variable
+	os.Setenv("HYPERFLEET_SERVER_PORT", "8888")
+	defer os.Unsetenv("HYPERFLEET_SERVER_PORT")
+
+	// Create flag set
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	cfg := config.NewApplicationConfig()
+
+	// Create viper and configure flags
+	v := config.NewCommandConfig()
+	cfg.ConfigureFlags(v, flags)
+
+	err = flags.Parse([]string{"--config=" + configFile})
+	require.NoError(t, err)
+
+	// Load config with full precedence
+	loadedCfg, err := config.LoadConfig(v, flags)
+	require.NoError(t, err)
+
+	// Create handler with loaded config
+	handler := NewConfigHandler(loadedCfg)
+
+	// Create test request
+	req := httptest.NewRequest("GET", "/api/hyperfleet/config", nil)
+	w := httptest.NewRecorder()
+
+	// Call handler
+	handler.Get(w, req)
+
+	// Parse response
+	var response config.ApplicationConfig
+	err = json.Unmarshal(w.Body.Bytes(), &response)
+	require.NoError(t, err)
+
+	// Verify precedence in endpoint response
+	assert.Equal(t, "file-host", response.Server.Host, "Should get hostname from file")
+	assert.Equal(t, 8888, response.Server.Port, "Should get port from env var (overrides file)")
+	assert.Equal(t, "testuser", response.Database.Username, "Should get username from file")
+
+	// Verify redaction in endpoint response
+	assert.Equal(t, "***", response.Database.Password, "Password should be redacted in endpoint")
+	assert.Equal(t, "***", response.OCM.ClientSecret, "Client secret should be redacted in endpoint")
+}
diff --git a/test/helper.go b/test/helper.go
index f79b9fae..c9fadc30 100755
--- a/test/helper.go
+++ b/test/helper.go
@@ -73,19 +73,32 @@ func NewHelper(t *testing.T) *Helper {
 			fmt.Println("Unable to read JWT keys - this may affect tests that make authenticated server requests")
 		}
 
-		env := environments.Environment()
-		err = env.AddFlags(pflag.CommandLine)
-		if err != nil {
-			glog.Fatalf("Unable to add environment flags: %s", err.Error())
-		}
+		// Create config
+		serveConfig := config.NewServeConfig()
+
+		// Allow custom log level
 		if logLevel := os.Getenv("LOGLEVEL"); logLevel != "" {
 			glog.Infof("Using custom loglevel: %s", logLevel)
-			// Intentionally ignore error from Set — acceptable for tests
-			_ = pflag.CommandLine.Set("-v", logLevel)
+			_ = pflag.CommandLine.Set("v", logLevel)
 		}
+
+		// Create viper and configure flags (tests need full serve config)
+		v := config.NewCommandConfig()
+		serveConfig.ConfigureFlags(v, pflag.CommandLine)
+
 		pflag.Parse()
 
-		err = env.Initialize()
+		// Load serve config (tests run full server environment)
+		loadedServeConfig, err := config.LoadServeConfig(v, pflag.CommandLine)
+		if err != nil {
+			glog.Fatalf("Failed to load configuration: %v", err)
+		}
+
+		// Convert to ApplicationConfig for environment initialization
+		loadedConfig := loadedServeConfig.ToApplicationConfig()
+
+		// Initialize environment with config
+		err = environments.Environment().Initialize(loadedConfig)
 		if err != nil {
 			glog.Fatalf("Unable to initialize testing environment: %s", err.Error())
 		}
@@ -97,7 +110,7 @@ func NewHelper(t *testing.T) *Helper {
 			JWTCA:         jwtCA,
 		}
 
-		// Start JWK certificate mock server for testing
+		// Start JWK certificate mock server and other test infrastructure
 		jwkMockTeardown := helper.StartJWKCertServerMock()
 		helper.teardowns = []func() error{
 			helper.CleanDB,
@@ -133,7 +146,7 @@ func (helper *Helper) Teardown() {
 
 func (helper *Helper) startAPIServer() {
 	// Configure JWK certificate URL for API server
-	helper.Env().Config.Server.JwkCertURL = jwkURL
+	helper.Env().Config.Server.Auth.JWT.CertURL = jwkURL
 	helper.APIServer = server.NewAPIServer()
 	listener, err := helper.APIServer.Listen()
 	if err != nil {
@@ -193,23 +206,29 @@ func (helper *Helper) RestartMetricsServer() {
 
 func (helper *Helper) Reset() {
 	glog.Infof("Reseting testing environment")
-	env := environments.Environment()
-	// Reset the configuration
-	env.Config = config.NewApplicationConfig()
-
-	// Re-read command-line configuration into a NEW flagset
-	// This new flag set ensures we don't hit conflicts defining the same flag twice
-	// Also on reset, we don't care to be re-defining 'v' and other glog flags
-	flagset := pflag.NewFlagSet(helper.NewID(), pflag.ContinueOnError)
-	if err := env.AddFlags(flagset); err != nil {
-		glog.Fatalf("Unable to add environment flags on Reset: %s", err.Error())
-	}
+
+	// Create new config
+	appConfig := config.NewApplicationConfig()
+
+	// Create viper and configure flags
+	v := config.NewCommandConfig()
+	appConfig.ConfigureFlags(v, pflag.CommandLine)
+
 	pflag.Parse()
 
-	err := env.Initialize()
+	// Load config
+	loadedConfig, err := config.LoadConfig(v, pflag.CommandLine)
+	if err != nil {
+		glog.Fatalf("Failed to load configuration: %v", err)
+	}
+
+	// Reinitialize environment
+	env := environments.Environment()
+	err = env.Initialize(loadedConfig)
 	if err != nil {
 		glog.Fatalf("Unable to reset testing environment: %s", err.Error())
 	}
+
 	helper.AppConfig = env.Config
 	helper.RestartServer()
 }
@@ -227,7 +246,7 @@ func (helper *Helper) NewUUID() string {
 
 func (helper *Helper) RestURL(path string) string {
 	protocol := "http"
-	if helper.AppConfig.Server.EnableHTTPS {
+	if helper.AppConfig.Server.Auth.Authz.Enabled {
 		protocol = "https"
 	}
 	return fmt.Sprintf("%s://%s/api/hyperfleet/v1%s", protocol, helper.AppConfig.Server.BindAddress, path)
@@ -245,7 +264,7 @@ func (helper *Helper) NewApiClient() *openapi.APIClient {
 	config := openapi.NewConfiguration()
 	// Override the server URL to use the local test server
 	protocol := "http"
-	if helper.AppConfig.Server.EnableHTTPS {
+	if helper.AppConfig.Server.Auth.Authz.Enabled {
 		protocol = "https"
 	}
 	config.Host = helper.AppConfig.Server.BindAddress
@@ -290,7 +309,7 @@ func (helper *Helper) NewAuthenticatedContext(account *amv1.Account) context.Con
 
 func (helper *Helper) StartJWKCertServerMock() (teardown func() error) {
 	jwkURL, teardown = mocks.NewJWKCertServerMock(helper.T, helper.JWTCA, jwkKID, jwkAlg)
-	helper.Env().Config.Server.JwkCertURL = jwkURL
+	helper.Env().Config.Server.Auth.JWT.CertURL = jwkURL
 	return teardown
 }
 
diff --git a/test/integration/metadata_test.go b/test/integration/metadata_test.go
index 96779b62..1ba3739f 100755
--- a/test/integration/metadata_test.go
+++ b/test/integration/metadata_test.go
@@ -34,7 +34,7 @@ func TestMetadataGet(t *testing.T) {
 
 	// Build the metadata URL (metadata endpoint is at /api/hyperfleet, not /api/hyperfleet/v1)
 	protocol := "http"
-	if h.AppConfig.Server.EnableHTTPS {
+	if h.AppConfig.Server.Auth.Authz.Enabled {
 		protocol = "https"
 	}
 	metadataURL := fmt.Sprintf("%s://%s/api/hyperfleet", protocol, h.AppConfig.Server.BindAddress)
diff --git a/test/integration/openapi_test.go b/test/integration/openapi_test.go
index c2cf7406..97cd5df9 100755
--- a/test/integration/openapi_test.go
+++ b/test/integration/openapi_test.go
@@ -32,7 +32,7 @@ func TestOpenAPIGet(t *testing.T) {
 	h, _ := test.RegisterIntegration(t)
 
 	protocol := "http"
-	if h.AppConfig.Server.EnableHTTPS {
+	if h.AppConfig.Server.Auth.Authz.Enabled {
 		protocol = "https"
 	}
 	openAPIURL := fmt.Sprintf("%s://%s/api/hyperfleet/v1/openapi", protocol, h.AppConfig.Server.BindAddress)
@@ -72,7 +72,7 @@ func TestOpenAPIUIGet(t *testing.T) {
 	h, _ := test.RegisterIntegration(t)
 
 	protocol := "http"
-	if h.AppConfig.Server.EnableHTTPS {
+	if h.AppConfig.Server.Auth.Authz.Enabled {
 		protocol = "https"
 	}
 	openAPIUIURL := fmt.Sprintf("%s://%s/api/hyperfleet/v1/openapi.html", protocol, h.AppConfig.Server.BindAddress)
