C++ System Structure — Package, Registration, And Bootstrap¶
C++ contract table of contents | Language interface table of contents | Next: C++ Per-Language Interface
This document owns how ZLink framework is composed in C++. Package/build target, application host, DI container, configuration, logging, lifecycle, and the registration surface of each capability.
The meaning and behavior rule of a capability is owned by the common spec — channel-messaging, spot-messaging, MeshNode, stream-session, actor-model, session-actor-dispatch, runtime-monitoring, location-runtime, channel-topology.
The public type and signature is owned by the per-capability interface. HTTP is owned by 60 · 61. The internal runtime structure is owned by internals/runtime-architecture — it isn't a public contract.
1. Product Position¶
The C++ framework isn't a binding helper — it's an application framework. It provides host, DI, configuration, logging, and lifecycle together.
This is decisively different from the other languages. .NET
borrows ASP.NET Core, Node borrows NestJS, and Java borrows Spring
Boot. C++ has no such host, so the framework provides it directly.
That's why only the C++ document keeps a per-capability spec.
What the framework must provide:
| Axis | Content |
|---|---|
| Application host | Starts application bootstrap and manages hosted service, module, and lifecycle. |
| DI container | Manages service lifetime and scope and provides dependencies through constructor injection. |
| Configuration | Provides application and Framework option as a hierarchical settings model. |
| Logging | Selects log level and backend and manages a bounded async queue and rotating file. |
| HTTP hosting | Provides an embedded HTTP server, route, and middleware inside the application lifecycle. |
| zlink messaging | Provides Channel, Spot, STREAM, and Actor message API. |
| Handler model | Registers a handler, dispatches it in the selected execution context, and applies filter. |
| Observability | Provides metric, message flow, and health status to the application. |
The public API is expressed in C++ convention — RAII, value type, template, coroutine.
2. Package And Build Target¶
| Target | CMake | Content |
|---|---|---|
zlink_framework |
zlink::framework (STATIC) |
Provides Framework core and requires C++20 (cxx_std_20). |
The client connector is a separate product line — owned by the C++ Stream Connector guide. It doesn't mutually depend on the server framework.
3. Application Host¶
class app_t; // host instance
class app_advanced_t; // advanced configuration access
class hosted_service_t; // start/stop hook
class module_t; // capability bundle registration
module_tbundles related registration into one unit. Used to split a large app by capability.- Runtime is built at host startup and cleaned up at shutdown. It isn't hidden behind lazy creation (channel-messaging §2).
3.1 Hosted Service Execution Order¶
| Stage | Rule |
|---|---|
| Start | Starts in registration order |
| Stop | Cleans up in reverse start order |
3.2 Start Failure — Fail-Fast¶
If even one service fails during start, the services started so far are cleaned up in reverse order and the exception is re-thrown. No half-started host is left behind.
Cleanup doesn't fail (noexcept). Because an error during cleanup
must not mask the original failure.
4. DI Container¶
4.1 Lifetime¶
| Lifetime | Meaning |
|---|---|
singleton |
One across the whole host |
scoped |
One per scope (§4.2) |
transient |
A new one every resolve |
4.2 Scope Boundary¶
Creation and cleanup of a scoped service is performed by the
Framework at the handler, STREAM session, and object lifecycle
boundary. The application doesn't choose a scope kind or create a
scope directly.
4.3 Registration¶
class service_collection_t
{
public:
template <typename T> service_collection_t &add_singleton ();
template <typename T, typename... TDependencies>
requires (sizeof...(TDependencies) > 0) service_collection_t &add_singleton ();
template <typename T> service_collection_t &add_singleton (std::unique_ptr<T> instance);
template <typename T> service_collection_t &add_scoped ();
template <typename T, typename... TDependencies>
requires (sizeof...(TDependencies) > 0) service_collection_t &add_scoped ();
template <typename T> service_collection_t &add_transient ();
template <typename T, typename... TDependencies>
requires (sizeof...(TDependencies) > 0) service_collection_t &add_transient ();
template <typename T, typename TFactory>
service_collection_t &add_factory (
TFactory factory,
service_lifetime_t lifetime = service_lifetime_t::transient);
template <typename T> service_collection_t &add_framework_dependency ();
};
- A dependency is declared as a template argument. With no argument, a default constructor is required (statically verified).
- Taking dependencies as a handler constructor's parameters makes the framework inject those types and build the handler.
logger_t<TCategory>is a framework dependency — it's auto-wired byadd_framework_dependency.
4.4 Resolve¶
class service_provider_t
{
public:
template <typename T> T &get_required (); // fails if absent
template <typename T> std::optional<std::reference_wrapper<T>> get (); // empty value if absent
};
A handler doesn't receive a service locator. Only constructor injection is used.
4.5 Error Contract¶
| Situation | Result |
|---|---|
| Registering the same type twice | Fails at registration time — doesn't silently overwrite |
get_required on an unregistered type |
Fails |
get on an unregistered type |
Returns an empty value. Doesn't fail |
Resolving a scoped service with no scope |
Fails — scoped requires a scope |
| Resolving from a closed provider | Fails as a shutdown boundary error |
4.6 Lifetime And Cleanup¶
singletonis built on the first resolve and reused for the host's lifetime.scopedis built on the first resolve in that scope and reused within the scope.- When the Framework closes a scope, it cleans up that scope's
scoped/transientinstances together.
A closed provider can't be used again. Every subsequent resolve fails.
5. Configuration¶
Configuration sources are merged as a hierarchy. A source added later overwrites an earlier one. If a required value is absent, it fails before host start.
6. Logging¶
The framework provides logging. It doesn't force an external logging library.
enum class log_level_t { trace, debug, info, warn, error, critical, off };
enum class logging_backend_t { builtin, structured };
enum class logging_overflow_policy_t { drop_debug, drop_oldest, block };
struct log_field_t; // structured log key-value
struct log_record_t; // one log entry
struct logging_async_options_t
{
std::size_t queue_capacity = 8192;
logging_overflow_policy_t overflow_policy = logging_overflow_policy_t::drop_debug;
};
struct rotating_file_options_t
{
std::size_t max_file_size = 10 * 1024 * 1024; // 10 MiB
std::size_t max_files = 5;
};
template <typename TCategory = void> class logger_t; // injected through DI
class logger_factory_t;
Async logging's overflow policy is a contract.
| Policy | Behavior |
|---|---|
drop_debug (default) |
When the queue fills, debug and below are dropped first. Keeps important logs alive |
drop_oldest |
Drops the oldest entry |
block |
Blocks the caller. Doesn't lose a log, but propagates the delay |
logger_t<TCategory> is injected through DI. Category is
distinguished by type.
7. HTTP Hosting¶
The framework provides an embedded HTTP server. The contract is owned by 60 · 61, and the public type is owned by configuration and host. Here only the rule that hits system structure is summarized.
7.1 Per-Request DI Scope¶
One request is one scope. The route handler and middleware receive
the same request-scope provider. When the request ends, that
scope's scoped/transient instances are cleaned up (§4.6).
7.2 Middleware Execution Order¶
Middleware is a before/after pair. This differs from the
handler filter's next delegate approach
(Framework API §8.1).
| Stage | Order |
|---|---|
before |
In registration order |
| Route handler | — |
after |
In reverse order |
after runs only for the middleware whose before ran.
8. Handler Registration And Filter¶
The handler registration surface and filter contract are owned by Channel Messaging §3. Filter's language-neutral meaning is owned by Framework API §8.1.
9. Capability Registration¶
The registration surface of each capability is owned by the per-capability interface.
| Capability | Section |
|---|---|
| Channel | §7 Channel Builder |
| SPOT · Actor | §11 Spot Framework API and Instance Spot registration/call |
| STREAM | §12 Hosted Service and Module |
| HTTP | 60 · 61 |
| Monitoring · Location | §13 Configuration and Logging |
The startup validation item is owned by the common spec — channel-messaging §4, spot-messaging §8, stream-session §7.2, runtime-monitoring §6.
C++ turns every violation into a failure before host start. The
error follows the result_t/framework_exception_t boundary
convention, not an exception
(common runtime).
10. Regression Test¶
The regression item for registration and startup validation is owned by regression-test-matrix.
C++ contract table of contents | Language interface table of contents | Next: C++ Per-Language Interface