refactor(config): mandatory app-config rows seeded in DB; rename to session.setup_timeout
All registry keys must exist as rows in the config table: main seeds missing keys with their defaults at startup, LoadApp fails fast on a missing key, and the code-side fallback const/helper for the onboarding setup timeout is gone -- the value rides in SessionConfig.SetupTimeout. The key is renamed session.idle_timeout -> session.setup_timeout, and the /config page's 'overridden' now means 'differs from the default'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,13 +19,13 @@ type AppKey struct {
|
||||
// KeySessionDuration is the session cookie lifetime, in integer hours.
|
||||
const (
|
||||
KeySessionDuration = "session.duration"
|
||||
// KeySessionIdleTimeout bounds an *onboarding Garmin session* (the
|
||||
// ephemeral, pre-account login attempt), not the login cookie --
|
||||
// KeySessionSetupTimeout bounds an *onboarding Garmin setup session*
|
||||
// (the ephemeral, pre-account login attempt), not the login cookie --
|
||||
// session.duration is how long a signed-in user stays signed in
|
||||
// (hours); session.idle_timeout is how long an unfinished setup
|
||||
// (hours); session.setup_timeout is how long an unfinished setup
|
||||
// attempt survives untouched before its subprocess is torn down
|
||||
// (minutes).
|
||||
KeySessionIdleTimeout = "session.idle_timeout"
|
||||
KeySessionSetupTimeout = "session.setup_timeout"
|
||||
)
|
||||
|
||||
var appRegistry = []AppKey{
|
||||
@@ -36,9 +36,9 @@ var appRegistry = []AppKey{
|
||||
Validate: validatePositiveInt,
|
||||
},
|
||||
{
|
||||
Key: KeySessionIdleTimeout,
|
||||
Key: KeySessionSetupTimeout,
|
||||
Default: "15",
|
||||
Description: "Idle timeout in minutes for an unfinished onboarding Garmin session",
|
||||
Description: "Idle timeout in minutes for an unfinished onboarding Garmin setup session",
|
||||
Validate: validatePositiveInt,
|
||||
},
|
||||
}
|
||||
@@ -69,32 +69,35 @@ func ValidateAppValue(key, value string) error {
|
||||
return fmt.Errorf("unknown configuration key %q", key)
|
||||
}
|
||||
|
||||
// AppConfig is the typed result of merging DB overrides over registry
|
||||
// defaults.
|
||||
// AppConfig is the typed application configuration, built from the DB's
|
||||
// config rows.
|
||||
type AppConfig struct {
|
||||
SessionDuration time.Duration
|
||||
SetupSessionIdleTimeout time.Duration
|
||||
SessionDuration time.Duration
|
||||
SetupTimeout time.Duration
|
||||
}
|
||||
|
||||
// LoadApp merges overrides (store.ConfigValues' map) over defaults. Pure
|
||||
// -- it takes the raw map instead of a *store.DB so this package needs no
|
||||
// store dependency and the merge logic tests without a database. A bad
|
||||
// stored value fails fast, same posture as LoadEnv() for env vars.
|
||||
func LoadApp(overrides map[string]string) (AppConfig, error) {
|
||||
merged := map[string]string{}
|
||||
for _, k := range appRegistry {
|
||||
merged[k.Key] = k.Default
|
||||
}
|
||||
for key, value := range overrides {
|
||||
// LoadApp builds the typed AppConfig from the config table's rows. Every
|
||||
// registry key is mandatory: main seeds missing keys with their defaults
|
||||
// at startup (see cmd/geniusrund), so a missing key here means that
|
||||
// seeding didn't run -- fail fast, same posture as LoadEnv() for env
|
||||
// vars, and likewise for an unknown or invalid stored value. Pure -- it
|
||||
// takes the raw map instead of a *store.DB so this package needs no store
|
||||
// dependency and the logic tests without a database.
|
||||
func LoadApp(values map[string]string) (AppConfig, error) {
|
||||
for key, value := range values {
|
||||
if err := ValidateAppValue(key, value); err != nil {
|
||||
return AppConfig{}, fmt.Errorf("app config: %w", err)
|
||||
}
|
||||
merged[key] = value
|
||||
}
|
||||
hours, _ := strconv.Atoi(merged[KeySessionDuration])
|
||||
idleMinutes, _ := strconv.Atoi(merged[KeySessionIdleTimeout])
|
||||
for _, k := range appRegistry {
|
||||
if _, ok := values[k.Key]; !ok {
|
||||
return AppConfig{}, fmt.Errorf("app config: missing key %q (defaults are seeded into the DB at startup)", k.Key)
|
||||
}
|
||||
}
|
||||
hours, _ := strconv.Atoi(values[KeySessionDuration])
|
||||
setupMinutes, _ := strconv.Atoi(values[KeySessionSetupTimeout])
|
||||
return AppConfig{
|
||||
SessionDuration: time.Duration(hours) * time.Hour,
|
||||
SetupSessionIdleTimeout: time.Duration(idleMinutes) * time.Minute,
|
||||
SessionDuration: time.Duration(hours) * time.Hour,
|
||||
SetupTimeout: time.Duration(setupMinutes) * time.Minute,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user