Skip to content

Support explicit single-tenant routing without synthetic TenantID #6

@fredcamaral

Description

@fredcamaral

Problem

lib-streaming currently rejects non-system events when EmitRequest.TenantID is empty. That is correct for SaaS multi-tenant deployments, but it leaves single-tenant/BYOC services with only bad choices:

  • skip emitting business events when no tenant-manager tenant exists;
  • put organizationId into TenantID, which is semantically wrong;
  • invent a synthetic tenant UUID, which violates services that intentionally have no tenant identity in single-tenant mode.

In plugin-br-bank-transfer, we rejected the organizationId -> TenantID fallback because tenant identity and organization scope are distinct:

  • tenantId comes from tenant-manager/JWT context and routes tenant-scoped infrastructure.
  • organizationId is a business-scope identifier for CRM/Midaz/Fees calls.
  • Overloading EmitRequest.TenantID with organization metadata contaminates CloudEvents/outbox routing metadata and can mislead downstream consumers.

The current safe plugin behavior is to skip emits when no real tenant is present. That preserves correctness but means single-tenant deployments lose streaming events.

Desired Capability

Add an explicit single-tenant routing mode that lets services emit non-system business events without providing a fake TenantID.

Possible API shapes:

  1. Add a routing scope field:
type EmitRequest struct {
    DefinitionKey string
    TenantID      string
    RoutingScope  RoutingScope // e.g. MultiTenant, SingleTenant, System
    Subject       string
    EventID       string
    Payload       []byte
}
  1. Add a dedicated single-tenant routing key/config at builder level:
streaming.WithSingleTenantRoutingKey("default")
  1. Add an explicit method/helper:
emitter.EmitSingleTenant(ctx, EventRequest{...})

The important contract: the emitted event must not label this value as tenant identity (tenantId, ce-tenantid, outbox tenant_id) unless it is an actual tenant-manager tenant.

Acceptance Criteria

  • Multi-tenant non-system events still fail fast when TenantID is missing.
  • Single-tenant non-system events can be emitted through an explicit API/config path.
  • CloudEvents/outbox metadata does not misrepresent organization IDs or synthetic IDs as tenant identity.
  • Event manifests/documentation make the distinction between tenant identity and single-tenant routing metadata clear.
  • Existing multi-tenant behavior remains backward compatible.

Downstream Context

This was found during Gate 8 review of plugin-br-bank-transfer. The branch temporarily considered using either organizationId or a fixed UUID as EmitRequest.TenantID; both were rejected because they violate the plugin tenant-isolation rules and produce misleading event metadata.

Until this is supported upstream, the plugin will skip emits when no real tenant exists rather than emit events with a false tenant identity.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions