EnvelopeRegistryService¶
Target
This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.
| Bounded context | BC-42 Data & Event Foundations |
| Platform / plane | Data & Event Platform / Data & Event |
| Deployment granularity | module of host · host DataEventFoundations |
| Status | target · ConnectSoft.Factory.DataEvent.Envelopes |
| Built from | connectsoft-microservice · libraries: connectsoft-extensions-messaging-model, connectsoft-extensions-messaging-model-orleans, connectsoft-extensions-persistence-model-nhibernate, connectsoft-extensions-saas-abstractions |
| Decisions | ADR-0012, ADR-0014 |
| Traceability | FR-10 FUX-11 NFR-05 NFR-14 XL-02 |
Purpose and responsibilities¶
EnvelopeRegistryService makes the event architecture (original design §55, ADR-0012, ADR-0014) enforceable. Every integration event in the model has a topic context.area.vN.event-name with exactly one producer and listed consumers; the registry holds the same facts at runtime with the payload schema versions and their compatibility (backward, forward, full, breaking), and refuses to activate a breaking version until every registered consumer has acknowledged it. It also holds the envelope profile: the port-level envelope fields are identical on every messaging profile (Orleans outbox/inbox, MassTransit on Azure Service Bus, NServiceBus); what differs is the carriage — mirrored transport properties, outbox and inbox table contracts, deduplication window — and that is what the profile records.
Hosts call ResolveTopic at publish time (cached) and, in non-production profiles, ValidateEnvelope before an outbox write.
Context and boundaries¶
flowchart LR
S["EnvelopeRegistryService"]
ControlPlaneApi["ControlPlaneApi"] -->|grpc| S
StudioBff["StudioBff"] -->|sync-http| S
S -->|grpc| ArtifactService["ArtifactService"]
S -. "TopicRegistered" .-> E_TopicRegistered(("event"))
S -. "SchemaVersionPublished" .-> E_SchemaVersionPublished(("event"))
S -. "TopicDeprecated" .-> E_TopicDeprecated(("event"))
S -. "EnvelopeProfileActivated" .-> E_EnvelopeProfileActivated(("event"))
The registry is downstream of the architecture model: ModelSync applies the generated topic catalog at release time and reports drift, so the model stays the source of truth and the registry the runtime mirror. Replay is not promised and exactly-once external effects are not promised (ADR-0014); consumers deduplicate on eventId within the profile's window.
Domain model¶
TopicDefinition — One integration topic: context (the producing bounded context slug), area, version, event name, producing service, registered consumers, the current payload schema version and the envelope profile; mirrors the architecture model and is the runtime truth for publish-time validation. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
topic |
string |
yes | context.area.vN.event-name |
context |
string |
yes | |
area |
string |
yes | |
version |
int |
yes | |
eventName |
string |
yes | |
producer |
string |
yes | Service id. |
consumers |
list:string |
yes | |
currentSchemaVersion |
string |
yes | |
state |
enum:TopicState |
yes | |
registeredAt |
datetime |
yes |
Invariants:
- Exactly one producer per topic; the context segment equals the producer's bounded-context slug.
- A new schema version is Active only if it is backward compatible with the current one or every registered consumer has acknowledged the breaking version.
- Deprecated topics keep delivering for the deprecation window; Retired topics reject publication.
stateDiagram-v2
Draft --> Active : Activate
Active --> Deprecated : Deprecate
Deprecated --> Retired : WindowElapsed
Events: TopicRegistered, SchemaVersionPublished, TopicDeprecated · Tables: Topics, SchemaVersions, TopicConsumers · Repository: TopicDefinitionRepository
EnvelopeProfile — How the port-level envelope (eventId, schemaVersion, occurredAt, tenantId, projectId, runId, stepId, attemptId, correlationId, causationId, producer, type; ADR-0014) is carried on each messaging profile: body fields, mirrored transport properties, outbox and inbox table contracts, deduplication window. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
profile |
enum:MessagingProfile |
yes | |
envelopeSchemaVersion |
string |
yes | |
transportProperties |
json |
yes | Mirrored properties, e.g. cs-event-type, cs-tenant-id, cs-schema-version |
outboxContract |
json |
yes | Outbox table columns and dispatcher semantics. |
inboxContract |
json |
yes | Inbox table columns and deduplication window. |
dedupWindowHours |
int |
yes | |
active |
bool |
yes |
Invariants:
- The envelope fields are identical across profiles; only their carriage differs.
- No profile promises exactly-once external effects or replay (ADR-0014); consumers deduplicate on eventId within the window.
Events: EnvelopeProfileActivated · Tables: EnvelopeProfiles · Repository: EnvelopeProfileRepository
erDiagram
TopicDefinition {
string topic PK
string context
string area
int version
string eventName
string producer
list_string consumers
string currentSchemaVersion
enum_TopicState state
datetime registeredAt
}
EnvelopeProfile {
enum_MessagingProfile profile PK
string envelopeSchemaVersion
json transportProperties
json outboxContract
json inboxContract
int dedupWindowHours
bool active
}
SchemaVersion {
string version
string schemaRef
enum_Compatibility compatibility
datetime publishedAt
datetime deprecatedAt
}
TopicDefinition ||--o{ SchemaVersion : contains
Entities and value objects¶
SchemaVersion (entity, in TopicDefinition) — One payload schema version with its JSON Schema reference and compatibility against the previous.
| Field | Type | Required | Description |
|---|---|---|---|
version |
string |
yes | |
schemaRef |
string |
yes | |
compatibility |
enum:Compatibility |
yes | |
publishedAt |
datetime |
yes | |
deprecatedAt |
datetime |
no |
Data model and storage¶
| Store | Role | Engine / profile | Tables |
|---|---|---|---|
| Data & Event foundations store | primary | azure-sql / nhibernate-sqlserver | Topics, SchemaVersions, TopicConsumers, EnvelopeProfiles |
| Table | Owner | Columns | Indexes |
|---|---|---|---|
dbo.Topics |
TopicDefinition | 10 | 2 |
dbo.SchemaVersions |
SchemaVersion | 7 | 0 |
dbo.TopicConsumers |
TopicDefinition | 4 | 0 |
dbo.EnvelopeProfiles |
EnvelopeProfile | 8 | 0 |
Full DDL: appendix.
APIs¶
| Method | Path | Operation | Scope | Side effects | Idempotency | Gateway | Summary |
|---|---|---|---|---|---|---|---|
GET |
/factory/data/topics |
ListTopics | factory.data.read |
read | natural | GW-03 | Topics with producer, consumers, current schema version and state; filter by context or producer. |
GET |
/factory/data/topics/{topic} |
GetTopic | factory.data.read |
read | natural | GW-03 | One topic with its schema versions and compatibility history. |
PUT |
/factory/data/topics/{topic} |
RegisterTopic | factory.data.admin |
production | natural | GW-03 | Register or update a topic (Platform admin; normally applied from the architecture model by the release pipeline). |
POST |
/factory/data/topics/{topic}/schema-versions |
PublishSchemaVersion | factory.data.admin |
production | key-header | GW-03 | Publish a payload schema version; breaking versions need every consumer's acknowledgement first. |
GET |
/factory/data/envelope-profiles |
ListEnvelopeProfiles | factory.data.read |
read | natural | GW-03 | Envelope carriage per messaging profile with outbox and inbox contracts. |
| gRPC service | Method | Streaming | Visibility | Side effects | Summary |
|---|---|---|---|---|---|
Envelopes |
ResolveTopic |
none | internal | read | Resolve an event name to its topic, current schema version and state at publish time. |
Envelopes |
ValidateEnvelope |
none | internal | read | Validate an envelope and payload against the registered schema version before it enters the outbox (optional strict mode). |
Messages¶
| Event | Topic | Scope / v | Aggregate | Consumers | Summary |
|---|---|---|---|---|---|
| TopicRegistered | data-foundations.topics.v1.topic-registered |
integration / 1 | TopicDefinition | StudioBff, AuditService | A topic was registered or its producer or consumers changed. |
| SchemaVersionPublished | data-foundations.topics.v1.schema-version-published |
integration / 1 | TopicDefinition | StudioBff, AuditService | A payload schema version is active. |
| TopicDeprecated | data-foundations.topics.v1.topic-deprecated |
integration / 1 | TopicDefinition | StudioBff, AuditService | A topic entered its deprecation window. |
| EnvelopeProfileActivated | data-foundations.envelopes.v1.envelope-profile-activated |
integration / 1 | EnvelopeProfile | StudioBff, AuditService | The installation's envelope profile (or its contracts) changed. |
TopicRegistered payload:
| Field | Type | Required | Description |
|---|---|---|---|
topic |
string |
yes | |
producer |
string |
yes | |
currentSchemaVersion |
string |
yes | |
state |
enum:TopicState |
yes |
SchemaVersionPublished payload:
| Field | Type | Required | Description |
|---|---|---|---|
topic |
string |
yes | |
version |
string |
yes | |
compatibility |
enum:Compatibility |
yes |
TopicDeprecated payload:
| Field | Type | Required | Description |
|---|---|---|---|
topic |
string |
yes | |
retiresAt |
datetime |
yes |
EnvelopeProfileActivated payload:
| Field | Type | Required | Description |
|---|---|---|---|
profile |
enum:MessagingProfile |
yes | |
envelopeSchemaVersion |
string |
yes |
| Command | Handled by | Result events | Summary |
|---|---|---|---|
RegisterTopic |
TopicDefinition | TopicRegistered | |
PublishSchemaVersion |
TopicDefinition | SchemaVersionPublished |
None modelled
No consumed events are modelled for this item yet.
Workers and jobs¶
| Worker | Trigger | Output events | Retry | Idempotency key | Summary |
|---|---|---|---|---|---|
| ModelSync | manual on release of the architecture model |
TopicRegistered, SchemaVersionPublished | fixed | topic + schemaVersion |
Applies the topics, producers, consumers and schema references of the architecture model (the generated catalogs) to the registry at release time and reports drift. |
| DeprecationSweeper | schedule 0 2 * * * |
— | none | topic + day |
Retires topics whose deprecation window elapsed. |
Actors and grains¶
None modelled
No grains are modelled for this item yet.
Sagas and long-running flows¶
None modelled
No sagas are modelled for this item yet.
sequenceDiagram
participant REL as Release pipeline
participant E as EnvelopeRegistryService
participant C as Consumer service
participant P as Producer host (outbox writer)
REL->>E: ModelSync (topics, producers, consumers, schema refs)
E->>E: compatibility check per schema version
alt breaking
E-->>REL: refused until consumers acknowledge
C->>E: acknowledge schema version
end
E-)C: SchemaVersionPublished
P->>E: ResolveTopic(eventName) → topic, schema version, state
P->>P: write envelope + payload to outbox (profile contract)
Options and configuration¶
| Section | Key | Type | Default | Reloadable | Secret | Summary |
|---|---|---|---|---|---|---|
DataEvent:Envelopes |
StrictValidation |
bool | false |
yes | no | Validate every outbox write against the schema (on in non-production profiles). |
DataEvent:Envelopes |
DeprecationWindowDays |
int | 90 |
yes | no | Days a deprecated topic keeps delivering. |
Metrics and observability¶
| Metric | Instrument | Unit | Dimensions | Summary |
|---|---|---|---|---|
connectsoft.factory.data_event.topics |
updown | {topic} | state | Topics by state. |
connectsoft.factory.data_event.envelope_validation_failures |
counter | {event} | producer, topic | Envelopes rejected by validation. |
Security¶
| Authentication | client-credentials |
| Scopes | factory.data.read (Read the registry.); factory.data.admin (Register topics and schema versions (Platform admin, release pipeline).) |
| Roles | PlatformAdmin, Operator, Observer |
| Tenant isolation | row-filter |
| Data classification | internal |
| Max side-effect class | production |
| Secrets | — |
Dependencies¶
Outbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| ArtifactService | grpc | JSON Schema documents of payload versions. | degrade | no |
Inbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| ControlPlaneApi | grpc | ResolveTopic and ValidateEnvelope from every host's outbox writer. | — | yes |
| StudioBff | sync-http | Registry views. | — | yes |
Failure and recovery¶
| Scenario | Detection | Recovery | Data impact | RTO (min) |
|---|---|---|---|---|
| Breaking schema published without acknowledgement | compatibility check | the publish is refused with the list of unacknowledged consumers | none | 0 |
NFR targets¶
| Target | Class value (pilot-interactive) | Override |
|---|---|---|
| latency_p95_ms | 2000 | — |
| availability_pct | 99.5 | — |
| throughput_rps | 50 | — |
| rpo_minutes | 15 | — |
| rto_minutes | 240 | — |
| cost_class | low | — |
Deployment¶
| Granularity | module of host · host DataEventFoundations |
| Topologies | saas-default, hybrid, on-prem, hybrid-compute |
| Runtime | —; replicas —–— |
| Ports | — |
Current implementation¶
Topic naming and the envelope are documented (event envelope, ADR-0014) and typed as run-event-envelope.schema.json; AgentEventEnvelope in code carries a different, older dialect. No registry exists; the generated events catalog is the design-time registry.
Later capabilities¶
CloudEvents as an optional carriage profile over the port (ADR-0012 note, technology radar); consumer-driven contract tests generated from the registry; topic-level access control for partner subscriptions through A2A.
Decisions and traceability¶
| Family | Ids |
|---|---|
| FR | FR-10 |
| FUX | FUX-11 |
| NFR | NFR-05, NFR-14 |
| XL | XL-02 |