Files
clean-architecture-backend-…/docs/superpowers/plans/2026-09-18-messaging-platform-bridge.md
T

4.9 KiB

Messaging Platform Bridge Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Connect the canonical application integration-event publish boundary to the messaging platform without re-encoding bytes or introducing broker-specific ownership in app-bootstrap.

Architecture: Add an application-owned publish port, implement it in adapter/outbound/messaging/platformbridge, and publish canonical pre-encoded envelopes through EncodedMessagePublisher. The bridge preserves identity/routing/evidence and maps platform publish evidence explicitly into application outcomes.

Tech Stack: Java 21, Gradle 9, Spring Boot auto-configuration, JUnit 5, AssertJ.

Spec: docs/superpowers/specs/2026-09-18-messaging-platform-bridge-design.md

Global Constraints

  • Preserve existing uncommitted changes; do not reset, stage, commit, amend, or push.
  • Never invent missing canonical identity, timestamp, trace, tenant, schema, or routing values.
  • Never bypass DefaultMessagePublisher through transport SPI or native Kafka clients.
  • Preserve exact ValidatedIntegrationEvent.envelopeBytes().
  • Fail closed before send when event or causation identity is not UUIDv7.
  • Legacy outbox storage/relay migration is outside this plan.

Task 1: Application-owned canonical publish port

Files:

  • Create: application-core/src/main/java/dev/caskeleton/application/messaging/event/IntegrationEventPublishPort.java
  • Test: existing bridge test compile contract

Interfaces:

  • Produces: CompletionStage<OutboxPublishOutcome> publish(ValidatedIntegrationEvent event)

  • Create the minimal application-owned interface.

  • Run the focused bridge test and verify remaining failures are platform dependencies/adapter implementation, not the port.

Task 2: Outbound messaging platform API dependency

Files:

  • Modify: adapter/outbound/messaging/build.gradle
  • Modify: adapter/outbound/messaging/gradle.lockfile through Gradle lock writing

Interfaces:

  • Consumes: :messaging:messaging-core-api, :messaging:messaging-schema-api.

  • Add only the platform API dependencies required by the bridge.

  • Refresh this module's locks.

  • Re-run focused bridge test and verify the missing type set is reduced to bridge production code.

Task 3: Canonical platform bridge

Files:

  • Create: adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/platformbridge/PlatformIntegrationEventPublishAdapter.java
  • Test: adapter/outbound/messaging/src/test/java/dev/caskeleton/adapter/outbound/messaging/platformbridge/PlatformIntegrationEventPublishAdapterTest.java

Interfaces:

  • Consumes: IntegrationEventPublishPort, EncodedMessagePublisher.

  • Produces: canonical application-to-platform anti-corruption bridge.

  • Implement UUIDv7 parsing that rejects incompatible identity before publisher invocation.

  • Map canonical metadata and exact bytes into MessageEnvelope<EncodedMessage>.

  • Preserve non-first-class evidence in bounded x-ca-* headers.

  • Map PublishResult using transmission evidence.

  • Run all three focused bridge tests to GREEN.

Task 4: Spring ownership while preserving the legacy seam

Files:

  • Modify: adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/MessagingSettings.java
  • Modify: adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/autoconfigure/MessagingBridgeRootAutoConfiguration.java
  • Test: focused auto-configuration ownership test

Interfaces:

  • Consumes: Spring-provided EncodedMessagePublisher, explicit app.messaging.producer-id.

  • Produces: IntegrationEventPublishPort bean for canonical events.

  • Add explicit producerId to the existing app.messaging adapter settings.

  • Register the canonical bridge only when app.messaging.producer-id is explicitly present.

  • Keep KafkaSender / KafkaMessageBroker as a documented transitional dependency of legacy outbox/realtime only.

  • Add a Spring test proving producer-id present => one canonical bridge bean, absent => no canonical bridge bean.

  • Run outbound messaging tests.

Task 5: Platform and composition regression verification

Files: no new production files unless a test exposes a real defect.

  • Run :messaging:messaging-runtime-core:test.
  • Run :messaging:messaging-spring-boot-starter:test.
  • Run :adapter:outbound:messaging:check --warning-mode=fail.
  • Run :app-bootstrap:architectureTest :app-bootstrap:systemTest --warning-mode=fail.
  • Search for direct app-bootstrap Kafka producer ownership.
  • Run git diff --check.
  • Report any remaining legacy outbox cutover blocker explicitly rather than inventing a migration.