Request lifecycle
This page traces a command and a query through a coupled service. Each step names the component that owns it, so you know where to look when something misbehaves.
A command
| Step | Owner | Fails with |
|---|---|---|
| Body size limit | riverbase_http | WEB-103 |
| Authentication | riverbase_http::auth | AUT-001, AUT-002 |
| Activity authorization | riverbase_http::casbin | AUT-003, CAS-011 |
| Payload decoding and validation | The generated command route | WEB-001 (422) |
| Command lookup | The command registry | CMD-* |
| Loading the root (object commands) | AggregateCore::open | DAT-001 (404) when missing or in another tenant |
| Business rules | Your aggregate | Your domain codes (TDO-*) |
| Commit | CommandUnitOfWork | DAT-* (conflicts are 409) |
Everything from "begin" to "commit" is one database transaction. If any step fails, the state change, the audit records, and the outbox rows roll back together. The command log is then updated to an error status.
A query
A query never opens a write transaction and never touches the aggregate. If the policy cannot be
resolved for a policy: required resource, the engine denies the request instead of returning
everything.
Where to hook in
| You need to | Hook |
|---|---|
| Reject a request before any domain code runs | Casbin policy, or a custom axum layer |
| Enforce a rule on every command, including non-HTTP calls | A CommandPolicy on the engine |
| Restrict rows | scope_policy on the resource; tenant access policy in config |
| React after a successful command | Consume its integration message from the bus |
Run code after execute in the same request | domain_trait: manual and a custom DomainCommandEngine::execute |