docs: the events are emitted by the API, and what that implies
Recording where the work lands and the two facts about that codebase that shape it: every write passes through one BaseModelViewSet, so one hook covers every domain; and the models are managed = False, so a transactional outbox introduces the estate's first Django-managed table beside the pre-existing schema. Emission belongs in the API rather than a database CDC or a gateway plugin, because only the API knows which change is a business event and only it holds the sub/azp that the event must carry for a downstream agent to act under the same authority. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -96,15 +96,38 @@ policy must not need to know the trigger mode.
|
|||||||
|
|
||||||
## Backlog
|
## Backlog
|
||||||
|
|
||||||
**Events over Kafka.** The target for the reactive half. The estate emits no
|
**Events over Kafka, emitted by `classic-models-api`.** The target for the
|
||||||
domain event today — `classic-models-api` has no signals, no outbound webhook,
|
reactive half. The estate emits no domain event today — the API has no signals
|
||||||
and there is no bus in the cluster — so a workflow can only poll, which is what
|
and no outbound webhook, and there is no bus in the cluster — which is what made
|
||||||
made a nightly sweep look like the only option. Until Kafka is in place,
|
a nightly sweep look like the only option.
|
||||||
detection stays unbuilt rather than being approximated by a periodic scan: a
|
|
||||||
batch that pretends to be reactive is worse than an absent feature, because it
|
|
||||||
looks finished.
|
|
||||||
|
|
||||||
The periodic ordering run does not wait on this.
|
The emission belongs **in the API**, not in a database CDC and not in a gateway
|
||||||
|
plugin. Only the API knows which change is a business event rather than a row
|
||||||
|
update, and only it holds the identity that made it — `sub` and `azp` from the
|
||||||
|
caller's token, which the event has to carry if a downstream agent is to act
|
||||||
|
under the same authority as the person who triggered it.
|
||||||
|
|
||||||
|
Two facts about that codebase shape the work:
|
||||||
|
|
||||||
|
- Every write goes through one `BaseModelViewSet` in
|
||||||
|
`api/v1/classicmodels/views.py`. One hook there covers products, orders,
|
||||||
|
payments and the rest — Django signals scattered across models would be the
|
||||||
|
harder version of the same thing.
|
||||||
|
- **The models are `managed = False`.** The tables are the pre-existing
|
||||||
|
classicmodels schema and Django owns no migrations for them. A transactional
|
||||||
|
outbox means introducing the estate's first managed table beside unmanaged
|
||||||
|
ones — which works, and is worth deciding deliberately rather than
|
||||||
|
discovering.
|
||||||
|
|
||||||
|
An outbox is the part that matters: emitting from a viewset after `save()` drops
|
||||||
|
the event if the process dies between the two, and an agent that never hears
|
||||||
|
about a stock movement is worse than one that hears late.
|
||||||
|
|
||||||
|
Until this exists, detection stays unbuilt rather than being approximated by a
|
||||||
|
periodic scan: a batch that pretends to be reactive is worse than an absent
|
||||||
|
feature, because it looks finished.
|
||||||
|
|
||||||
|
The periodic ordering run does not wait on any of it.
|
||||||
|
|
||||||
## Two controls that become mandatory here
|
## Two controls that become mandatory here
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user