Download the PHP package alexandrebulete/ddd-activity-bundle without Composer
On this page you can find all versions of the php package alexandrebulete/ddd-activity-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download alexandrebulete/ddd-activity-bundle
More information about alexandrebulete/ddd-activity-bundle
Files in alexandrebulete/ddd-activity-bundle
Package ddd-activity-bundle
Short Description Activity journal as a reusable DDD building block — who did what, through which chain of causes, and how it ended.
License MIT
Informations about the package ddd-activity-bundle
DDD Activity Bundle
The activity journal of a DDD application: who did what, through which chain of causes, and how it ended — for every command, every sensitive read and every effect on the outside world.
"Who deployed lapsa to production on the 12th?" becomes a search in the back office: Pauline from Slack, an AI agent, or the system reacting to an approval — with everything that led to it and everything that followed.
Install
Requires alexandrebulete/ddd-symfony-bundle ≥ 1.5, whose tracing provides the
actor and the chain on every message. Symfony Security and an IAM are
optional: without them, the system is the actor of every chain.
The bundle ships its own migration (a service, so it follows
activity.table): never migrations:diff its table.
What gets journaled
| Journaled | |
|---|---|
A command (CommandInterface) |
always — unless marked #[NotJournaled] |
A query (QueryInterface) |
only when marked #[Journaled] — sensitive reads |
| An external effect | when the adapter records it (below) |
| Anything else on the buses | no |
Each entry keeps: when; who (kind, id, the name at that time, and the
credential used — an API token's id, filterable: "everything this token did");
the
action; the outcome (succeeded, failed with the error, refused); the
channel; the chain (correlation_id, causation_id, message_id); the
permission of the use case; and what the message chose to describe.
A use case refused by the authorization middleware is journaled as refused,
with who asked.
Describing a use case
Nothing to do for the defaults. To name the subject, a readable sentence and
the facts worth keeping, a message implements the foundation's
JournaledInterface — the Application layer depends on nothing else:
Details are scalars or lists of scalars, picked explicitly: nothing is serialized implicitly, so no secret, entity or client document slips in.
Recording an external effect
The effect joins the chain being handled. It is written on its own connection: an effect that happened stays journaled even if the transaction around it is rolled back.
Guarantees
- A success is written in the command's transaction: rolled back with it, the journal never claims what did not happen. The EntityManager is flushed first, so a failure at flush time (a constraint) is a failure.
- A failure is written on a second connection: it survives the rollback, and a closed EntityManager.
- Journaling never hides an error: an entry that cannot be written is logged, and the original exception is what surfaces.
- Once per message: the middleware sits right before the handling — a message sent to a transport is journaled where it is consumed.
Databases. PostgreSQL and MySQL get every guarantee above. SQLite has a single writer: a failure occurring after the command wrote cannot be journaled — it is logged instead, without ever blocking the application.
Who sees what
Every entry carries the permission of its use case (an effect, the one of the
use case that caused it). When the application authorizes use cases (a
PermissionCheckerInterface is registered — the IAM does it), a viewer sees:
- the entries of the use cases they may run themselves,
- the entries of a message marked
#[Journaled(visibleWith: 'mission.supervise')]when they hold that permission — to widen the audience of a sensitive read, - their own actions.
Seeing the journal at all takes activity.find_activity_entries. Without a
checker, everything is visible to whoever reaches the screen.
Back office
With Sylius Admin UI, "Activity journal" lists entries with filters (actor, action, subject, outcome, chain). "Show the chain" narrows the list to one chain, oldest first. Read-only by construction.
Retention
The purge is a command like any other: the journal records its own purges.
Configuration
Development
The integration tests boot a kernel without Sylius nor Security, on the
database given by DDD_TEST_DATABASE_URL (a SQLite file otherwise); CI runs
them on PostgreSQL, MySQL and SQLite.
All versions of ddd-activity-bundle with dependencies
alexandrebulete/ddd-doctrine-bridge Version ^1.3
alexandrebulete/ddd-foundation Version ^1.4
alexandrebulete/ddd-sylius-bundle Version ^1.0
alexandrebulete/ddd-symfony-bundle Version ^1.5
doctrine/dbal Version ^4.3
doctrine/doctrine-bundle Version ^2.13 || ^3.0
doctrine/doctrine-migrations-bundle Version ^3.7 || ^4.0
doctrine/migrations Version ^3.8
doctrine/orm Version ^3.3
pagerfanta/core Version ^4.0
psr/clock Version ^1.0
psr/log Version ^3.0
sylius/admin-ui Version >=0.10
sylius/grid-bundle Version ^1.13
sylius/resource-bundle Version >=1.14
symfony/clock Version ^7.0 || ^8.0
symfony/config Version ^7.0 || ^8.0
symfony/console Version ^7.0 || ^8.0
symfony/dependency-injection Version ^7.0 || ^8.0
symfony/framework-bundle Version ^7.0 || ^8.0
symfony/messenger Version ^7.0 || ^8.0
symfony/translation Version ^7.0 || ^8.0
symfony/uid Version ^7.0 || ^8.0