Documentation
¶
Overview ¶
Package app is wowapi's composition root helpers. Product binaries (cmd/api, cmd/worker, cmd/migrate in the product repo) construct an App, register their modules, and run it.
Phase 0 ships registration + whole-graph validation (duplicate names, invalid names, unknown dependencies, dependency cycles) and the deterministic registration order. Kernel construction and the RunAPI/RunWorker/RunMigrate helpers land in Phases 1–2.
Module registration context (D-0006/D-0040; blueprint 06 §2).
The context is capability-scoped: modules receive registries and services, never raw pools or global config. Accessors grow per phase alongside the kernel capability each delivers. Phase 5 wires the full set the current kernel supports (routes, permissions, resource types, authz, tx, migrations, seeds, openapi, health, inter-module ports) and injects the shared registries modules register into during boot.
Startup/shutdown lifecycle skeleton (phase-plan Phase 1).
RunHooks provides orderly start-then-stop sequencing for named components (HTTP server, outbox relay, …) wired in as Hook values. Signal wiring (SIGINT/SIGTERM) belongs to the process main via signal.NotifyContext; RunHooks stays testable with a plain context.
Real server construction arrives in Phases 2–3; this skeleton establishes the lifecycle contract that those phases plug into.
Process config narrowing (blueprint 12 §7).
One loaded config.Framework, three narrowed views: each process binary receives only the sections it actually needs. Unused sections are never wired, so a worker process has no HTTP section and a migrate process has no module namespaces. Each view carries a Fingerprint method so ops can detect per-section drift across processes on shared config sections.
Index ¶
- func Readiness(b *Booted, fingerprint config.Fingerprint, extra map[string]httpx.HealthCheck) *httpx.Health
- func RunHooks(ctx context.Context, logger *slog.Logger, stopTimeout time.Duration, ...) error
- func StartWorker(ctx context.Context, b *Booted, opts WorkerConfigOpts) error
- type APIConfig
- type App
- type BootOption
- type Booted
- type Hook
- type MigrateConfig
- type MigrateDB
- type RecurringJob
- type RuntimeDB
- type WorkerConfig
- type WorkerConfigOpts
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Readiness ¶
func Readiness(b *Booted, fingerprint config.Fingerprint, extra map[string]httpx.HealthCheck) *httpx.Health
Readiness assembles the /readyz aggregator from the booted app: every module's registered readiness check (ctx.Health) plus the framework checks the caller supplies as `extra` (typically a DB ping and a "migrations current" probe, which the composition root wires because it owns the pool). The redacted config fingerprint is reported in the response for drift correlation. Mount h.Liveness() at /healthz and h.Readiness() at /readyz in the product's api and worker mains (blueprint 07 §9).
func RunHooks ¶
func RunHooks(ctx context.Context, logger *slog.Logger, stopTimeout time.Duration, hooks ...Hook) error
RunHooks starts hooks in order and blocks until ctx is cancelled or a Start returns an error. It then stops the successfully-started hooks in reverse order, each bounded by stopTimeout.
Errors are handled as follows:
- A Start error aborts the remaining starts and triggers immediate shutdown.
- Stop errors are all collected (never short-circuited) and joined with any Start error via errors.Join.
- If every Start and Stop succeeds, RunHooks returns nil.
func StartWorker ¶
func StartWorker(ctx context.Context, b *Booted, opts WorkerConfigOpts) error
StartWorker runs the background worker process for a booted app: the outbox relay (dispatches events to subscribed handlers) and the job runner (executes enqueued jobs with retries/DLQ). It blocks until ctx is cancelled, then drains in-flight work within ShutdownDrain and returns. Requires the kernel's Platform pool (cross-tenant kernel work) — a worker/migrate posture, not api-only.
Signal wiring (SIGINT/SIGTERM) belongs to the process main via signal.NotifyContext; StartWorker stays testable with a plain context.
Types ¶
type APIConfig ¶
type APIConfig struct {
Environment config.Env `json:"environment"`
HTTP config.HTTP `json:"http"`
DB RuntimeDB `json:"db"`
Log config.Log `json:"log"`
Modules config.Namespaces `json:"modules"`
}
APIConfig is the narrowed view handed to cmd/api: HTTP server settings, runtime database, logging, and module namespaces. It deliberately omits the migration DSN and provider credentials the API process does not use (blueprint 12 §7).
func NewAPIConfig ¶
NewAPIConfig constructs the api process view from a loaded Framework and the full module namespace map. The runtime DSN is required here — DSNs are validated at narrowing, not by config tags, so DB-less tooling loads stay possible (D-0021).
func (APIConfig) Fingerprint ¶
func (c APIConfig) Fingerprint() (config.Fingerprint, error)
Fingerprint returns the SHA-256 of this view's canonical redacted JSON rendering. Shared sections fingerprinted separately let ops detect api-vs-worker drift on a half-rolled deploy (blueprint 12 §7).
func (APIConfig) SectionFingerprints ¶
func (c APIConfig) SectionFingerprints() (map[string]config.Fingerprint, error)
SectionFingerprints returns one fingerprint per top-level section so processes sharing a section (api/worker both carry log + modules) can be compared for config drift (blueprint 12 §7); comparing whole-view fingerprints across differently-shaped views is meaningless.
type App ¶
type App struct {
// contains filtered or unexported fields
}
App holds the registered module set. Construct with New, add modules with Register, then call Validate before starting anything.
func (*App) Boot ¶
func (a *App) Boot(ctx context.Context, k *kernel.Kernel, namespaces config.Namespaces, opts ...BootOption) (*Booted, error)
Boot runs the module lifecycle up to (not including) Start: it registers every module against a capability-scoped context built from k — in dependency order so a module's ports are available to its dependents — then validates the whole graph and the shared registries (blueprint 06 §2). Boot fails, before anything serves, on: a module graph error (dup/unknown/cycle), a registration error, a route whose permission is not registered, a duplicate/invalid permission or resource type, or a seed ownership/parse error.
namespaces is the loaded product config's module.* subtree; each module sees only its own slice via Context.Config().
func (*App) Ordered ¶
Ordered returns modules in dependency order (dependencies first, ties broken alphabetically for determinism), validating the graph on the way.
type BootOption ¶
type BootOption func(*bootOpts)
BootOption tunes Boot. See SkipRLSEnforcementCheck.
func SkipRLSEnforcementCheck ¶
func SkipRLSEnforcementCheck() BootOption
SkipRLSEnforcementCheck disables the boot-time assertion that the runtime pool cannot bypass row-level security. Use it ONLY for a process that does not serve tenant traffic and runs as a privileged role by design — namely the migrate command, which boots the app merely to COLLECT module migration sets and connects with DDL (app_migrate/superuser) credentials. api/worker processes must NOT use it: their tenant-serving runtime pool must be a non-privileged app_rt role, and the default check keeps that safe-by-default (finding M3).
type Booted ¶
type Booted struct {
Kernel *kernel.Kernel
Router *httpx.Router
Events *outbox.HandlerRegistry // event subscriptions (drives the relay)
Jobs *jobs.Registry // job kinds (drives the worker pools)
OpenAPI map[string][]byte
Health map[string]func(context.Context) error
Migrations map[string]fs.FS
Seeds seeds.Bundle // merged catalog seeds, ready for SeedSync
Recurring []RecurringJob // module-registered recurring jobs (run by the worker scheduler)
}
Booted is the result of App.Boot: everything the process layer needs to start serving (or to migrate/seed). Modules have registered; the whole graph and registries are validated; nothing has started yet.
type Hook ¶
type Hook struct {
// Name is used in log messages; should be short and unique within a run.
Name string
// Start launches background work and must return promptly (not block for
// the component's lifetime). The ctx is the run context; components should
// respect its cancellation on their own internal paths.
Start func(ctx context.Context) error
// Stop performs a graceful shutdown. nil means nothing to stop. Stop
// receives a fresh context bounded by the stopTimeout, independent of
// the (already-cancelled) run context.
Stop func(ctx context.Context) error
}
Hook is one startable/stoppable component: an HTTP server, outbox relay, background sweeper, or any other process-lifetime service.
type MigrateConfig ¶
type MigrateConfig struct {
Environment config.Env `json:"environment"`
DB MigrateDB `json:"db_migrate"`
Log config.Log `json:"log"`
}
MigrateConfig is the narrowed view handed to cmd/migrate: the migration DSN and logging only. Module namespaces, the HTTP section, and the runtime DSN are deliberately absent (blueprint 12 §7).
func NewMigrateConfig ¶
func NewMigrateConfig(f config.Framework) (MigrateConfig, error)
NewMigrateConfig constructs the migrate process view from a loaded Framework. Requires the migration DSN (D-0021).
func (MigrateConfig) Fingerprint ¶
func (c MigrateConfig) Fingerprint() (config.Fingerprint, error)
Fingerprint returns the SHA-256 of this view's canonical redacted JSON rendering.
func (MigrateConfig) SectionFingerprints ¶
func (c MigrateConfig) SectionFingerprints() (map[string]config.Fingerprint, error)
SectionFingerprints returns one fingerprint per top-level section so processes sharing a section (api/worker both carry log + modules) can be compared for config drift (blueprint 12 §7); comparing whole-view fingerprints across differently-shaped views is meaningless.
type MigrateDB ¶
MigrateDB is the migrate slice of config.DB: the app_migrate DSN plus the pool knobs. The runtime DSN is deliberately absent (blueprint 12 §7).
type RecurringJob ¶
type RecurringJob struct {
Name string
Every time.Duration
Run func(ctx context.Context, db database.TenantDB) error
}
RecurringJob is a leader-safe per-tenant recurring job a module registered via module.Context.RecurringJob (roadmap E5/CA-5). StartWorker registers each on the scheduler; Run is invoked once per active tenant every Every, in that tenant's transaction.
type RuntimeDB ¶
type RuntimeDB struct {
DSN config.Secret `json:"dsn"`
config.Pool // flattens: max_conns, query_timeout, …
}
RuntimeDB is the runtime slice of config.DB handed to api/worker: the app_rt DSN plus the embedded pool knobs. The migration DSN is deliberately absent — runtime processes never hold app_migrate credentials (12 §7). Embedding config.Pool (not re-listing its fields) means new pool knobs reach every view without touching the narrowing code (ARCH-17).
type WorkerConfig ¶
type WorkerConfig struct {
Environment config.Env `json:"environment"`
DB RuntimeDB `json:"db"`
Log config.Log `json:"log"`
Modules config.Namespaces `json:"modules"`
}
WorkerConfig is the narrowed view handed to cmd/worker: runtime database, logging, and module namespaces. The HTTP server section is deliberately absent — a worker does not bind a port (blueprint 12 §7).
func NewWorkerConfig ¶
func NewWorkerConfig(f config.Framework, mods config.Namespaces) (WorkerConfig, error)
NewWorkerConfig constructs the worker process view from a loaded Framework and the full module namespace map. Requires the runtime DSN (D-0021).
func (WorkerConfig) Fingerprint ¶
func (c WorkerConfig) Fingerprint() (config.Fingerprint, error)
Fingerprint returns the SHA-256 of this view's canonical redacted JSON rendering.
func (WorkerConfig) SectionFingerprints ¶
func (c WorkerConfig) SectionFingerprints() (map[string]config.Fingerprint, error)
SectionFingerprints returns one fingerprint per top-level section so processes sharing a section (api/worker both carry log + modules) can be compared for config drift (blueprint 12 §7); comparing whole-view fingerprints across differently-shaped views is meaningless.
type WorkerConfigOpts ¶
type WorkerConfigOpts struct {
RelayBatch int
RelayPoll time.Duration
JobPoll time.Duration
JobPoolSize int
ShutdownDrain time.Duration
// Scheduler (leader-safe kernel maintenance sweeps). Zero values use defaults.
SchedulerPoll time.Duration // how often to check for due tasks (default 30s)
SLAInterval time.Duration // workflow SLA sweep interval (default 1m)
IdempotencyInterval time.Duration // idempotency-key expiry sweep interval (default 1h)
DLQDepthInterval time.Duration // dlq_depth gauge refresh interval (default 1m)
AuditAnchorInterval time.Duration // audit-chain anchor-export interval (default 1h)
NotifySendInterval time.Duration // notify send/retry poll interval (default 1m)
WebhookRetryInterval time.Duration // webhook retry + inbound poll interval (default 1m)
}
WorkerConfigOpts tunes the worker loops.