BC-065B — EventBridge Persistence & Serialization Boundary¶
Status: HISTORICAL
For the current architecture, see: ./dependances.md, ../runtime/overview.md.
Status¶
BC-065B completed.
No plugin file changed. No runtime mirror file changed. No Composer change. No runtime sync.
Retained option¶
Retained strategy: Option A — extract serialization only, plus a minimal persistence port.
| Option | Gain | Risk | Files | Retained |
|---|---|---|---|---|
| A — payload/type extractor | high | low | low | yes |
| B — envelope contract DTO | medium | medium | medium | no |
| C — full persistence service | medium | high | higher | no |
Reason:
EventBridgehad no proven incoming consumer in production code;PersistentEventStorehad an isolated append signature already matching the current persisted format;- introducing a tiny store contract made failure-order characterization testable without changing payload, type, dispatch, store implementation or replay format.
Public API¶
| API | Signature | Side effects | Exceptions |
|---|---|---|---|
| constructor | __construct(EventBus $eventBus, PersistableEventStore $eventStore) |
stores collaborators, creates serializer helper | none explicitly added |
| publish | publish(string $aggregateId, object $event): void |
persist then dispatch | propagates store/bus exceptions unchanged |
| subscribe | subscribe(string $eventType, callable $handler): void |
delegates to EventBus | none explicitly added |
Persisted format¶
EventBridge still passes the exact same values to the store:
| Champ | Source | Type | Nullabilité | Exemple |
|---|---|---|---|---|
aggregate_id |
publish($aggregateId, ...) |
string |
no | product-42 |
event_type |
$event::class |
string |
no | CMonChoix\Platform\Domain\Product\Event\ProductCreatedV2 |
payload |
get_object_vars($event) |
array<string,mixed> |
no | ['eventId' => 'evt', 'aggregateId' => 'product-42', ...] |
version |
default append arg | int |
no | 1 |
created_at |
generated by PersistentEventStore |
int |
no | time() |
Not persisted by EventBridge itself:
- metadata
- extra timestamp
- renamed event type
- replay envelope
- hydrated object
get_object_vars() limits¶
The new explicit serializer preserves the old behavior exactly:
- only publicly visible properties are extracted;
- inherited public properties remain visible;
- private/protected properties remain absent;
- nested objects, arrays, nulls and
DateTimeImmutableinstances remain untouched.
This is now documented behavior, not an accidental side effect.
Order¶
The order remains:
- persistence
- dispatch
Characterized cases:
| Cas | Persist appelé | Dispatch appelé | Résultat |
|---|---|---|---|
| success / success | yes | yes | success |
| persistence failure | yes attempted | no | store exception propagated |
| dispatch failure | yes | yes attempted | bus exception propagated after persistence |
Partial state remains possible by design if dispatch fails after persistence.
Compatibility¶
| Élément | Avant | Après | Identique |
|---|---|---|---|
| event type persisted | $event::class |
$event::class |
yes |
| payload persisted | get_object_vars($event) |
get_object_vars($event) |
yes |
| store call count | 1 | 1 | yes |
| bus publish count | 1 | 1 | yes |
| order | persist then dispatch | persist then dispatch | yes |
| plugin/runtime coupling | none | none | yes |
Remaining debt¶
After BC-065E final certification:
- BC-065 is closed;
EventBridgeremains legacy by FQCN but its persistence boundary is explicit and characterized;- any future redesign or retirement work must open a new dedicated BC outside BC-065.