Package-level declarations
Types
How the access attributes are stamped over the histories: by the built-in subscription wow.access, in stamps of a bounded number of streams, remembering the last attributes of a bounded number of aggregates; and by the access walk of each aggregate type, a page of aggregates at a time, at a bounded rate and a bounded share of the time.
An aggregate type's ClickHouse settings: wow.aggregates.[<context>.<aggregate>].clickhouse.*.
An aggregate type's settings. tenant fixes the tenant of every aggregate of the type: its commands and state reads are in that tenant whoever the caller is (me.ahoo.wow.spi.tenant.TenantPolicy). idGenerator names the me.ahoo.wow.spi.id.AggregateIdGenerator bean that gives the type's new ids, or a generator an me.ahoo.wow.spi.id.AggregateIdGeneratorSource bean finds by that name (CosId's, with wow-cosid); the type's ids come from the wowAggregateIdGenerator bean otherwise. A type the node does not serve, or a name nothing gives a generator of, is refused at startup.
An aggregate type's queries (wow.aggregates.[<context>.<aggregate>].query.*).
An aggregate type's snapshot queries: store, the snapshot store they read, one of the type's snapshot.stores, its primary when not set: an Elasticsearch store that searches the states, say, while the commands and the state reads stay on the primary.
One aggregate type's store of its log or of its snapshots: one of wow.stores.
Creates the schemas of the backends the node opened, where they are missing, before anything uses them.
How a subscription answers backpressure: a downstream that is up but asks to be called later (wow.command.busy, wow.wait.timeout, wow.query.busy, a 429 with Retry-After). The entry is retried, then its aggregate parks; it never pauses the partition. Meanwhile each backpressure halves the handlings the partition runs at once, and each success raises them again.
One calling service: the commands it may call, names or patterns (AddItem, shop.cart.*, wow.lifecycle.*): without them, the domain commands alone; a system command (wow.*: the lifecycle, the snapshot rebuild, the schedules) only when an entry naming wow. lists it; an entry naming a domain command narrows the domain commands to those listed. The reads narrow the models it may read on the internal port's read routes, by context.aggregate.model (ordering.order.snapshot, .events, .state) or a dataset's context.dataset, patterns with *: without them, every model the node serves.
How the nodes of a service share the partitions of each context's log, and forward commands to their owners.
The wow.* keys of the environment that no property names: Spring binds what it knows and ignores the rest, so wow.cluster.forward-timout would be a silent no-op. A key is known when a property of the configuration metadata on the class path (METADATA, the host's and any module's) is the key or holds it (a map or list property, such as wow.aggregates), or when it is under the prefix of another @ConfigurationProperties bean of the application that no metadata describes (its owned prefixes), whose keys this check cannot tell. Names compare as Spring's relaxed binding does (laneCapacity is lane-capacity); only property sources that list their names are read.
The bounded contexts a node serves: wow.contexts.include and wow.contexts.exclude (ContextsProperties) over the domain modules on the class path, their binding indexes (ModelProvider).
The bounded contexts the node serves among the domain modules on the class path (ContextSelection), all of them by default. A name that is no context on the class path is refused at startup.
Wires CoSec into the host when the application has wow-cosec and CoSec's WebFlux module: the host wires its optional integrations as it wires Kafka, and wow-cosec keeps the Spring-free part, the resolver, the authorizers and the route map. It reads wow.cosec.* once, through WowProperties.cosec, the keys' one reader and one default.
CoSec's settings (wow-cosec), which the host's CoSec configuration reads from here alone, their one reader and their one default: they have metadata, and a key of wow.cosec that none of these is refuses the startup (ConfigurationKeys) instead of being ignored, so a mistyped Authorizer.enabled cannot leave the authorizer that allows all in place.
The Manifest's command and service routes as the route map CoSec's pipeline reads (CoSecActions.routes), where CoSec decides the requests itself (cosec.pipeline.mode enforce, its default): a command is <context>:<command> on <aggregate>/<id>, a service route <context>:<route> on route/<route>, the names CoSecCommandAuthorizer and CoSecServiceRouteAuthorizer decide them by. It comes after the host's configuration, which defines the Manifest, and before CoSec's pipeline, whose route map file it takes the place of; an application that maps routes of its own declares its RouteMap. Experimental as wow-cosec is.
The application's database connection pool, from its properties alone: when spring.datasource.url is set, HikariCP is on the class path, the application has no DataSource bean and no Spring Boot JDBC (spring-boot-jdbc, whose own auto-configuration then makes it), the host makes a HikariDataSource of spring.datasource.url, .username, .password and .driver-class-name, with HikariCP's settings under spring.datasource.hikari.* as Boot reads them; closed with the context. Its pool opens at the first connection. The backend then follows the DataSource bean as it follows the application's (wow.backend); without the URL the host connects to no database.
A resolver that answers through another one, decorated, narrowing or completing its callers (a service's reserved scopes, its sign-in): the request's credentials are still decorated's, so what the host declares of them, the OpenAPI security schemes (WowOpenApiSecurity.of), is decorated's too.
The host's callers in a development profile (a profile of wow.dev-profiles), when the application has no CallerResolver and CoSec is off: the caller the request's identity headers (DevelopmentHeaders) name, so a service runs and is tried out at every caller level without an identity provider. Any client sets these headers, so the host wires it only when a development profile is active: outside one, it never does.
Whether the node runs for development: a profile of wow.dev-profiles (dev, local, test, demo) is active, or its internal port binds a loopback address alone. It is the one exemption the host's safeguards share, so a laptop starts as it is and a deployment cannot: wow.backend=auto falls back to memory, the public port serves without a CallerResolver bean, and, in a development profile alone (profiles), takes its callers from request headers. reason says why, null outside development.
wow.peer.discovery=dns, the default: a peer service's nodes are the targets of the DNS SRV records name-template names after it, _internal._tcp.{service}-cluster.{namespace}.svc by default, each http://<target>:<port>. Kubernetes publishes one such record per pod behind a headless Service, whose targets resolve to the pods' IPs, the addresses their nodes advertise. A peer's {namespace} is its namespaces.<service>, else the node's own: namespace, else that of the pod's service account, from namespaceFile.
The events query backend of the node: the bindings of each aggregate type's events backend and storage facts, none for a type no backend serves (its events are then not queried), and the store its queries run on, null for the application's own backend. For a store whose events queries manage indexes (me.ahoo.wow.query.store.EventQueries), how it prepares a type's log and manages the indexes of its access attributes at startup. It is not itself QueryBindings, so that it is never taken for the application's snapshot bindings bean.
How the node executes commands.
Waits, between the public server's graceful shutdown and its stop, for the thread of that shutdown to end, at most timeout: a workaround of a race in Spring Boot 4.1.1 (spring-boot-reactor-netty, and 3.5.x before it), to remove once the host builds on a Spring Boot that fixes it (below).
The node's health in Spring Boot Actuator, when the application has Actuator's health support (spring-boot-starter-actuator), unless wow.health.enabled=false (HealthProperties):
The node's command executors.
Whether the node is stuck, so a restart helps; a storage outage never fails it.
The node's share of each lease group's partitions.
The node's health (me.ahoo.wow.runtime.health.NodeHealth): with Spring Boot Actuator on the class path, the contributor wow (every component), and wowReadiness and wowLiveness, which the host adds to Actuator's readiness and liveness groups (/actuator/health/readiness, /actuator/health/liveness) unless the application configures their members itself. The thresholds are conservative: a probe that fails too soon takes nodes out of service, or restarts them, for what a retry would have absorbed.
The node's event logs, as its own calls and a probe of their heads see them.
The node's subscriptions, never a reason to take it out of service.
The topics of other contexts the node reads.
The backends of the node: the BackendFactory the me.ahoo.wow.runtime.node.ServiceNode opens each context's stores from, remembering what it opened, so that the state reads find a context's stores and the backend lifecycle (WowLifecycles.BACKENDS_PHASE) creates their schemas before the node starts.
The node's dataset bindings: the application's, or a dataset backend's (provided); null when no backend serves datasets. Closed with the context, they close a dataset backend's bindings that hold resources of their own (a client it opened), never the application's.
The node whose write pressure the stores' query bounds adapt to (HostQueryBulkheads.pressureOf), taken once the context has built every singleton. The bounds cannot take the node as a parameter: the node is built with the gate its state rebuilds replay under (me.ahoo.wow.runtime.state.ReplayGate), which is built over them.
The HTTP edge: its routes and its error answers.
The node's topics in its JVM, for trying a service out without Kafka (DX gap G27), when wow.transport selects them (TransportSelection.MEMORY: memory, or auto in development without a configured transport): one InMemoryTopics of wow.log.partitions partitions, each keeping its last wow.memory.topic-retention messages, unless the application has one of its own, as wow-kafka's beans give them on Kafka:
Serves the internal port from before the node starts until after it stops; once the port is bound, tells bound the port it is bound at, so a node whose port the system chose learns its address (ServiceNode.bind).
The SRV lookup of the JDK's DNS provider (JNDI), with the search domains of the node's resolver: a name without a trailing dot is tried under each search domain of resolvConf and as given, the first that has records answering, as given first when it has at least the resolver's ndots dots (options ndots:n, 1 by default; Kubernetes gives its pods 5); a name with one is absolute. resolvConf is read once; it is absent on a developer's machine, where a name is tried as given alone.
The in-memory provider's settings, wow.memory.*, as each provider has its group (wow.kafka.*, wow.mongo.*).
The application's MongoDB client, from its properties alone: when wow-mongo is on the class path, spring.mongodb.uri is set, the application has no MongoClient bean and no Spring Boot MongoDB (spring-boot-mongodb, whose own auto-configuration then makes it), the host makes a MongoClient of the URI; closed with the context. The MongoDB stores then open over it, in the database their database option names.
The pool gauge of the MongoDB stores (MongoPoolGauge), when the application has wow-mongo: added to the MongoClient the host makes (MongoClientAutoConfiguration) or Spring Boot makes (through its settings customizer), so the stores bound their queries by the client's pool and read their write pressure from it. An application that builds its own client adds the gauge itself (MongoPoolGauge.applyTo).
Who this node is: the service it belongs to, its node id and the address of its internal port, null while the port is not bound yet when the system chooses it (wow.internal.port=0): the node then learns it as host and the bound port (ServiceNode.bind).
The node's one sampler (NodeSampler), every wow.node.sample-interval, its parked entries counted up to wow.node.max-parked: the node's health, its gauges and the operator's read of its subscriptions all read its samples, so the ledgers and the logs' heads are read once per interval, whoever reports them.
The standby of node as the internal port's operator routes see it (wow.node.standby).
Tracing and metrics (wow-observability), active when the application has wow-observability on its classpath, unless wow.observability.enabled=false (ObservabilityProperties).
Observability's configuration, wow.observability.*, read when wow-observability is on the classpath (ObservabilityAutoConfiguration).
The operator's side of the parked entries: the webhook told when an entry parks, and the failure ledger published to the ops context. Their routes are the edge's, wow.http.ops.enabled.
The automatic retries of parked entries over minutes and hours; per subscription, wow.subscriptions.[<context>.<name>].parked.* overrides them.
One subscription's retry spec of its parked entries, each setting not given being wow.subscription.parked's.
How the node calls its peers over HTTP, whichever peer: one HTTP client, these settings.
How a problem a retry may get past is retried (me.ahoo.wow.client.RetryPolicy): a 429, a command's problem that keeps the request id, or a connection that could not be made.
One peer context: its internal port's base url (service mode), http://host:port of an address in its internal network, never its public port, which refuses calls; its public routes' base publicUrl (user mode); the mode it is called in, over wow.peer.mode; where its contract comes from (jar, or manifest for a peer called by its Manifest alone); and its timeout, over wow.peer.timeout.
The Sinks the node's providers opened, each its subscriptions' factory; closed with the context.
Publishing the failure ledger to the ops context, so one console sees the parked entries of every service: each entry goes to the parked aggregate of the ops context through its command topic, which needs a topic transport.
The query plane (–), active when wow-query is on the classpath (wow-http brings it) and wow.query.enabled is not off. Over the node's Manifest it builds:
The application's beans a QueryEngine is built of: each it may give, or not.
The events queries of a store or an aggregate type: unpinned, whether one that names no aggregate runs, over the store's and wow.query.events.unpinned.
Manages the indexes of every aggregate type in types at startup, after the backends' schemas exist (BackendsLifecycle) and before the node starts: each aggregate's storage is prepared, its query model compiled from catalog, and its Manifest's x-wow-index planned and managed by backend as the ddl of the store it is on says (wow.stores.<store>.ddl, else wow.ddl). A key the model cannot index fails the start, and so does an index that validate finds missing or invalid: a query it would serve scans the whole collection.
The query plane's configuration, wow.query.*, read by QueryAutoConfiguration: the query routes and gateways, the budgets they run under, who may query what, and how many queries each store runs at once.
Ends every open query stream of the public port with end {"reason":"node-stopping","resumable":true}, and refuses new ones, as the node starts to stop: its clients resume them on another node.
How a failing read is retried, never giving up: the wait grows from initial-backoff by multiplier at each failure, up to max-backoff; past error-after attempts each failure is logged as an error.
A retry policy: the wait grows from initial-backoff by multiplier at each failure, up to max-backoff.
One subscription's in-process retry budget: each setting given replaces its handler's @Retry one, each one not given is the handler's, else wow.subscription.retry's. timeout bounds one attempt: one that runs longer is cancelled and counts as failed.
The scope the HTTP routes, public and internal, produce their streamed answers in, apart from the requests: cancelled once the node and the internal port have stopped, so a stream still open then ends instead of outliving the node.
An @OnSchedule job's settings, the only place it is configured: its rule, the cron, the time zone and the misfire policy, each unset to keep the annotation's (a tenant's own rule of a TENANT job comes before it); enabled false disables a SYSTEM or a SHARDED job's instances at startup; and the retry and parked retries of the subscriptions that run it, over its handler's @Retry and wow.subscription.retry, and over wow.subscription.parked.
Starts the node once its backends and internal port are up, and stops it once the public server has stopped: a stop reports the application not ready first, when nothing did (a host without a public server), then runs ServiceNode.stop apart from the thread that closes the context, which waits for it at most the phase's timeout.
Hears each step of ServiceNode.stop once it is done, in order: a bean of the application's.
The bounds of each context's shared states, the states its consumers share after each commit.
Requires a signed-in caller: decorated's caller without a subject, the anonymous one, is no caller, so the edge answers the request 401 on every route, as CoSec's resolver has it answered. For a service whose every route needs a user, in development too, where the host's callers (DevelopmentCallerResolver) serve a request without Wow-User as the anonymous caller.
The Sinks of the streams the service publishes: those the me.ahoo.wow.spi.sink providers on the classpath or among the application's beans find configured (PortProviders), the ClickHouse Sink by wow.clickhouse.sink.enabled=true alone, over the application's ClickHouse client when it has one, else one of wow.clickhouse.endpoint. Each is one subscription per published stream, named <processor>.<aggregate>, which the node takes with its subscription factories (ProvidedSinks).
Where the snapshots are, and how the snapshot maintenance runs. Snapshots may be written to several stores; a store added to them is backfilled from the log: switch the primary to it once it caught up, then drop the old one.
The snapshot query backend of the node: the bindings of each aggregate type's backend and storage facts (null when no backend serves the node's snapshots), and, for a backend the host manages, how it prepares an aggregate's storage and manages its x-wow-index indexes and those of its access attributes at startup.
How an in-place rebuild of the snapshots rewrites them (wow.snapshot.rebuild.*).
The springdoc bridge (gap): with springdoc on the classpath, the OpenAPI document of the public routes, the one GET /wow/openapi answers (wowOpenApi), joins springdoc's, so that /v3/api-docs and Swagger UI list the application's own controllers and the Wow routes together.
The Wow document as plain data, read into swagger-core's model for each springdoc document.
A DNS SRV lookup: the records of name, as a resolver finds them.
The cache of aggregate states each context keeps between commands.
A named store instance (wow.stores.<name>): its type, memory, postgres, mongo or a community backend's (the type of its store provider), how it manages the framework's schema (ddl) and how its queries run (query). Every other key of the store is a setting its provider declares, at the same level (wow.stores.<name>.data-source, wow.stores.<name>.client): the host reserves RESERVED alone, and a key no provider of the store's type declares fails the start, naming the ones it does. Two stores of one type may serve different databases; two log stores may not share one.
The store providers of the node, by type: the memory provider built into the host, those on the classpath (ServiceLoader: the built-in PostgreSQL and MongoDB ones, a community backend's), and the application's StoreProvider beans, each taking the place of the one of its type before it. A store's queries are its own facet (me.ahoo.wow.query.store.StoreQueries).
How one store's queries run (wow.stores.<name>.query.*): maxConcurrent, how many run at once, over wow.query.max-concurrent (beyond it a query is wow.query.busy, 429; 0 for no bound); maxWait and maxQueued, how long and how many queries beyond it wait for a permit, over wow.query.max-wait and wow.query.max-queued; events, its events queries; adaptive, how its bound adapts to its write pressure, over wow.query.adaptive.*.
How the node's subscriptions run, retry their failures and park what keeps failing.
One subscription's settings. start is where it starts in a partition it has no checkpoint in yet: beginning, end, or an ISO-8601 instant (2026-10-01T00:00:00Z), the first entry committed at or after it; unset, its kind's default (a projection from the beginning, a reactor or a saga from the end). A subscription that has a checkpoint goes on from it. parked is how its parked entries are retried, over wow.subscription.parked. retry is its in-process retry budget before it parks, over its handler's @Retry and wow.subscription.retry. A name the node has no subscription of is refused at startup, and so is the subscription of an @OnSchedule job, whose settings are its job's, wow.schedules.<job>.*.
When a subscription pauses its partition on a systemic failure: at once on a failure classified systemic, or when enough different aggregates failed within a window with no handling succeeding since. While paused, one attempt at a time probes until a handling succeeds. A handler's failures are classified by its @Retry(recoverable, unrecoverable), then the FailureClassifier beans, then the modules' on the classpath, then the runtime's own.
The tenants of the callers.
The node's firing loop of the timers, which sends the scheduled commands when they are due.
The node's topic transport: the one a TransportProvider gives, found on the classpath or among the application's beans (PortProviders), configured by its keys (wow.kafka.* for Wow's Kafka transport). The host builds nothing of a broker's own: it takes the transport's ports.
What needs a topic transport in a node without one (TransportSelection.NONE), in words: its aggregate types routed through Kafka (wow.aggregates.[..].routing=topic), its failure ledger published to the ops context (wow.ops.publish.enabled), and the command intake (a transport's command-intake.enabled, intake). A sourced subscription or a saga's commands to another context need it too, which the node itself refuses when it is built.
The node's topic transport, as wow.transport selects it (derived, the key an override):
How long and how far the commands' waits go.
The webhook of the parked entries, told when an entry parks or spends its retries.
The Wow host (.3; –): by what the classpath and the application's beans offer, it assembles one ServiceNode and serves it on two ports.
The aggregate models the node serves and the providers they come from (the binding index), with their factories' parameters from the application's beans.
How a caller of the public routes presents its identity, as the springdoc document declares it: the document's security schemes, by name, and its global security, one requirement naming them all, since a caller presents them together, so that Swagger UI's "Try it out" sends the identity.
The host's configuration, the wow.* namespace: the node, its internal port, its stores and logs, the cluster, the commands' waits and execution, the subscriptions, the timers and schedules, the HTTP edge and the calls to other contexts. The defaults are the runtime's own. The query plane, Kafka, ClickHouse and OpenTelemetry have their own classes (QueryProperties, KafkaProperties, ClickHouseProperties, ObservabilityProperties).