Files
core/CHANGELOG.md

109 lines
6.2 KiB
Markdown
Raw Normal View History

feat(core): initial implementation — launcher, logz, xerrors, valid Introduces `code.nochebuena.dev/einherjar/core` — the foundational implementation module of the Einherjar framework. Provides four sub-packages that together cover every service's baseline needs: lifecycle management, structured logging, typed errors, and struct validation. - launcher: Launcher interface — three-phase managed lifecycle (OnInit → BeforeStart hooks → OnStart → OS signal wait → OnStop in reverse). Accepts lifecycle.Component and logging.Logger from contracts. Prints an ASCII art banner at startup (EINHERJAR_BANNER=off to suppress). Banner includes core version via runtime/debug.ReadBuildInfo() and a loaded-module list for every registered component that implements observability.Identifiable. Config struct with EINHERJAR_COMPONENT_STOP_TIMEOUT env tag (caarlos0/env syntax, default 15s). - logz: Logger implementation backed by log/slog. Returns contracts/logging.Logger. Detects errs.CodedError and errs.ContextualError (from contracts/errs) to enrich log records automatically — replaces the private duck-typed bridge from micro-lib. Context helpers: WithRequestID, WithField, WithFields, GetRequestID. Config struct with EINHERJAR_LOG_LEVEL (default INFO) and EINHERJAR_LOG_JSON (default false) env tags (caarlos0/env syntax); programmatic-only fields StaticArgs and Writer carry no tags. - xerrors: Typed error codes with context enrichment. Complete gRPC canonical set (16 codes) plus HTTP 410 ErrGone. Adds ErrOutOfRange, ErrAborted, ErrDataLoss over micro-lib. One convenience constructor per code. *Err declares compile-time satisfaction of errs.CodedError and errs.ContextualError. - valid: Struct validation wrapping go-playground/validator/v10. Validator interface + MessageProvider interface with full built-in tag coverage (~150 tags) in both DefaultMessages (English) and SpanishMessages (Spanish). Backend fully hidden; returns *xerrors.Err with ErrInvalidInput or ErrInternal. FieldLevel interface abstracts the backend's field-level access for custom validators. WithCustomValidator registers custom validation tags at construction time; OverrideProvider chains a tag→handler map with a fallback MessageProvider for custom tag messages without re-implementing built-ins. Compliance test enforces CT-6 (at most one exported TypeSpec per file via AST) and verifies behavioural correctness of all four sub-packages, including custom validator registration and OverrideProvider composition. Compile-time var _ assertions prove interface satisfaction. docs: ADR-001 (core module composition), ADR-002 (logz contracts/errs adoption), ADR-003 (Config naming convention and caarlos0/env tag standard)
2026-05-29 15:45:12 +00:00
# Changelog — einherjar/core
All notable changes to this module are documented here.
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
This module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
---
## [1.0.0] — 2026-05-28
### Added
#### `launcher`
- `Launcher` interface — `Append`, `BeforeStart`, `Run`, `Shutdown`
- `New(logger logging.Logger, opts ...Options) Launcher` — constructs the lifecycle
orchestrator; takes `contracts/logging.Logger` (not the concrete `logz` type)
- `Hook` type (`func() error`) — assembly-phase callback registered via `BeforeStart`
- `Config` struct — `ComponentStopTimeout time.Duration` with `env:"EINHERJAR_COMPONENT_STOP_TIMEOUT" envDefault:"15s"` (`caarlos0/env` syntax)
- Startup banner — printed to stdout before any slog output; disabled via
`EINHERJAR_BANNER=off` or `EINHERJAR_BANNER=false`
- Components accepted as `lifecycle.Component` from `contracts` — not a locally
defined interface; any type that satisfies `contracts/lifecycle.Component` is
directly compatible
#### `logz`
- `Config` struct — `Level slog.Level`, `JSON bool`, `StaticArgs []any`, `Writer io.Writer`
- `Level` and `JSON` carry `env` and `envDefault` tags (`caarlos0/env` syntax); `StaticArgs` and `Writer` are programmatic-only fields without tags
- Env vars: `EINHERJAR_LOG_LEVEL` (default `INFO`), `EINHERJAR_LOG_JSON` (default `false`)
- `New(cfg Config) logging.Logger` — returns `contracts/logging.Logger`; the
concrete `slogLogger` struct is unexported
- Error enrichment — when the error passed to `Logger.Error` satisfies
`errs.CodedError` or `errs.ContextualError` (from `contracts/errs`), the
corresponding `error_code` field and context key-value pairs are automatically
appended to the log record; this replaces the private duck-typed bridge used in
micro-lib's `logz`
- Context helpers — `WithRequestID`, `GetRequestID`, `WithField`, `WithFields`
- `Logger.WithContext(ctx)` — extracts `request_id` and extra fields from context
and attaches them to every subsequent log record
#### `xerrors`
- `Code` type (stable string wire values, gRPC-aligned)
- **16 error code constants** — complete gRPC canonical set plus `ErrGone` (HTTP 410)
- New over micro-lib: `ErrOutOfRange` (gRPC OUT_OF_RANGE, HTTP 400),
`ErrAborted` (gRPC ABORTED, HTTP 409), `ErrDataLoss` (gRPC DATA_LOSS, HTTP 500)
- `Code.Description()` — human-readable description for each code
- `Err` struct — `code`, `message`, `err` (cause), `fields` (context), `platformCode`
- Base constructors: `New(code, message)`, `Wrap(code, message, err)`
- **16 convenience constructors** (one per code): `InvalidInput`, `OutOfRange`,
`Unauthorized`, `PermissionDenied`, `NotFound`, `AlreadyExists`, `Aborted`,
`Gone`, `PreconditionFailed`, `RateLimited`, `Cancelled`, `Internal`, `DataLoss`,
`NotImplemented`, `Unavailable`, `DeadlineExceeded`
- Builder methods: `WithContext`, `WithError`, `WithPlatformCode`
- Accessors: `Code()`, `Message()`, `Fields()`, `PlatformCode()`, `Detailed()`
- Standard interfaces: `error`, `Unwrap`, `json.Marshaler`
- Compile-time assertions: `var _ errs.CodedError = (*Err)(nil)` and
`var _ errs.ContextualError = (*Err)(nil)` — formalises the duck-type bridge
from micro-lib into an explicit, verifiable contract
#### `valid`
- `Validator` interface — `Struct(v any) error`
- `New(opts ...Option) Validator` — constructs a validator backed by
`go-playground/validator/v10` (backend is hidden; never exposed in the public API)
- `MessageProvider` interface — `Message(field, tag, param string) string`
- `DefaultMessages` — built-in English message provider
- `SpanishMessages` — opt-in Spanish message provider
- `Option` type and `WithMessageProvider(mp MessageProvider) Option`
- `FieldLevel` interface — passed to custom validator functions; exposes `Field() reflect.Value`, `Param() string`, `FieldName() string`; go-playground backend never visible
- `WithCustomValidator(tag string, fn func(FieldLevel) bool) Option` — registers a custom validation tag at construction time; panics on empty or conflicting tag
- `OverrideProvider(handlers map[string]func(field, param string) string, base MessageProvider) MessageProvider` — composes a tag→message handler map with a fallback; use for custom tag messages without re-implementing built-ins
- **Full built-in tag coverage** in `DefaultMessages` and `SpanishMessages` — all go-playground/validator tags have specific messages (fields, network, strings, format, comparisons, other; ~150 tags total)
- Field names in error context prefer the json struct tag, falling back to the Go
field name
- Error codes: `ErrInvalidInput` for constraint failures, `ErrInternal` for
non-struct arguments — both returned as `*xerrors.Err`
### Design Notes
1. **Contracts as the source of truth.** `launcher` accepts `lifecycle.Component`
and `logging.Logger` from `contracts`. It does not define its own lifecycle
interface. Any type that satisfies the contracts interface is directly compatible —
no adapters needed.
2. **Duck typing replaced by explicit interfaces.** micro-lib's `logz` detected
enrichable errors via private `errorWithCode`/`errorWithContext` interfaces.
`core/logz` detects them via `contracts/errs.CodedError` and `contracts/errs.ContextualError`.
The decoupling (logz does not import xerrors) is preserved; the contract is now
visible. See [ADR-002](docs/adr/ADR-002-logz-contracts-errs.md).
3. **Complete gRPC error code set.** micro-lib's `xerrors` had 13 codes. `core/xerrors`
adds the three missing gRPC codes (`OUT_OF_RANGE`, `ABORTED`, `DATA_LOSS`) and
provides a named convenience constructor for every code — `New()` and `Wrap()` are
reserved for edge cases.
4. **One module, four sub-packages.** The consolidation eliminates four-way version
coordination for a set of packages that always ship and upgrade together.
See [ADR-001](docs/adr/ADR-001-core-module-composition.md).
5. **Startup banner.** The launcher prints an ASCII art banner to stdout before any
structured log output. It is disabled via `EINHERJAR_BANNER=off`, not via code
changes, so production deployments can suppress it without modifying the service.
---
[1.0.0]: https://code.nochebuena.dev/einherjar/core/releases/tag/v1.0.0