GitHub
08/09/2026, 4:25 PMservice_config database table, seeded from the YAML file on first boot and exposed via read-only API endpoints.
Problem
Every service boots by loading a YAML file into config.ServiceParameters. The structured sections — logger, carver, SAML, OIDC, JWT, metrics, TLS, debug — are never persisted to the DB and can't be inspected from the UI. Only a handful of scalar runtime knobs live in setting_values.
Changes
New package pkg/serviceconfig
• ServiceConfig GORM model: one row per (service, section, environment) with a unique composite index. Value holds the JSON-encoded YAML section; Source tracks yaml vs `db`; Editable gates future writes (all false in phase 1).
• SectionRegistry declaratively maps which sections belong to which service (12 for TLS, 11 for API). Connection/secret sections (db, redis) are flagged non-editable.
• Seed uses ON CONFLICT DO NOTHING for create-if-missing semantics — idempotent and never overwrites a DB-edited row.
• 10 tests covering idempotency, no-overwrite of DB-edited rows, JSON round-trip, service-specific sections, per-environment isolation, and input validation.
Seeding wired into startup
• cmd/tls/main.go and cmd/api/main.go call Seed right after loadingSettings, persisting the YAML-loaded config into service_config.
Read-only API handlers (cmd/api/handlers/service_config.go)
| Method | Path | Description |
| ------ | ------------------------------------------ | -------------------------------- |
| GET | /api/v1/service-config | All sections across all services |
| GET | /api/v1/service-config/{service} | All sections for one service |
| GET | /api/v1/service-config/{service}/{section} | One section |
All require AdminLevel permissions, validate service/section against the registry, audit-log reads, and return 404 for missing sections. Wired through HandlersApi.ServiceConfig + WithServiceConfig.
Design notes
• No risk to existing settings: new table, new package, no changes to SettingValue or loadingSettings.
• No risk to runtime: phase 1 is read-only mirror; services still consume ServiceParameters from YAML exactly as before.
• Security: connection sections (db, redis) are flagged editable=false and never writable through the API.
• Auditable: every read hits `AuditLog.Visit`; future writes will hit AuditLog.SettingsAction.
Validation
• go build ./...
• go test ./... — all packages pass, including 10 new tests in pkg/serviceconfig
• golangci-lint run ./pkg/serviceconfig/... — 0 issues
• gofmt clean on all new/modified files
Evolution path
| Phase | What changes |
| ----------- | ------------------------------------------------------------------------------------------------- |
| 1 (this PR) | Seed from YAML → DB. API read endpoints. YAML still live source of truth. |
| 2 | editable sections can be PUT from the frontend. DB value takes precedence. |
| 3 | Services read config from DB at startup; YAML becomes an override/bootstrap. |
| 4 | YAML shrinks to db + redis + bootstrap. Logger, carver, auth, metrics, TLS, debug all DB-managed. |
jmpsec/osctrlGitHub
08/09/2026, 4:51 PM