The companion repository that holds additional packages used by kosatnkn/catalyst.
Every package follows the same shape, a top-level contracts.go (or similarly named file) defines an interface, and one or more sub-packages provide concrete adapters that implement it. This keeps consuming services decoupled from any specific implementation (Postgres, zerolog, viper, etc.) so adapters can be swapped without touching business logic.
github.com/kosatnkn/catalyst-pkgs
├── config # configuration parsing (env vars + YAML file)
├── infra
│ └── readiness # component readiness / health tracking
│ └── basic # in-memory implementation
├── persistence # database adapter contract
│ └── postgres # Postgres implementation
└── telemetry
└── log # structured logging contract
└── loggerjson # zerolog-based JSON implementation
Parses application configuration into a caller-supplied struct, merging values from three sources with the following precedence:
- Environment variables prefixed with
Settings.Prefix - A
config.yamlfile located inSettings.Dir - Default values supplied via
Settings.Defaults
Built on top of spf13/viper, so the target struct must carry mapstructure tags for field mapping. Dot-concatenated keys (e.g. app.metrics.enabled) address nested struct fields for defaults and env binding, and the squash mapstructure option is supported to flatten an embedded struct's fields into its parent's key namespace.
After parsing, the struct is validated using go-playground/validator — validation tags (validate:"min=80,max=65535", etc.) on the struct are honored automatically.
Key files
settings.go— theSettingsstruct (Dir,Prefix,Defaults) that configures parsing behavior.parse.go—Parse(config any, s Settings) (any, error), plus the reflection-based helper that derives env-var binding keys frommapstructuretags.validate.go— runs struct validation and aggregates validator errors witherrors.Join.
Defines the Readiness interface used to track whether individual service components (database, cache, message broker, etc.) are healthy, and to expose an overall readiness state for the service (commonly surfaced via a /ready HTTP endpoint).
type Readiness interface {
SetReadiness(component string, ready bool)
Ready() bool
RegisterCheckerFn(name string, checker func() (bool, error))
Snapshot() map[string]bool
String() string
}A concurrency-safe, in-memory implementation of Readiness.
- Tracks component state in a
map[string]boolguarded by async.RWMutex. RegisterCheckerFnassociates a component with a health-check callback and starts it in a "not ready" state.- When a component flips from ready → not ready, a background goroutine (
recover) polls the registered checker function every 5 seconds (cancellable via context) until it reports healthy again, at which point readiness is restored automatically. - Depends on
telemetry/log(log.LoggerBasic) to log warnings/info during state transitions and recovery.
Defines the DatabaseAdapter interface that any database adapter in the ecosystem must implement, decoupling business logic from a specific database driver.
type DatabaseAdapter interface {
Identity() string
Ping() error
Query(ctx context.Context, query string, params map[string]any) ([]map[string]any, error)
QueryBulk(ctx context.Context, query string, params []map[string]any) ([]map[string]any, error)
WrapInTx(ctx context.Context, fn func(ctx context.Context) (any, error)) (any, error)
IsReadinessFail(err error) bool
Destruct() error
}It also defines the context key used to carry an in-flight transaction (DatabaseTxKey) and standard result-map keys (DatabaseAffectedRows, DatabaseLastInsertID).
A Postgres implementation of DatabaseAdapter, built on database/sql and the lib/pq driver.
Notable behavior:
- Named parameters — queries can use
?name(optionally suffixed#arrto indicate array binding viapq.Array) instead of positional$1, $2, ...placeholders - Statement-type detection — inspect the query (with
-- #select/-- #insertoverride comments, or regex-based detection, including CTEs starting withWITH) to decide whether to treat the query specifically as aSELECTorINSERT. - Transactions —
WrapInTxattaches a*sql.Txto the context (or reuses one already present, enabling safe nesting) and commits/rolls back based on whether the wrapped function returns an error. - Bulk operations —
QueryBulkruns the same statement for a slice of parameter sets, intended for batched INSERT/UPDATE/DELETE (SELECT is rejected). - Readiness integration —
IsReadinessFailclassifies an error as an infrastructure/connectivity failure (context deadline, closed connection, or common transient network error strings), suitable for feeding intoinfra/readiness's checker callbacks. config.godefines the PostgresConfigstruct (host,port,database,user,password,poolsize,check) with YAML/mapstructure tags for use with theconfigpackage.
Defines the logging contracts used across services.
type LoggerBasic interface {
Error(ctx context.Context, message string)
Debug(ctx context.Context, message string)
Info(ctx context.Context, message string)
Warn(ctx context.Context, message string)
}
type Logger interface {
AddTraceID(ctx context.Context, id string) context.Context
AppendTracePoint(ctx context.Context, point string) context.Context
LoggerBasic
}Logger extends LoggerBasic with context-based trace propagation: AddTraceID attaches a request/trace identifier to the context, and AppendTracePoint builds up a --separated path of trace points (e.g. as a request moves through layers) — both readable later by the logging implementation. Log level constants (LevelError, LevelWarn, LevelDebug, LevelInfo) are also defined here.
A structured JSON logging implementation of Logger, built on rs/zerolog.
Config.Levelselects the minimum log level (ERROR,WARN,DEBUG,INFO), validated against a known set at construction time.- Every log call automatically enriches the log event with the trace
idandtracepath pulled from context (if present), via the internalwithCtxValshelper. - Output is written as JSON to
stdoutwith timestamps enabled.