# Notification Delivery Platform — module mapping > Source design: `notification-superpowers-package/docs/superpowers/specs/2026-08-10-notification-platform-design.md` > > Source plan: `notification-superpowers-package/docs/superpowers/plans/2026-08-10-notification-platform-implementation-plan.md` ## Why a mapping exists The plan was written against a hypothetical repository (`modules/notification/**`, root package `io.backend.skeleton.notification`, 31 Gradle projects). This repository is a fail-closed 19-leaf Clean Architecture template: `src/settings.gradle` rejects any registry that does not contain exactly the 19 modules in `src/config/architecture/modules.json`, and `verifyCleanArchitectureDependencies` rejects any project edge outside `allowed_dependencies`. Creating 31 new Gradle projects would violate HARD-STOP #5 of `AGENTS.md`. The package README anticipates this and instructs the implementer to map dependency catalog and package/file paths onto the host repository's rules while preserving the public contracts and reliability semantics. Every logical module of the plan is therefore implemented as a **package** inside the registered leaf that owns its responsibility. No public contract, evidence rule, or reliability semantic is dropped. ## Logical module → registered leaf | Plan module | Registered leaf | Package | |---|---|---| | `notification-core-api` | `application-core` | `dev.caskeleton.application.notification.platform.api` | | `notification-content-api` | `application-core` | `…platform.api.content` | | `notification-contact-api` | `application-core` | `…platform.contact` | | `notification-template-api` | `application-core` | `…platform.template` | | `notification-policy` | `application-core` | `…platform.policy` | | `notification-provider-spi` | `application-core` | `…platform.provider` | | `notification-callback-api` | `application-core` | `…platform.callback` | | `notification-email-api` | `application-core` | `…platform.email` | | `notification-sms-api` | `application-core` | `…platform.sms` | | `notification-push-api` | `application-core` | `…platform.push` | | `notification-webpush` (API half) | `application-core` | `…platform.webpush` | | `notification-inbox-api` | `application-core` | `…platform.inbox` | | `notification-admin-api` | `application-core` | `…platform.admin` | | `notification-security` (ports + redaction) | `application-core` | `…platform.security` | | `notification-observability` (ports) | `application-core` | `…platform.observation` | | `notification-dispatch-runtime` | `adapter:outbound:notification` | `dev.caskeleton.adapter.outbound.notification.platform.dispatch` | | `notification-security` (AES-GCM/HMAC impl) | `adapter:outbound:notification` | `…platform.security` | | `notification-template-thymeleaf` (reference renderer) | `adapter:outbound:notification` | `…platform.template` | | `notification-email-smtp` | `adapter:outbound:notification` | `…platform.provider.smtp` | | `notification-email-ses` | `adapter:outbound:notification` | `…platform.provider.ses` | | `notification-sms-twilio` | `adapter:outbound:notification` | `…platform.provider.twilio` | | `notification-push-fcm` | `adapter:outbound:notification` | `…platform.provider.fcm` | | `notification-push-apns` | `adapter:outbound:notification` | `…platform.provider.apns` | | `notification-webpush` (transport + crypto) | `adapter:outbound:notification` | `…platform.provider.webpush` | | `notification-webhook-extension` | `adapter:outbound:notification` | `…platform.provider.webhook` | | `notification-observability` (Micrometer impl) | `adapter:outbound:notification` | `…platform.observation` | | `notification-admin-runtime` | `adapter:outbound:notification` | `…platform.admin` | | `notification-reactor` | `adapter:outbound:notification` | `…platform.reactor` | | `notification-spring-boot-starter` | `adapter:outbound:notification` (+ `app-bootstrap` wiring) | `…platform.autoconfigure` | | `notification-persistence-jpa` | `adapter:outbound:persistence-jpa` | `dev.caskeleton.adapter.outbound.persistence.notification.platform` | | `notification-inbox-jpa` | `adapter:outbound:persistence-jpa` | `…persistence.notification.platform.inbox` | | `notification-callback-mvc` | `adapter:inbound:web` | `dev.caskeleton.adapter.inbound.web.notification.platform.callback` | | `notification-callback-webflux` | `adapter:inbound:web` | `…callback.reactive` | | `notification-testkit` | test source sets of the owning leaves | `…platform.testkit` | ## Dependency-direction consequences The plan's module DAG (`*-api` → `provider-spi`/`policy` → runtime/adapters → starter) is preserved by the leaf DAG that the registry already enforces: ```text application-core (all *-api, provider SPI, policy, callback contracts) ↑ ↑ ↑ adapter:outbound:notification adapter:outbound:persistence-jpa adapter:inbound:web ↑ ↑ ↑ app-bootstrap ``` Two plan edges cannot be expressed as project edges in this repository, and are replaced by ports: 1. `notification-email-ses`, `notification-sms-twilio`, `notification-push-fcm`, `notification-push-apns`, `notification-webpush`, `notification-webhook-extension` → `httpclient platform`. `adapter-outbound-notification` is not allowed to depend on `adapter-outbound-httpclient`. The provider adapters therefore call `dev.caskeleton.adapter.outbound.notification.platform.provider.http.NotificationHttpGateway`, an adapter-local port with a JDK `java.net.http.HttpClient` default implementation. `app-bootstrap` sees both leaves and is the supported place to substitute an implementation backed by the HTTP Client Platform (TLS/timeout/circuit-breaker/SSRF/dynamic-target policy reuse). 2. `notification-inbox-jpa` → `optional messaging outbox integration`. `adapter-outbound-persistence-jpa` may not depend on `adapter-outbound-messaging`; the inbox publishes through the existing persistence outbox tables plus the `NotificationInboxSignalPort` application port, and `app-bootstrap` binds the relay. ## Commit policy `AGENTS.md` pins commit policy to `human-only`. Step 5 (`git add` / `git commit`) of every plan task is therefore intentionally **not** executed by the agent; the working tree carries the change and the human owner commits.