Codegen entity meta-model — C++ NATS
Table of Contents
This page is a segment of the Codegen org-entity meta-model hub. It covers
five separate physical-space facets together, because they are one
conceptual flow, not five independent concerns: ores.cpp.nats-handler,
ores.cpp.nats-sub-registrar, ores.cpp.nats-eventing,
ores.cpp.nats-event-registrar, ores.cpp.nats-event-cache. (All five
currently belong to the one C++ Technical Space alongside every other
C++ facet on this hub — there is no MASD concept of a "facet group"
one level below technical space; nothing in the physical-space graph
distinguishes these five as a NATS sub-grouping within it. A single
ores.cpp.nats facet with five archetypes underneath would model
this more accurately than five separate facets; that's a
physical-space graph change, tracked as task Consolidate the five
ores.cpp.nats-* facets into one facet with five archetypes rather
than done as part of this documentation task.)
Physical model mapping
| Facet | Description |
|---|---|
| ores.cpp.nats-handler | NATS subscription handlers. |
| ores.cpp.nats-sub-registrar | Per-entity NATS sub-registrar pair wiring an entity's subjects to its handler. |
| ores.cpp.nats-eventing | NATS changed-event publishers. |
| ores.cpp.nats-event-registrar | Per-entity NATS event-mapping registrar pair wiring an entity's Postgres LISTEN/NOTIFY channel to its changed-event pipeline. |
| ores.cpp.nats-event-cache | Consumer-side in-process cache mirroring a producer entity, kept fresh via eventing. |
Two independent pipelines
NATS transport is used for two unrelated purposes per entity, and it helps to keep them mentally separate:
Command pipeline — client asks, server answers
A client sends a request (defined by C++ Protocol), a handler receives it and dispatches to the C++ Service, and a sub-registrar wires the handler's methods to their NATS subjects.
ores.cpp.nats-handler→<entity>_handler.hpp— subject handler skeleton dispatching protocol messages to the service.ores.cpp.nats-sub-registrar→<entity>_registrar.hpp— declaresregister_<entity>_handlers(), the per-entity function that subscribes the handler's methods to their subjects.
Generates, in book_registrar.hpp:
namespace ores::refdata::messaging { std::vector<ores::nats::service::subscription> register_book_handlers(ores::nats::service::client& nats, ores::database::context ctx, std::optional<ores::security::jwt::jwt_authenticator> verifier); }
That function has to actually be called somewhere for the entity to work at all — see Codegen entity — post-generation checklist, this is one of the fixed post-generation steps.
Event pipeline — server tells everyone something changed
Independent of any client request: whenever a row changes, Postgres
NOTIFY's a channel; the event-registrar bridges that
LISTEN=/=NOTIFY channel into the eventing pipeline's changed-event
type; any consumer wanting a fast local view of the entity keeps a
event-cache warm by listening for that changed-event.
ores.cpp.nats-eventing→<entity>_changed_event.hpp— the event type itself.ores.cpp.nats-event-registrar→<entity>_event_registrar.hpp— declaresregister_<entity>_event_mapping(), bridging the DB notify channel to the changed-event pipeline.ores.cpp.nats-event-cache→<entity>_cache.hpp— a consumer-side in-process mirror, kept fresh via the changed-event above. Not every entity needs a cache; this facet only fires for entities another component actually mirrors (partyis mirrored by ores.iam, for example).
Generates, in book_changed_event.hpp:
namespace ores::refdata::eventing { /** * @brief Domain event indicating that book data has changed. * * Published when any book entity is created, updated, or * deleted. Subscribers use the timestamp to query for changes since that point. */ struct book_changed_event final { std::chrono::system_clock::time_point timestamp; // ... }; }
And, in another component's party_event_registrar.hpp (the
event-registrar pattern, illustrated from a real consumer):
namespace ores::synthetic::service::messaging { [[nodiscard]] ores::eventing::service::subscription register_gmm_component_event_mapping(ores::eventing::service::postgres_event_source& event_source, ores::eventing::service::event_bus& event_bus, ores::nats::service::client& nats); }
This registrar also has to be called somewhere — the Domain entity evaluation checklist's Service-layer criterion calls this out specifically: it is hand-maintained with no AUTO-GENERATED marker, and easy to miss when commissioning a new entity (party_type and ~14 other entities silently never fired eventing because of exactly this miss).
Paste blocks
The ores.cpp.nats-handler facet defines the following paste block
kinds, one per sub-heading below — see Paste blocks for the general
mechanism they assume.
Handler save() early-exit override
A placeholder at the very top of the generated save() method body,
before the standard JWT-authenticated request-context flow, expecting
a body block. Use for an entity whose save subject must
special-case some inbound messages before falling through to the
standard flow — e.g. workflow-step orchestration commands that bypass
JWT auth and use a header-supplied tenant id instead. The block
should contain its own early return for the cases it handles;
anything falling through continues into the generated standard flow.
party uses this for its workflow-step save command.
Handler extra includes
Additional #include directives after the standard generated
includes in <entity>_handler.hpp, expecting a body block. Use for
headers custom handler methods need — rfl/msgpack.hpp,
storage_transfer.hpp, extra protocol headers.
Handler custom public methods
Additional public method definitions just before the private:
label in <entity>_handler.hpp, expecting a declaration block. Use
for entity-specific NATS handler methods beyond the standard CRUD
surface — export-to-storage, bulk operations. Pairs with
C++ Protocol's custom message types when the method needs its own
request/response shapes.
Handler extra private members
Additional private member declarations inside the private section of
<entity>_handler.hpp, expecting a declaration block. Use when the
handler needs extra members the generic template doesn't generate,
e.g. http_base_url_.
See also
- Codegen org-entity meta-model — the hub.
- C++ Protocol — the message shapes this pipeline moves.
- C++ Service — what the handler dispatches to, and where the changed-event is published from.