feat: jpa, messaging, notification, mongo, graphql 어댑터터 구현체 추가

This commit is contained in:
DongHyeonka
2026-08-15 13:01:58 +09:00
parent ac874e49e6
commit 2f5d2fc219
909 changed files with 62510 additions and 6354 deletions
@@ -0,0 +1,69 @@
# NOTIF-ADR-005 — 어느 notification API가 canonical인가
## 상태
Accepted (2026-08-15). NTF-018 대응.
## 문제
같은 저장소에 notification 모델이 **두 개** 있다.
| 세대 | 위치 | 규모 |
| --- | --- | --- |
| R0 legacy | `adapter:outbound:notification`의 router/provider seam | 삭제 예정 |
| R1 | `dev.caskeleton.application.notification` (직속) | public type 100개 |
| Platform | `dev.caskeleton.application.notification.platform..` | 신규 |
`application-core/CLAUDE.md`는 R1을 "R1 canonical"이라 부르고,
`docs/notification/migration-guide.md`는 R0 → platform 이행만 설명하며 R1의 처분을 전혀 다루지 않는다.
`Channel`, plan, dispatch, receipt/evidence 모델이 두 namespace에 중복 존재하고 둘 사이에 production
bridge도 import도 없다.
**실패 모드는 "무엇이 깨지는가"가 아니라 "무엇을 써야 하는가"다.** 새 consumer가 어느 API를 쓸지 알 수
없고, 두 모델이 각자 진화하며, R0를 지운 뒤에도 R1 graph가 고아로 남거나 platform이 R1 정책을 우회하는
이중 canonical이 된다.
## 결정
**Platform이 canonical이다.** R1은 유지되지만 새 production consumer를 받지 않는다.
이유는 능력이 아니라 증거다. platform은 durable acceptance, fenced claim, event ledger, projection,
reconciliation을 실제 PostgreSQL 레인으로 증명한다(NOTIF-ADR-001~003). R1은 fake로 증명된 R1 계약이며
스스로 그렇게 선언한다 — `application-core/CLAUDE.md`가 "R1 application contract proven with fakes.
It does not claim PostgreSQL schema/locking, provider protocol, cryptographic verifier, or runtime
wiring qualification"이라고 적어 둔 그대로다.
## Disposition
R1 public type 100개의 처분은 네 가지 중 하나다.
| 처분 | 의미 | 대상 |
| --- | --- | --- |
| `replace` | platform에 동등물이 있다. 새 consumer는 platform을 쓴다 | `Channel`, plan/dispatch/receipt/evidence 계열 |
| `bridge` | 변환이 필요하다. 변환은 ACL 한 곳에만 둔다 | writer-cutover / receipt 적용 경로 |
| `retain` | platform이 다루지 않는 관심사다. 그대로 둔다 | consent/quiescence verifier port |
| `delete` | R0와 함께 사라진다 | R0 router가 쓰던 seam |
전수 분류표는 이 ADR이 아니라 `docs/notification/module-mapping.md`가 소유한다. ADR은 규칙을,
mapping 문서는 목록을 소유한다 — 목록을 두 곳에 복제하면 드리프트하는 쪽이 늘어난다.
## 강제
두 namespace 사이의 production dependency는 **0건**이며, 이것은 문서가 아니라 ArchUnit 규칙이 지킨다
(`CleanArchitectureTest``NOTIFICATION_R1_AND_PLATFORM_DO_NOT_DEPEND_ON_EACH_OTHER`).
변환이 필요해지면 `dev.caskeleton.application.notification.compatibility.r1` 한 패키지에만 두고, 그
패키지만 규칙에서 예외로 인정한다. 예외를 한 곳으로 모으는 것이 목적이다 — 두 모델이 서로를 아는
지점이 여러 곳이면 "어느 쪽이 canonical인가"라는 질문에 코드가 답하지 못한다.
## 결과
- 새 production consumer는 `..notification.platform..`만 쓴다.
- R1 type은 남지만, 새 코드가 그것을 import하면 ArchUnit이 막는다.
- R0 삭제는 이 ADR과 무관하게 진행된다. R1은 R0와 함께 사라지지 않는다.
## 하지 않은 것
R1 100개 type에 `@Deprecated(forRemoval = true)`를 붙이지 않았다. 제거 시점이 정해지지 않았고,
`forRemoval`은 "이 릴리스 이후 사라진다"는 약속이라 시점 없이 붙이면 그 자체가 거짓 신호다. 경계는
ArchUnit이 강제하고, deprecation은 제거 계획이 생길 때 붙인다.
+572
View File
@@ -0,0 +1,572 @@
# NTF-022 — public type surface of the notification platform.
# Every top-level public type under the platform packages. Growth is a reviewed
# change: ./gradlew updateNotificationApiSurface -PapproveNotificationApiChange
dev.caskeleton.adapter.outbound.notification.NotificationConfig
dev.caskeleton.adapter.outbound.notification.NotificationRoutesSettings
dev.caskeleton.adapter.outbound.notification.catalog.CompiledNotificationBinding
dev.caskeleton.adapter.outbound.notification.catalog.NotificationBindingCompiler
dev.caskeleton.adapter.outbound.notification.catalog.NotificationCanonicalRouteCatalog
dev.caskeleton.adapter.outbound.notification.catalog.NotificationCatalogException
dev.caskeleton.adapter.outbound.notification.catalog.NotificationCutoverRouteCatalog
dev.caskeleton.adapter.outbound.notification.catalog.NotificationPlanAdapter
dev.caskeleton.adapter.outbound.notification.catalog.NotificationProviderCapabilityCard
dev.caskeleton.adapter.outbound.notification.catalog.NotificationProviderCapabilityDescriptorSource
dev.caskeleton.adapter.outbound.notification.catalog.NotificationProviderDescriptor
dev.caskeleton.adapter.outbound.notification.catalog.NotificationProviderRuntimeProfile
dev.caskeleton.adapter.outbound.notification.catalog.NotificationRouteDescriptor
dev.caskeleton.adapter.outbound.notification.catalog.NotificationTemplateDescriptor
dev.caskeleton.adapter.outbound.notification.core.FailOpenNotificationProvider
dev.caskeleton.adapter.outbound.notification.core.NotificationProvider
dev.caskeleton.adapter.outbound.notification.core.RoutingNotifier
dev.caskeleton.adapter.outbound.notification.email.google.GoogleEmailClient
dev.caskeleton.adapter.outbound.notification.email.google.GoogleEmailNotificationAdapterConfig
dev.caskeleton.adapter.outbound.notification.email.google.GoogleEmailProvider
dev.caskeleton.adapter.outbound.notification.platform.autoconfigure.AssembledProvider
dev.caskeleton.adapter.outbound.notification.platform.autoconfigure.NotificationPlatformAutoConfiguration
dev.caskeleton.adapter.outbound.notification.platform.autoconfigure.NotificationPlatformMode
dev.caskeleton.adapter.outbound.notification.platform.autoconfigure.NotificationPlatformSettings
dev.caskeleton.adapter.outbound.notification.platform.autoconfigure.NotificationProviderAssembly
dev.caskeleton.adapter.outbound.notification.platform.autoconfigure.ProviderRuntimeAssembler
dev.caskeleton.adapter.outbound.notification.platform.autoconfigure.ProviderType
dev.caskeleton.adapter.outbound.notification.platform.dispatch.AttemptPermit
dev.caskeleton.adapter.outbound.notification.platform.dispatch.CapabilityReconciliationGateway
dev.caskeleton.adapter.outbound.notification.platform.dispatch.ConfiguredProfileCatalog
dev.caskeleton.adapter.outbound.notification.platform.dispatch.CredentialProbe
dev.caskeleton.adapter.outbound.notification.platform.dispatch.CredentialValidationException
dev.caskeleton.adapter.outbound.notification.platform.dispatch.JacksonRoutingPlanCodec
dev.caskeleton.adapter.outbound.notification.platform.dispatch.LeaseRecoveryService
dev.caskeleton.adapter.outbound.notification.platform.dispatch.LoggingInboxSignalPublisher
dev.caskeleton.adapter.outbound.notification.platform.dispatch.MapTemplateRendererRegistry
dev.caskeleton.adapter.outbound.notification.platform.dispatch.NotificationBackgroundWorkers
dev.caskeleton.adapter.outbound.notification.platform.dispatch.NotificationDispatchProperties
dev.caskeleton.adapter.outbound.notification.platform.dispatch.NotificationSchedulerWorker
dev.caskeleton.adapter.outbound.notification.platform.dispatch.ProviderAttemptLimiter
dev.caskeleton.adapter.outbound.notification.platform.dispatch.ProviderEventReplayWorker
dev.caskeleton.adapter.outbound.notification.platform.dispatch.ProviderRuntime
dev.caskeleton.adapter.outbound.notification.platform.dispatch.ProviderRuntimeRegistry
dev.caskeleton.adapter.outbound.notification.platform.dispatch.ProviderRuntimeRotator
dev.caskeleton.adapter.outbound.notification.platform.dispatch.ReconciliationJobWorker
dev.caskeleton.adapter.outbound.notification.platform.dispatch.RegistryProviderDispatchGateway
dev.caskeleton.adapter.outbound.notification.platform.dispatch.RegistryProviderRuntimeControl
dev.caskeleton.adapter.outbound.notification.platform.dispatch.RuntimeDrainCoordinator
dev.caskeleton.adapter.outbound.notification.platform.dispatch.SingleTenantContext
dev.caskeleton.adapter.outbound.notification.platform.dispatch.UuidV7Generator
dev.caskeleton.adapter.outbound.notification.platform.observation.LoggingNotificationAudit
dev.caskeleton.adapter.outbound.notification.platform.observation.LoggingNotificationMetrics
dev.caskeleton.adapter.outbound.notification.platform.observation.NotificationHealthReporter
dev.caskeleton.adapter.outbound.notification.platform.observation.NotificationHealthSnapshot
dev.caskeleton.adapter.outbound.notification.platform.observation.NotificationServingThresholds
dev.caskeleton.adapter.outbound.notification.platform.provider.ProviderResults
dev.caskeleton.adapter.outbound.notification.platform.provider.UnconfiguredAttachmentResolver
dev.caskeleton.adapter.outbound.notification.platform.provider.apns.ApnsFailureClassifier
dev.caskeleton.adapter.outbound.notification.platform.provider.apns.ApnsNotificationProviderAdapter
dev.caskeleton.adapter.outbound.notification.platform.provider.apns.ApnsProviderProperties
dev.caskeleton.adapter.outbound.notification.platform.provider.apns.ApnsRequestMapper
dev.caskeleton.adapter.outbound.notification.platform.provider.fcm.FcmBatchCoordinator
dev.caskeleton.adapter.outbound.notification.platform.provider.fcm.FcmBatchResult
dev.caskeleton.adapter.outbound.notification.platform.provider.fcm.FcmContactPointUpdater
dev.caskeleton.adapter.outbound.notification.platform.provider.fcm.FcmFailureClassifier
dev.caskeleton.adapter.outbound.notification.platform.provider.fcm.FcmGateway
dev.caskeleton.adapter.outbound.notification.platform.provider.fcm.FcmMessageMapper
dev.caskeleton.adapter.outbound.notification.platform.provider.fcm.FcmNotificationProviderAdapter
dev.caskeleton.adapter.outbound.notification.platform.provider.fcm.FcmProviderProperties
dev.caskeleton.adapter.outbound.notification.platform.provider.fcm.FcmTargetMapper
dev.caskeleton.adapter.outbound.notification.platform.provider.fcm.FcmWireTarget
dev.caskeleton.adapter.outbound.notification.platform.provider.http.JdkNotificationHttpGateway
dev.caskeleton.adapter.outbound.notification.platform.provider.http.NotificationEndpoints
dev.caskeleton.adapter.outbound.notification.platform.provider.http.NotificationHttpGateway
dev.caskeleton.adapter.outbound.notification.platform.provider.http.NotificationHttpRequest
dev.caskeleton.adapter.outbound.notification.platform.provider.http.NotificationHttpResponse
dev.caskeleton.adapter.outbound.notification.platform.provider.http.NotificationHttpTransportException
dev.caskeleton.adapter.outbound.notification.platform.provider.ses.AwsSignatureV4Signer
dev.caskeleton.adapter.outbound.notification.platform.provider.ses.SesCallbackAdapter
dev.caskeleton.adapter.outbound.notification.platform.provider.ses.SesDeliveryProjector
dev.caskeleton.adapter.outbound.notification.platform.provider.ses.SesEventNormalizer
dev.caskeleton.adapter.outbound.notification.platform.provider.ses.SesFailureClassifier
dev.caskeleton.adapter.outbound.notification.platform.provider.ses.SesNotificationProviderAdapter
dev.caskeleton.adapter.outbound.notification.platform.provider.ses.SesProviderProperties
dev.caskeleton.adapter.outbound.notification.platform.provider.ses.SesRequestMapper
dev.caskeleton.adapter.outbound.notification.platform.provider.ses.SesSuppressionUpdater
dev.caskeleton.adapter.outbound.notification.platform.provider.ses.SnsCertificateProvider
dev.caskeleton.adapter.outbound.notification.platform.provider.ses.SnsSignatureVerifier
dev.caskeleton.adapter.outbound.notification.platform.provider.smtp.SmtpDispatch
dev.caskeleton.adapter.outbound.notification.platform.provider.smtp.SmtpDispatchException
dev.caskeleton.adapter.outbound.notification.platform.provider.smtp.SmtpFailureClassifier
dev.caskeleton.adapter.outbound.notification.platform.provider.smtp.SmtpMimeMessageFactory
dev.caskeleton.adapter.outbound.notification.platform.provider.smtp.SmtpNotificationProviderAdapter
dev.caskeleton.adapter.outbound.notification.platform.provider.smtp.SmtpProviderProperties
dev.caskeleton.adapter.outbound.notification.platform.provider.twilio.TwilioCallbackAdapter
dev.caskeleton.adapter.outbound.notification.platform.provider.twilio.TwilioDeliveryProjector
dev.caskeleton.adapter.outbound.notification.platform.provider.twilio.TwilioFailureClassifier
dev.caskeleton.adapter.outbound.notification.platform.provider.twilio.TwilioProviderProperties
dev.caskeleton.adapter.outbound.notification.platform.provider.twilio.TwilioReconciliationCapability
dev.caskeleton.adapter.outbound.notification.platform.provider.twilio.TwilioRequestMapper
dev.caskeleton.adapter.outbound.notification.platform.provider.twilio.TwilioSignatureValidator
dev.caskeleton.adapter.outbound.notification.platform.provider.twilio.TwilioSmsProviderAdapter
dev.caskeleton.adapter.outbound.notification.platform.provider.twilio.TwilioStatusNormalizer
dev.caskeleton.adapter.outbound.notification.platform.provider.webhook.WebhookNotificationProviderAdapter
dev.caskeleton.adapter.outbound.notification.platform.provider.webhook.WebhookSignatureStrategy
dev.caskeleton.adapter.outbound.notification.platform.provider.webhook.WebhookSubscription
dev.caskeleton.adapter.outbound.notification.platform.provider.webpush.EncryptedWebPushPayload
dev.caskeleton.adapter.outbound.notification.platform.provider.webpush.Rfc8291Aes128GcmEncryptor
dev.caskeleton.adapter.outbound.notification.platform.provider.webpush.VapidAuthorizationProvider
dev.caskeleton.adapter.outbound.notification.platform.provider.webpush.VapidJwtSigner
dev.caskeleton.adapter.outbound.notification.platform.provider.webpush.VapidKeyRegistry
dev.caskeleton.adapter.outbound.notification.platform.provider.webpush.WebPushFailureClassifier
dev.caskeleton.adapter.outbound.notification.platform.provider.webpush.WebPushNotificationProviderAdapter
dev.caskeleton.adapter.outbound.notification.platform.provider.webpush.WebPushProviderProperties
dev.caskeleton.adapter.outbound.notification.platform.provider.webpush.WebPushReceiptCapability
dev.caskeleton.adapter.outbound.notification.platform.provider.webpush.WebPushRequestMapper
dev.caskeleton.adapter.outbound.notification.platform.reactor.ReactiveNotificationOrchestrator
dev.caskeleton.adapter.outbound.notification.platform.reactor.ReactorContextBridge
dev.caskeleton.adapter.outbound.notification.platform.reactor.ReactorNotificationOrchestrator
dev.caskeleton.adapter.outbound.notification.platform.security.AesGcmCallbackPayloadProtection
dev.caskeleton.adapter.outbound.notification.platform.security.AesGcmContactPointProtector
dev.caskeleton.adapter.outbound.notification.platform.security.CredentialGeneration
dev.caskeleton.adapter.outbound.notification.platform.security.HmacProviderRequestIdHasher
dev.caskeleton.adapter.outbound.notification.platform.security.ProviderCredentialManager
dev.caskeleton.adapter.outbound.notification.platform.security.SettingsSecretMaterialProvider
dev.caskeleton.adapter.outbound.notification.platform.template.CanonicalNotificationRenderer
dev.caskeleton.adapter.outbound.notification.platform.template.JacksonInboxContentCodec
dev.caskeleton.adapter.outbound.notification.platform.template.JacksonNotificationVariablesCodec
dev.caskeleton.adapter.outbound.notification.platform.template.JacksonTemplateContentCodec
dev.caskeleton.adapter.outbound.notification.platform.template.JsonSchemaVariableValidator
dev.caskeleton.adapter.outbound.notification.platform.template.NotificationDigest
dev.caskeleton.adapter.outbound.notification.platform.template.NotificationJsonMapper
dev.caskeleton.adapter.outbound.notification.platform.template.NotificationTemplateEngine
dev.caskeleton.adapter.outbound.notification.platform.template.PlaceholderTemplateEngine
dev.caskeleton.adapter.outbound.notification.platform.template.Sha256MessageDigestAdapter
dev.caskeleton.adapter.outbound.notification.platform.template.TemplateSlotMode
dev.caskeleton.adapter.outbound.notification.platform.template.ThymeleafNotificationRenderer
dev.caskeleton.adapter.outbound.notification.platform.template.ThymeleafStringTemplateEngine
dev.caskeleton.adapter.outbound.notification.provider.AttemptCorrelationId
dev.caskeleton.adapter.outbound.notification.provider.InlineNotificationAttemptAdapter
dev.caskeleton.adapter.outbound.notification.provider.NotificationAdmissionReadinessAdapter
dev.caskeleton.adapter.outbound.notification.provider.NotificationAttemptContext
dev.caskeleton.adapter.outbound.notification.provider.NotificationProviderAttemptAdapter
dev.caskeleton.adapter.outbound.notification.provider.NotificationProviderAttemptClient
dev.caskeleton.adapter.outbound.notification.provider.NotificationProviderRateAdmission
dev.caskeleton.adapter.outbound.notification.provider.NotificationProviderReadinessProbe
dev.caskeleton.adapter.outbound.notification.provider.NotificationProviderReadinessSnapshot
dev.caskeleton.adapter.outbound.notification.provider.NotificationProviderSecretMaterialProvider
dev.caskeleton.adapter.outbound.notification.provider.NotificationReconciliationAdapter
dev.caskeleton.adapter.outbound.notification.provider.NotificationSecretMaterialHandle
dev.caskeleton.adapter.outbound.notification.provider.PreparedNotificationAttempt
dev.caskeleton.adapter.outbound.notification.provider.ProviderMessageReference
dev.caskeleton.adapter.outbound.notification.provider.ReconciliationLookupMode
dev.caskeleton.adapter.outbound.notification.slack.webhook.SlackClient
dev.caskeleton.adapter.outbound.notification.slack.webhook.SlackNotificationAdapterConfig
dev.caskeleton.adapter.outbound.notification.slack.webhook.SlackWebhookProvider
dev.caskeleton.adapter.outbound.notification.template.LocalEmailRenderer
dev.caskeleton.adapter.outbound.notification.template.NotificationTemplateCatalog
dev.caskeleton.adapter.outbound.notification.template.NotificationTemplateManifest
dev.caskeleton.adapter.outbound.notification.template.NotificationTemplateRenderer
dev.caskeleton.adapter.outbound.notification.template.RenderedNotification
dev.caskeleton.adapter.outbound.notification.template.SlackBlockKitRenderer
dev.caskeleton.adapter.outbound.notification.template.TemplateRenderingException
dev.caskeleton.application.notification.ApplyNotificationReceiptCommand
dev.caskeleton.application.notification.ApplyNotificationReceiptResult
dev.caskeleton.application.notification.ApplyNotificationReceiptUseCase
dev.caskeleton.application.notification.Channel
dev.caskeleton.application.notification.ConsentCheckMode
dev.caskeleton.application.notification.EmailRecipientReference
dev.caskeleton.application.notification.InitializeNotificationWriterFencesCommand
dev.caskeleton.application.notification.InitializeNotificationWriterFencesOperation
dev.caskeleton.application.notification.InitializeNotificationWriterFencesResult
dev.caskeleton.application.notification.InitializeNotificationWriterFencesUseCase
dev.caskeleton.application.notification.InlineNotificationAttemptPort
dev.caskeleton.application.notification.NormalizedNotificationReceiptCommand
dev.caskeleton.application.notification.Notification
dev.caskeleton.application.notification.NotificationAdmissionClass
dev.caskeleton.application.notification.NotificationAdmissionGateCommand
dev.caskeleton.application.notification.NotificationAdmissionGateUseCase
dev.caskeleton.application.notification.NotificationAdmissionReadinessPort
dev.caskeleton.application.notification.NotificationAppendResult
dev.caskeleton.application.notification.NotificationApplicationException
dev.caskeleton.application.notification.NotificationAttemptId
dev.caskeleton.application.notification.NotificationCanonicalWriterFenceGuard
dev.caskeleton.application.notification.NotificationCanonicalWriterFencePort
dev.caskeleton.application.notification.NotificationCanonicalWriterRouteSet
dev.caskeleton.application.notification.NotificationCapabilityCompatibilityValidator
dev.caskeleton.application.notification.NotificationChannel
dev.caskeleton.application.notification.NotificationDeliveryId
dev.caskeleton.application.notification.NotificationDeliveryStorePort
dev.caskeleton.application.notification.NotificationDispatchCommand
dev.caskeleton.application.notification.NotificationDispatchResult
dev.caskeleton.application.notification.NotificationDispatchUseCase
dev.caskeleton.application.notification.NotificationEvidenceTrustSnapshot
dev.caskeleton.application.notification.NotificationFaultScope
dev.caskeleton.application.notification.NotificationFrozenPlan
dev.caskeleton.application.notification.NotificationIntentAppendPort
dev.caskeleton.application.notification.NotificationIntentDraft
dev.caskeleton.application.notification.NotificationIntentId
dev.caskeleton.application.notification.NotificationKindId
dev.caskeleton.application.notification.NotificationKindPolicy
dev.caskeleton.application.notification.NotificationLegacyWriterPermitCommand
dev.caskeleton.application.notification.NotificationLegacyWriterPermitResult
dev.caskeleton.application.notification.NotificationLegacyWriterPermitUseCase
dev.caskeleton.application.notification.NotificationMaintenanceCommand
dev.caskeleton.application.notification.NotificationMaintenanceResult
dev.caskeleton.application.notification.NotificationMaintenanceStorePort
dev.caskeleton.application.notification.NotificationMaintenanceUseCase
dev.caskeleton.application.notification.NotificationMode
dev.caskeleton.application.notification.NotificationOperationsSnapshot
dev.caskeleton.application.notification.NotificationOperationsSnapshotPort
dev.caskeleton.application.notification.NotificationOperationsSnapshotQuery
dev.caskeleton.application.notification.NotificationOperationsSnapshotUseCase
dev.caskeleton.application.notification.NotificationPlanPort
dev.caskeleton.application.notification.NotificationPlanningResult
dev.caskeleton.application.notification.NotificationPort
dev.caskeleton.application.notification.NotificationProviderAttemptPort
dev.caskeleton.application.notification.NotificationProviderCapabilityDescriptor
dev.caskeleton.application.notification.NotificationReasonCode
dev.caskeleton.application.notification.NotificationReceiptEventId
dev.caskeleton.application.notification.NotificationReceiptFact
dev.caskeleton.application.notification.NotificationReceiptIngressCapabilityDescriptor
dev.caskeleton.application.notification.NotificationReceiptProjection
dev.caskeleton.application.notification.NotificationReceiptStorePort
dev.caskeleton.application.notification.NotificationRecipientReference
dev.caskeleton.application.notification.NotificationReconciliationPort
dev.caskeleton.application.notification.NotificationRequestResult
dev.caskeleton.application.notification.NotificationRouteId
dev.caskeleton.application.notification.NotificationRouteStrategy
dev.caskeleton.application.notification.NotificationSignedEvidenceHeader
dev.caskeleton.application.notification.NotificationStoreCapabilityDescriptor
dev.caskeleton.application.notification.NotificationTechnicalSuppressionPort
dev.caskeleton.application.notification.NotificationTemplateParameters
dev.caskeleton.application.notification.NotificationTemplateRef
dev.caskeleton.application.notification.NotificationTemplateValue
dev.caskeleton.application.notification.NotificationWriterCutoverPort
dev.caskeleton.application.notification.NotificationWriterInventoryEvidence
dev.caskeleton.application.notification.NotificationWriterInventoryEvidenceVerifierPort
dev.caskeleton.application.notification.NotificationWriterOwnership
dev.caskeleton.application.notification.NotificationWriterQuiescenceAttestationPort
dev.caskeleton.application.notification.NotificationWriterRouteSet
dev.caskeleton.application.notification.ProviderAttemptOutcome
dev.caskeleton.application.notification.ReconcileNotificationDeliveriesCommand
dev.caskeleton.application.notification.ReconcileNotificationDeliveriesResult
dev.caskeleton.application.notification.ReconcileNotificationDeliveriesUseCase
dev.caskeleton.application.notification.RecordNotificationWriterQuiescenceAttestationCommand
dev.caskeleton.application.notification.RecordNotificationWriterQuiescenceAttestationOperation
dev.caskeleton.application.notification.RecordNotificationWriterQuiescenceAttestationResult
dev.caskeleton.application.notification.RecordNotificationWriterQuiescenceAttestationUseCase
dev.caskeleton.application.notification.RetryDisposition
dev.caskeleton.application.notification.SignedNotificationWriterInventoryManifest
dev.caskeleton.application.notification.SignedNotificationWriterQuiescenceManifest
dev.caskeleton.application.notification.SlackAudienceReference
dev.caskeleton.application.notification.SubmissionCertainty
dev.caskeleton.application.notification.SwitchNotificationWriterOwnershipCommand
dev.caskeleton.application.notification.SwitchNotificationWriterOwnershipOperation
dev.caskeleton.application.notification.SwitchNotificationWriterOwnershipResult
dev.caskeleton.application.notification.SwitchNotificationWriterOwnershipUseCase
dev.caskeleton.application.notification.TargetAttemptOutcome
dev.caskeleton.application.notification.TerminalizeExpiredNotificationWriterPermitsCommand
dev.caskeleton.application.notification.TerminalizeExpiredNotificationWriterPermitsOperation
dev.caskeleton.application.notification.TerminalizeExpiredNotificationWriterPermitsResult
dev.caskeleton.application.notification.TerminalizeExpiredNotificationWriterPermitsUseCase
dev.caskeleton.application.notification.platform.admin.AdminAccessDeniedException
dev.caskeleton.application.notification.platform.admin.AdminActor
dev.caskeleton.application.notification.platform.admin.AdminAuthorizationGuard
dev.caskeleton.application.notification.platform.admin.AdminOperationClaim
dev.caskeleton.application.notification.platform.admin.AdminOperationResult
dev.caskeleton.application.notification.platform.admin.AdminOperationStorePort
dev.caskeleton.application.notification.platform.admin.DuplicateRiskApprovalRequiredException
dev.caskeleton.application.notification.platform.admin.DuplicateRiskGuard
dev.caskeleton.application.notification.platform.admin.NotificationAdminApplicationService
dev.caskeleton.application.notification.platform.admin.NotificationAdminAuthority
dev.caskeleton.application.notification.platform.admin.NotificationAdminService
dev.caskeleton.application.notification.platform.admin.ProviderRuntimeControlPort
dev.caskeleton.application.notification.platform.admin.ReconcileCommand
dev.caskeleton.application.notification.platform.admin.RedriveCommand
dev.caskeleton.application.notification.platform.admin.SetProviderStateCommand
dev.caskeleton.application.notification.platform.admin.SuppressCommand
dev.caskeleton.application.notification.platform.api.CallbackIngestionResult
dev.caskeleton.application.notification.platform.api.CallbackRequest
dev.caskeleton.application.notification.platform.api.CancelCommand
dev.caskeleton.application.notification.platform.api.CancelResult
dev.caskeleton.application.notification.platform.api.ChannelPreferenceOverride
dev.caskeleton.application.notification.platform.api.CollapseScope
dev.caskeleton.application.notification.platform.api.CollapseSpec
dev.caskeleton.application.notification.platform.api.ContactPointId
dev.caskeleton.application.notification.platform.api.ContactPointSelector
dev.caskeleton.application.notification.platform.api.CorrelationId
dev.caskeleton.application.notification.platform.api.DeduplicationAction
dev.caskeleton.application.notification.platform.api.DeduplicationSpec
dev.caskeleton.application.notification.platform.api.DeliveryAttemptId
dev.caskeleton.application.notification.platform.api.EncodedNotificationPlan
dev.caskeleton.application.notification.platform.api.IdempotencyKey
dev.caskeleton.application.notification.platform.api.NotificationAcceptance
dev.caskeleton.application.notification.platform.api.NotificationId
dev.caskeleton.application.notification.platform.api.NotificationOrchestrator
dev.caskeleton.application.notification.platform.api.NotificationPlan
dev.caskeleton.application.notification.platform.api.NotificationReceipt
dev.caskeleton.application.notification.platform.api.NotificationSnapshot
dev.caskeleton.application.notification.platform.api.NotificationVariable
dev.caskeleton.application.notification.platform.api.ProviderEventId
dev.caskeleton.application.notification.platform.api.ProviderId
dev.caskeleton.application.notification.platform.api.ProviderProfileId
dev.caskeleton.application.notification.platform.api.RecipientDeliveryId
dev.caskeleton.application.notification.platform.api.RecipientSpec
dev.caskeleton.application.notification.platform.api.RequestStatus
dev.caskeleton.application.notification.platform.api.TemplateSelection
dev.caskeleton.application.notification.platform.api.TenantId
dev.caskeleton.application.notification.platform.api.content.AttachmentDisposition
dev.caskeleton.application.notification.platform.api.content.AttachmentRef
dev.caskeleton.application.notification.platform.api.content.EmailContent
dev.caskeleton.application.notification.platform.api.content.EmailOptions
dev.caskeleton.application.notification.platform.api.content.InAppAction
dev.caskeleton.application.notification.platform.api.content.InAppContent
dev.caskeleton.application.notification.platform.api.content.MobilePushContent
dev.caskeleton.application.notification.platform.api.content.NotificationContent
dev.caskeleton.application.notification.platform.api.content.PushPresentation
dev.caskeleton.application.notification.platform.api.content.SmsContent
dev.caskeleton.application.notification.platform.api.content.SmsOptions
dev.caskeleton.application.notification.platform.api.content.WebPushContent
dev.caskeleton.application.notification.platform.api.content.WebPushOptions
dev.caskeleton.application.notification.platform.api.delivery.AttemptConfirmation
dev.caskeleton.application.notification.platform.api.delivery.DeliveryOutcome
dev.caskeleton.application.notification.platform.api.delivery.EvidenceLevel
dev.caskeleton.application.notification.platform.api.delivery.RecipientDeliveryState
dev.caskeleton.application.notification.platform.api.delivery.SubmissionOutcome
dev.caskeleton.application.notification.platform.api.error.AmbiguousSubmissionException
dev.caskeleton.application.notification.platform.api.error.AttachmentIntegrityException
dev.caskeleton.application.notification.platform.api.error.AttachmentUnavailableException
dev.caskeleton.application.notification.platform.api.error.CallbackProjectionException
dev.caskeleton.application.notification.platform.api.error.CallbackValidationException
dev.caskeleton.application.notification.platform.api.error.FailureCategory
dev.caskeleton.application.notification.platform.api.error.IdempotencyConflictException
dev.caskeleton.application.notification.platform.api.error.InvalidContactPointException
dev.caskeleton.application.notification.platform.api.error.NotificationCapacityException
dev.caskeleton.application.notification.platform.api.error.NotificationException
dev.caskeleton.application.notification.platform.api.error.NotificationExpiredException
dev.caskeleton.application.notification.platform.api.error.NotificationFailureCode
dev.caskeleton.application.notification.platform.api.error.NotificationFailureDescriptor
dev.caskeleton.application.notification.platform.api.error.NotificationSuppressedException
dev.caskeleton.application.notification.platform.api.error.NotificationValidationException
dev.caskeleton.application.notification.platform.api.error.ProviderAuthenticationException
dev.caskeleton.application.notification.platform.api.error.ProviderAuthorizationException
dev.caskeleton.application.notification.platform.api.error.ProviderConfigurationException
dev.caskeleton.application.notification.platform.api.error.ProviderPayloadLimitException
dev.caskeleton.application.notification.platform.api.error.ProviderPermanentException
dev.caskeleton.application.notification.platform.api.error.ProviderRejectedException
dev.caskeleton.application.notification.platform.api.error.ProviderThrottledException
dev.caskeleton.application.notification.platform.api.error.ProviderTransientException
dev.caskeleton.application.notification.platform.api.error.ProviderUnavailableException
dev.caskeleton.application.notification.platform.api.error.ReconciliationException
dev.caskeleton.application.notification.platform.api.error.TemplateNotFoundException
dev.caskeleton.application.notification.platform.api.error.TemplateRenderingException
dev.caskeleton.application.notification.platform.api.error.TemplateVariableValidationException
dev.caskeleton.application.notification.platform.api.routing.Channel
dev.caskeleton.application.notification.platform.api.routing.DeliveryStrategy
dev.caskeleton.application.notification.platform.api.routing.ExplicitChannel
dev.caskeleton.application.notification.platform.api.routing.OrderedFallback
dev.caskeleton.application.notification.platform.callback.AppendEventResult
dev.caskeleton.application.notification.platform.callback.CallbackLimits
dev.caskeleton.application.notification.platform.callback.CallbackPayloadProtectionPort
dev.caskeleton.application.notification.platform.callback.CallbackVerificationResult
dev.caskeleton.application.notification.platform.callback.DeliveryAttemptResolverPort
dev.caskeleton.application.notification.platform.callback.DeliveryAttemptSnapshot
dev.caskeleton.application.notification.platform.callback.DeliveryProjection
dev.caskeleton.application.notification.platform.callback.DeliveryProjectionStorePort
dev.caskeleton.application.notification.platform.callback.EngagementFacts
dev.caskeleton.application.notification.platform.callback.IngestProviderCallbackApplicationUseCase
dev.caskeleton.application.notification.platform.callback.NormalizedEventType
dev.caskeleton.application.notification.platform.callback.NormalizedProviderEvent
dev.caskeleton.application.notification.platform.callback.NotificationSideEffectPort
dev.caskeleton.application.notification.platform.callback.ProjectionResult
dev.caskeleton.application.notification.platform.callback.ProjectionStatus
dev.caskeleton.application.notification.platform.callback.ProviderCallbackAdapter
dev.caskeleton.application.notification.platform.callback.ProviderCallbackAdapterRegistry
dev.caskeleton.application.notification.platform.callback.ProviderEventLedger
dev.caskeleton.application.notification.platform.callback.ProviderEventProjectionService
dev.caskeleton.application.notification.platform.callback.ProviderEventProjector
dev.caskeleton.application.notification.platform.callback.ProviderEventProjectorRegistry
dev.caskeleton.application.notification.platform.callback.ProviderEventRecord
dev.caskeleton.application.notification.platform.callback.ProviderEventRecordId
dev.caskeleton.application.notification.platform.callback.ProviderEventSource
dev.caskeleton.application.notification.platform.callback.StandardDeliveryProjector
dev.caskeleton.application.notification.platform.callback.SuppressionFacts
dev.caskeleton.application.notification.platform.callback.VerifiedCallback
dev.caskeleton.application.notification.platform.callback.VerifiedProviderEvent
dev.caskeleton.application.notification.platform.contact.ApnsDeviceToken
dev.caskeleton.application.notification.platform.contact.ApnsEnvironment
dev.caskeleton.application.notification.platform.contact.ContactPointStatus
dev.caskeleton.application.notification.platform.contact.ContactPointType
dev.caskeleton.application.notification.platform.contact.ContactPointValue
dev.caskeleton.application.notification.platform.contact.EmailAddress
dev.caskeleton.application.notification.platform.contact.FcmInstallationId
dev.caskeleton.application.notification.platform.contact.InAppRecipientRef
dev.caskeleton.application.notification.platform.contact.LegacyFcmRegistrationToken
dev.caskeleton.application.notification.platform.contact.MobilePushTarget
dev.caskeleton.application.notification.platform.contact.PhoneNumber
dev.caskeleton.application.notification.platform.contact.WebPushSubscriptionValue
dev.caskeleton.application.notification.platform.dispatch.ApplicationReceiptServiceImpl
dev.caskeleton.application.notification.platform.dispatch.AttachmentIntegrityGuard
dev.caskeleton.application.notification.platform.dispatch.CancelNotificationApplicationUseCase
dev.caskeleton.application.notification.platform.dispatch.CanonicalNotificationPlanEncoder
dev.caskeleton.application.notification.platform.dispatch.CanonicalNotificationPlanWriter
dev.caskeleton.application.notification.platform.dispatch.ContactPointRecord
dev.caskeleton.application.notification.platform.dispatch.ContactPointStorePort
dev.caskeleton.application.notification.platform.dispatch.DeliveryAttemptFactory
dev.caskeleton.application.notification.platform.dispatch.DeliveryAttemptRecord
dev.caskeleton.application.notification.platform.dispatch.DeliveryAttemptStorePort
dev.caskeleton.application.notification.platform.dispatch.DispatchGuardOutcome
dev.caskeleton.application.notification.platform.dispatch.DispatchOutcomeRecorder
dev.caskeleton.application.notification.platform.dispatch.DispatchPipeline
dev.caskeleton.application.notification.platform.dispatch.DuplicateIdempotencyKeyException
dev.caskeleton.application.notification.platform.dispatch.GetNotificationApplicationUseCase
dev.caskeleton.application.notification.platform.dispatch.MessageDigestPort
dev.caskeleton.application.notification.platform.dispatch.NotificationDispatchService
dev.caskeleton.application.notification.platform.dispatch.NotificationIdGeneratorPort
dev.caskeleton.application.notification.platform.dispatch.NotificationRequestInsertOutcome
dev.caskeleton.application.notification.platform.dispatch.NotificationRequestRecord
dev.caskeleton.application.notification.platform.dispatch.NotificationRequestStatusPolicy
dev.caskeleton.application.notification.platform.dispatch.NotificationRequestStorePort
dev.caskeleton.application.notification.platform.dispatch.NotificationRoutePlannerPort
dev.caskeleton.application.notification.platform.dispatch.NotificationRoutingPlanCodecPort
dev.caskeleton.application.notification.platform.dispatch.NotificationSubmissionService
dev.caskeleton.application.notification.platform.dispatch.NotificationVariablesCodecPort
dev.caskeleton.application.notification.platform.dispatch.PolicyRoutePlanner
dev.caskeleton.application.notification.platform.dispatch.ProviderDispatchGatewayPort
dev.caskeleton.application.notification.platform.dispatch.ProviderProfileCatalogPort
dev.caskeleton.application.notification.platform.dispatch.ProviderRequestIdHasherPort
dev.caskeleton.application.notification.platform.dispatch.RecipientDeliveryRecord
dev.caskeleton.application.notification.platform.dispatch.RecipientDeliveryStorePort
dev.caskeleton.application.notification.platform.dispatch.RecipientLease
dev.caskeleton.application.notification.platform.dispatch.RecipientLeaseStorePort
dev.caskeleton.application.notification.platform.dispatch.ReconciliationGatewayPort
dev.caskeleton.application.notification.platform.dispatch.ReconciliationJob
dev.caskeleton.application.notification.platform.dispatch.ReconciliationJobStorePort
dev.caskeleton.application.notification.platform.dispatch.ReconciliationService
dev.caskeleton.application.notification.platform.dispatch.RequestFingerprint
dev.caskeleton.application.notification.platform.dispatch.ScheduleNotificationApplicationUseCase
dev.caskeleton.application.notification.platform.dispatch.SubmitNotificationApplicationUseCase
dev.caskeleton.application.notification.platform.dispatch.SyntheticEventFingerprint
dev.caskeleton.application.notification.platform.dispatch.TemplateRendererRegistry
dev.caskeleton.application.notification.platform.dispatch.TenantContextPort
dev.caskeleton.application.notification.platform.email.EmailNotification
dev.caskeleton.application.notification.platform.email.EmailNotifier
dev.caskeleton.application.notification.platform.inbox.CreateInboxItemCommand
dev.caskeleton.application.notification.platform.inbox.InboxContentCodecPort
dev.caskeleton.application.notification.platform.inbox.InboxCursor
dev.caskeleton.application.notification.platform.inbox.InboxItem
dev.caskeleton.application.notification.platform.inbox.InboxItemCreated
dev.caskeleton.application.notification.platform.inbox.InboxItemId
dev.caskeleton.application.notification.platform.inbox.InboxItemState
dev.caskeleton.application.notification.platform.inbox.InboxMutationResult
dev.caskeleton.application.notification.platform.inbox.InboxPage
dev.caskeleton.application.notification.platform.inbox.InboxPrincipal
dev.caskeleton.application.notification.platform.inbox.InboxQuery
dev.caskeleton.application.notification.platform.inbox.MarkAllReadCommand
dev.caskeleton.application.notification.platform.inbox.NotificationInbox
dev.caskeleton.application.notification.platform.inbox.NotificationInboxSignalPort
dev.caskeleton.application.notification.platform.observation.CardinalityGuard
dev.caskeleton.application.notification.platform.observation.IllegalMetricTagException
dev.caskeleton.application.notification.platform.observation.NotificationAuditEvent
dev.caskeleton.application.notification.platform.observation.NotificationAuditPort
dev.caskeleton.application.notification.platform.observation.NotificationMetricName
dev.caskeleton.application.notification.platform.observation.NotificationMetricsPort
dev.caskeleton.application.notification.platform.observation.NotificationSecurityAuditPort
dev.caskeleton.application.notification.platform.observation.NotificationServingState
dev.caskeleton.application.notification.platform.observation.NotificationServingStatePort
dev.caskeleton.application.notification.platform.observation.SensitiveValueDetector
dev.caskeleton.application.notification.platform.policy.CompositeNotificationEligibilityPolicy
dev.caskeleton.application.notification.platform.policy.ConsentRecord
dev.caskeleton.application.notification.platform.policy.ConsentStorePort
dev.caskeleton.application.notification.platform.policy.DeduplicationResult
dev.caskeleton.application.notification.platform.policy.DeduplicationService
dev.caskeleton.application.notification.platform.policy.DeduplicationStorePort
dev.caskeleton.application.notification.platform.policy.DefaultNotificationRetryPolicy
dev.caskeleton.application.notification.platform.policy.EligibilityResult
dev.caskeleton.application.notification.platform.policy.JitterSource
dev.caskeleton.application.notification.platform.policy.NotificationContext
dev.caskeleton.application.notification.platform.policy.NotificationEligibilityPolicy
dev.caskeleton.application.notification.platform.policy.NotificationRetryPolicy
dev.caskeleton.application.notification.platform.policy.PreferenceRecord
dev.caskeleton.application.notification.platform.policy.PreferenceStorePort
dev.caskeleton.application.notification.platform.policy.RecipientIdentity
dev.caskeleton.application.notification.platform.policy.RetryBackoff
dev.caskeleton.application.notification.platform.policy.RetryBudget
dev.caskeleton.application.notification.platform.policy.RetryContext
dev.caskeleton.application.notification.platform.policy.RetryDecision
dev.caskeleton.application.notification.platform.policy.RouteCandidate
dev.caskeleton.application.notification.platform.policy.RoutingContext
dev.caskeleton.application.notification.platform.policy.RoutingDecision
dev.caskeleton.application.notification.platform.policy.RoutingDecisionEngine
dev.caskeleton.application.notification.platform.policy.SuppressionEntry
dev.caskeleton.application.notification.platform.policy.SuppressionId
dev.caskeleton.application.notification.platform.policy.SuppressionReason
dev.caskeleton.application.notification.platform.policy.SuppressionScope
dev.caskeleton.application.notification.platform.policy.SuppressionSource
dev.caskeleton.application.notification.platform.policy.SuppressionStorePort
dev.caskeleton.application.notification.platform.port.in.CancelNotificationCommand
dev.caskeleton.application.notification.platform.port.in.CancelNotificationUseCase
dev.caskeleton.application.notification.platform.port.in.GetNotificationQuery
dev.caskeleton.application.notification.platform.port.in.GetNotificationUseCase
dev.caskeleton.application.notification.platform.port.in.IngestProviderCallbackCommand
dev.caskeleton.application.notification.platform.port.in.IngestProviderCallbackUseCase
dev.caskeleton.application.notification.platform.port.in.ScheduleNotificationCommand
dev.caskeleton.application.notification.platform.port.in.ScheduleNotificationUseCase
dev.caskeleton.application.notification.platform.port.in.SubmitNotificationCommand
dev.caskeleton.application.notification.platform.port.in.SubmitNotificationUseCase
dev.caskeleton.application.notification.platform.provider.AttachmentAccessContext
dev.caskeleton.application.notification.platform.provider.AttachmentResolver
dev.caskeleton.application.notification.platform.provider.BatchNotificationProviderAdapter
dev.caskeleton.application.notification.platform.provider.CollapseCapability
dev.caskeleton.application.notification.platform.provider.EvidenceCertainty
dev.caskeleton.application.notification.platform.provider.EvidenceFact
dev.caskeleton.application.notification.platform.provider.NotificationProviderAdapter
dev.caskeleton.application.notification.platform.provider.ProviderCallNotStartedException
dev.caskeleton.application.notification.platform.provider.ProviderCapabilities
dev.caskeleton.application.notification.platform.provider.ProviderCollapseMapping
dev.caskeleton.application.notification.platform.provider.ProviderExecutionEvidence
dev.caskeleton.application.notification.platform.provider.ProviderFailure
dev.caskeleton.application.notification.platform.provider.ProviderProfileSnapshot
dev.caskeleton.application.notification.platform.provider.ProviderRuntimeState
dev.caskeleton.application.notification.platform.provider.ProviderSubmission
dev.caskeleton.application.notification.platform.provider.ProviderSubmissionResult
dev.caskeleton.application.notification.platform.provider.ReconciliationCapability
dev.caskeleton.application.notification.platform.provider.ReconciliationResult
dev.caskeleton.application.notification.platform.provider.ResolvedAttachment
dev.caskeleton.application.notification.platform.provider.TraceContext
dev.caskeleton.application.notification.platform.push.ApplicationIdentity
dev.caskeleton.application.notification.platform.push.ApplicationReceipt
dev.caskeleton.application.notification.platform.push.ApplicationReceiptService
dev.caskeleton.application.notification.platform.push.MobilePushNotification
dev.caskeleton.application.notification.platform.push.MobilePushNotifier
dev.caskeleton.application.notification.platform.push.ReceiptAuthorizationException
dev.caskeleton.application.notification.platform.push.ReceiptKind
dev.caskeleton.application.notification.platform.push.ReceiptResult
dev.caskeleton.application.notification.platform.security.AccessContext
dev.caskeleton.application.notification.platform.security.ContactPointProtector
dev.caskeleton.application.notification.platform.security.NotificationRedactor
dev.caskeleton.application.notification.platform.security.ProtectedContactPoint
dev.caskeleton.application.notification.platform.security.SafeDiagnosticContext
dev.caskeleton.application.notification.platform.security.SecretKeyMaterial
dev.caskeleton.application.notification.platform.security.SecretMaterialProvider
dev.caskeleton.application.notification.platform.security.SecretPurpose
dev.caskeleton.application.notification.platform.security.SensitiveValueClassifier
dev.caskeleton.application.notification.platform.security.SensitiveValueKind
dev.caskeleton.application.notification.platform.security.UnsafeDiagnosticFieldException
dev.caskeleton.application.notification.platform.sms.E164PhoneNumberParser
dev.caskeleton.application.notification.platform.sms.GsmAlphabet
dev.caskeleton.application.notification.platform.sms.InvalidPhoneNumberException
dev.caskeleton.application.notification.platform.sms.SmsEncoding
dev.caskeleton.application.notification.platform.sms.SmsEstimate
dev.caskeleton.application.notification.platform.sms.SmsNotification
dev.caskeleton.application.notification.platform.sms.SmsNotifier
dev.caskeleton.application.notification.platform.sms.SmsSegmentEstimator
dev.caskeleton.application.notification.platform.template.NotificationTemplateRenderer
dev.caskeleton.application.notification.platform.template.NotificationTemplateVersion
dev.caskeleton.application.notification.platform.template.RenderCommand
dev.caskeleton.application.notification.platform.template.RenderedNotificationContent
dev.caskeleton.application.notification.platform.template.TemplateContentCodecPort
dev.caskeleton.application.notification.platform.template.TemplateContentDefinition
dev.caskeleton.application.notification.platform.template.TemplateRegistry
dev.caskeleton.application.notification.platform.template.TemplateSlot
dev.caskeleton.application.notification.platform.template.TemplateStatus
dev.caskeleton.application.notification.platform.template.TemplateVariableValidator
dev.caskeleton.application.notification.platform.template.TemplateVersionConflictException
dev.caskeleton.application.notification.platform.template.VariableSchema
dev.caskeleton.application.notification.platform.webpush.WebPushNotification
dev.caskeleton.application.notification.platform.webpush.WebPushNotifier
+70 -12
View File
@@ -1,23 +1,73 @@
# Configuration reference
The notification delivery platform binds under `ca-skeleton.notification.platform`. The tree lives in
`src/app-bootstrap/src/main/resources/application.yml`, disabled by default, and every value carries
an inline default so a deployment that leaves the platform off supplies nothing.
Until 2026-08-15 this page named properties the binding did not have — `max-retry-concurrency`,
`scheduler-poll-interval`, `callback-worker-concurrency` — and omitted three it did. There was no
tree in `application.yml` at all, so the only way to configure the platform was to guess environment
variable names from Boot's relaxed binding. `./gradlew verifyNotificationConfiguration` now fails
when this page, the YAML tree and `docs/registries/env-keys.yaml` disagree.
## Master switch
| Property | Environment variable | Default | Meaning |
|---|---|---|---|
| `enabled` | `APP_NOTIFICATION_PLATFORM_ENABLED` | `false` | Binds nothing at all while false: no runtime, no schema check, no scheduler thread, no secret required |
| `mode` | `APP_NOTIFICATION_PLATFORM_MODE` | `SERVING` | `SERVING` refuses to start without a working provider; `ACCEPT_ONLY` stores requests and does not dispatch |
## Dispatch
| Property | Meaning | Bound |
|---|---|---|
| `claim-batch-size` | Rows claimed per scheduler tick | 1..1000 |
| `lease-duration` | How long a claimed job stays owned | positive, finite |
| `max-global-concurrency` | Ceiling across all providers | positive |
| `max-queue-age` | Age at which a job is escalated | positive |
| `max-retry-concurrency` | Ceiling for retry work | positive |
| `scheduler-poll-interval` | Queue poll cadence | positive |
| `callback-worker-concurrency` | Callback projection workers | positive |
| Property | Environment variable | Default | Bound |
|---|---|---|---|
| `dispatch.claim-batch-size` | `APP_NOTIFICATION_PLATFORM_CLAIM_BATCH_SIZE` | `50` | 1..1000 |
| `dispatch.lease-duration` | `APP_NOTIFICATION_PLATFORM_LEASE_DURATION` | `2m` | positive, finite |
| `dispatch.poll-interval` | `APP_NOTIFICATION_PLATFORM_POLL_INTERVAL` | `1s` | positive, finite |
| `dispatch.max-global-concurrency` | `APP_NOTIFICATION_PLATFORM_MAX_CONCURRENCY` | `64` | positive |
| `dispatch.max-additional-attempts` | `APP_NOTIFICATION_PLATFORM_MAX_ADDITIONAL_ATTEMPTS` | `4` | non-negative |
| `dispatch.max-queue-age` | `APP_NOTIFICATION_PLATFORM_MAX_QUEUE_AGE` | `24h` | positive |
| `dispatch.allow-ambiguous-fallback` | `APP_NOTIFICATION_PLATFORM_ALLOW_AMBIGUOUS_FALLBACK` | `false` | boolean |
Every value is bounded. "Unlimited" is not an accepted configuration.
The lease must outlast a provider call plus its timeout. Below that, a delivery a live worker is
still waiting on gets claimed by a second worker, and the recipient receives the notification twice.
## Callbacks
| Property | Environment variable | Default | Bound |
|---|---|---|---|
| `callbacks.enabled` | `APP_NOTIFICATION_PLATFORM_CALLBACKS_ENABLED` | `false` | boolean |
| `callbacks.max-body-bytes` | `APP_NOTIFICATION_PLATFORM_CALLBACK_MAX_BODY_BYTES` | `65508` | 1..65508 |
| `callbacks.replay-skew` | `APP_NOTIFICATION_PLATFORM_CALLBACK_REPLAY_SKEW` | `5m` | positive |
65508 is not a round number by accident: it is the ciphertext column's 65536 bytes minus the AES-GCM
nonce and tag. A larger configured value would pass every check above the database and fail the
`CHECK` constraint after the callback had already been acknowledged to the provider.
## Provider profiles
A profile pins provider type, environment, credential profile, timeouts, concurrency, rate limit,
retry policy and callback profile. Sender identity and credential profile are separate concerns.
Profiles are a map under `providers`, keyed by profile id. There are no environment variables for
them, because the keys are deployment-chosen; supply them as YAML or as
`CA_SKELETON_NOTIFICATION_PLATFORM_PROVIDERS_<ID>_<FIELD>`.
| Field | Meaning |
|---|---|
| `type` | `APNS`, `FCM`, `SES`, `SMTP`, `TWILIO`, `WEB_PUSH`, `WEBHOOK` — a closed enum, so an unknown value fails binding rather than assembling into nothing |
| `enabled` | A disabled profile is bound and validated but contributes no runtime |
| `primary-for-channel` | Exactly one primary per channel |
| `environment` | Required when enabled |
| `credential-profile` | Resolved through `SecretMaterialProvider`; never an inline secret |
| `topic` | APNs bundle id |
| `vapid-public-key` | Web Push application server key |
| `callback-signing-secret-ref` | Reference, not material |
| `timeout` | Positive and finite |
| `max-concurrency` | Positive |
| `rate-per-second` | Positive |
A profile pins provider type, environment, credential profile, timeouts, concurrency and rate limit.
Sender identity and credential profile are separate concerns.
## Startup failures
@@ -32,10 +82,18 @@ Startup fails rather than degrading when:
- a Web Push profile is missing its VAPID key
- two provider profiles share an id
- a route points only at disabled providers
- ambiguous fallback is enabled by default
- `mode` is `SERVING` and no provider profile is enabled
- the notification schema stream is not applied and promoted
## Secrets
All key material arrives through `SecretMaterialProvider`. Nothing is read from source, from a
committed file, or from a plaintext log. Contact point encryption and lookup HMAC keys must be
distinct, and the encryption key must be exactly 256 bits.
## Readiness
The platform contributes a `notifications` actuator endpoint and a health indicator. It reports DOWN
when a provider's credentials were rejected, when a configured provider has no channel route, and
when the measured backlog, stuck-lease count, projection lag or reconciliation lag passes the
thresholds in `NotificationServingThresholds`. See [operations.md](operations.md).
+77
View File
@@ -0,0 +1,77 @@
{
"$comment": [
"NTF-024 — what each support grade requires, as executable artifacts rather than prose.",
"A grade in support-matrix.md is a promise about production behaviour. The workflow that was",
"supposed to back those promises ran a unit subset on PR, a job named 'restart recovery' that",
"ran no restart, and a provider sandbox job whose entire body was two echo statements behind",
"continue-on-error. So the strongest claim in the document rested on the weakest evidence in",
"the pipeline, and nothing connected the two.",
"verifyNotificationEvidence reads this file, checks that every claim marked satisfied names",
"test classes that exist, and refuses a grade whose claims are not all satisfied."
],
"claims": {
"durable": {
"requires": "PostgreSQL migration, CRUD against the real schema, and survival of a restart",
"status": "satisfied",
"lane": ":adapter:outbound:persistence-jpa:jpaPlatformContractTest",
"evidence": [
"adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/notification/RecipientClaimContractTest.java",
"adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/notification/ProjectionFactDurabilityContractTest.java",
"adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/notification/ServingStateContractTest.java"
]
},
"multi-worker-safe": {
"requires": "two workers racing the same claim against a real database, with lease fencing",
"status": "satisfied",
"lane": ":adapter:outbound:persistence-jpa:jpaPlatformContractTest",
"evidence": [
"adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/notification/RecipientClaimContractTest.java",
"adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/readiness/PostgreSqlRecipientLeaseFencingIntegrationTest.java"
]
},
"callback-supported": {
"requires": "signature verification, duplicate suppression, and an event that arrives before its attempt is stored",
"status": "satisfied",
"lane": ":adapter:outbound:persistence-jpa:jpaPlatformContractTest",
"evidence": [
"adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/notification/LateEventBindingContractTest.java",
"application-core/src/test/java/dev/caskeleton/application/notification/platform/callback/CallbackIngestionAtomicityTest.java"
]
},
"recoverable": {
"requires": "a process-kill matrix covering each dispatch phase, proving no delivery is lost or duplicated",
"status": "satisfied",
"lane": ":adapter:outbound:persistence-jpa:jpaPlatformContractTest",
"evidence": [
"adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/notification/WorkerCrashRecoveryContractTest.java"
]
},
"provider-wire-qualified": {
"requires": "a real provider sandbox call producing an immutable, uploaded evidence artifact with a correlation id",
"status": "unsatisfied",
"lane": null,
"evidence": [],
"gap": "The provider-sandbox job runs two echo statements behind continue-on-error. No request has ever left the process, so no provider protocol is qualified against its real endpoint."
}
},
"grades": {
"Stable": [
"durable",
"multi-worker-safe",
"callback-supported",
"recoverable",
"provider-wire-qualified"
],
"Contract implemented / runtime unqualified": [
"durable",
"multi-worker-safe",
"callback-supported"
],
"Optional stable": [
"durable"
],
"Extension": [],
"Experimental": []
},
"matrixDocument": "docs/notification/support-matrix.md"
}
+13
View File
@@ -29,3 +29,16 @@ platform exists to avoid.
Registration tokens keep working through `LegacyFcmRegistrationToken`. New registrations should use
`FcmInstallationId`. The two are distinct types, so a migration is a compile-time task rather than a
runtime guess.
## R1의 처분 (NOTIF-ADR-005)
이 문서는 R0 router → platform 이행만 설명해 왔고, `dev.caskeleton.application.notification` 직속의
R1 public type 100개를 어떻게 할 것인지 다루지 않았다. 그래서 새 consumer가 어느 API를 써야 하는지
문서 어디에도 답이 없었다.
- **canonical은 `..notification.platform..`이다.** NOTIF-ADR-005가 근거와 함께 정한다.
- **R1은 남지만 새 production consumer를 받지 않는다.** 삭제 계획은 별개이며, R0 삭제와 함께
사라지지 않는다.
- **전수 분류표는 `docs/notification/module-mapping.md`에 있다** (replace / bridge / retain / delete).
- **두 namespace 간 production dependency는 0건이며 ArchUnit이 강제한다.** 변환이 필요하면
`dev.caskeleton.application.notification.compatibility.r1` 한 곳에만 둔다.
+22
View File
@@ -92,3 +92,25 @@ Two plan edges cannot be expressed as project edges in this repository, and are
`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.
## R1 public type disposition (NOTIF-ADR-005)
NOTIF-ADR-005 makes `..notification.platform..` canonical and keeps the R1 namespace in place
without new consumers. The ADR owns the rule; this table owns the list, so the two do not drift
apart by being written twice.
`NOTIFICATION_R1_AND_PLATFORM_DO_NOT_DEPEND_ON_EACH_OTHER` in `CleanArchitectureTest` enforces the
boundary: production dependencies between the two namespaces are zero, and the only permitted
exception is `dev.caskeleton.application.notification.compatibility.r1`.
| Disposition | Meaning | Types |
| --- | --- | --- |
| `replace` (27) | the platform has an equivalent; new consumers use it | `ApplyNotificationReceiptCommand`, `ApplyNotificationReceiptResult`, `ApplyNotificationReceiptUseCase`, `Channel`, `InlineNotificationAttemptPort`, `NormalizedNotificationReceiptCommand`, `NotificationAttemptId`, `NotificationDeliveryId`, `NotificationDeliveryStorePort`, `NotificationDispatchCommand`, `NotificationDispatchResult`, `NotificationDispatchUseCase`, `NotificationEvidenceTrustSnapshot`, `NotificationFrozenPlan`, `NotificationPlanPort`, `NotificationPlanningResult`, `NotificationProviderAttemptPort`, `NotificationReceiptEventId`, `NotificationReceiptFact`, `NotificationReceiptIngressCapabilityDescriptor`, `NotificationReceiptProjection`, `NotificationReceiptStorePort`, `NotificationSignedEvidenceHeader`, `NotificationWriterInventoryEvidence`, `NotificationWriterInventoryEvidenceVerifierPort`, `ProviderAttemptOutcome`, `TargetAttemptOutcome` |
| `bridge` (28) | conversion needed if an R1 caller remains; conversion lives only in the ACL | `InitializeNotificationWriterFencesCommand`, `InitializeNotificationWriterFencesOperation`, `InitializeNotificationWriterFencesResult`, `InitializeNotificationWriterFencesUseCase`, `NotificationAdmissionGateCommand`, `NotificationAdmissionGateUseCase`, `NotificationAppendResult`, `NotificationLegacyWriterPermitCommand`, `NotificationLegacyWriterPermitResult`, `NotificationLegacyWriterPermitUseCase`, `NotificationMaintenanceCommand`, `NotificationMaintenanceResult`, `NotificationMaintenanceUseCase`, `NotificationOperationsSnapshot`, `NotificationOperationsSnapshotQuery`, `NotificationOperationsSnapshotUseCase`, `NotificationRequestResult`, `ReconcileNotificationDeliveriesCommand`, `ReconcileNotificationDeliveriesResult`, `ReconcileNotificationDeliveriesUseCase`, `SwitchNotificationWriterOwnershipCommand`, `SwitchNotificationWriterOwnershipOperation`, `SwitchNotificationWriterOwnershipResult`, `SwitchNotificationWriterOwnershipUseCase`, `TerminalizeExpiredNotificationWriterPermitsCommand`, `TerminalizeExpiredNotificationWriterPermitsOperation`, `TerminalizeExpiredNotificationWriterPermitsResult`, `TerminalizeExpiredNotificationWriterPermitsUseCase` |
| `retain` (45) | a concern the platform does not cover; left as it is | `ConsentCheckMode`, `EmailRecipientReference`, `Notification`, `NotificationAdmissionClass`, `NotificationAdmissionReadinessPort`, `NotificationApplicationException`, `NotificationCanonicalWriterFenceGuard`, `NotificationCanonicalWriterFencePort`, `NotificationCanonicalWriterRouteSet`, `NotificationCapabilityCompatibilityValidator`, `NotificationChannel`, `NotificationFaultScope`, `NotificationIntentAppendPort`, `NotificationIntentDraft`, `NotificationIntentId`, `NotificationKindId`, `NotificationKindPolicy`, `NotificationMaintenanceStorePort`, `NotificationMode`, `NotificationOperationsSnapshotPort`, `NotificationPort`, `NotificationProviderCapabilityDescriptor`, `NotificationReasonCode`, `NotificationRecipientReference`, `NotificationReconciliationPort`, `NotificationRouteId`, `NotificationRouteStrategy`, `NotificationStoreCapabilityDescriptor`, `NotificationTechnicalSuppressionPort`, `NotificationTemplateParameters`, `NotificationTemplateRef`, `NotificationTemplateValue`, `NotificationWriterCutoverPort`, `NotificationWriterOwnership`, `NotificationWriterQuiescenceAttestationPort`, `NotificationWriterRouteSet`, `RecordNotificationWriterQuiescenceAttestationCommand`, `RecordNotificationWriterQuiescenceAttestationOperation`, `RecordNotificationWriterQuiescenceAttestationResult`, `RecordNotificationWriterQuiescenceAttestationUseCase`, `RetryDisposition`, `SignedNotificationWriterInventoryManifest`, `SignedNotificationWriterQuiescenceManifest`, `SlackAudienceReference`, `SubmissionCertainty` |
Total: 100 public types, every one classified.
No type carries `@Deprecated(forRemoval = true)`: no removal release is fixed, and
`forRemoval` without a date is a promise the codebase cannot keep. The boundary is
enforced by the ArchUnit rule instead.
+35 -5
View File
@@ -2,18 +2,48 @@
What each channel can actually prove, and what the platform refuses to claim.
The grade column is not an opinion. `docs/notification/evidence-manifest.json` declares which claims
each grade requires and which executable artifact proves each claim, and
`./gradlew verifyNotificationEvidence` refuses a grade whose claims are not all backed by a file that
exists. Raising a grade means adding the artifact first.
Five channels read `Stable` until 2026-08-15. Nothing in the pipeline had ever sent a request to a
provider — the sandbox job's whole body was two `echo` statements behind `continue-on-error` — and
no test killed a worker mid-dispatch. The protocols are implemented and their contracts are proven
against real PostgreSQL; the wire and the crash are not. That is what the grade now says.
## Channels
| Channel | Reference implementation | Grade | Strongest evidence the platform records by default |
|---|---|---|---|
| Email | SMTP, Amazon SES API | Stable | Provider acceptance; recipient mail-server delivery, bounce and complaint when the provider publishes events |
| SMS | Twilio Programmable Messaging | Stable | `accepted`/`queued`, `sent`, and carrier-DLR `delivered`/`undelivered` |
| Mobile push (Android and cross-platform) | FCM, FID-first with legacy registration token compatibility | Stable | FCM acceptance and explicit failures |
| Mobile push (Apple) | APNs HTTP/2 provider API | Stable | APNs acceptance |
| Web Push | RFC 8030, RFC 8291, RFC 8292 | Stable | Push-service acceptance; user-agent acknowledgement only where the service offers receipts |
| Email | SMTP, Amazon SES API | Contract implemented / runtime unqualified | Provider acceptance; recipient mail-server delivery, bounce and complaint when the provider publishes events |
| SMS | Twilio Programmable Messaging | Contract implemented / runtime unqualified | `accepted`/`queued`, `sent`, and carrier-DLR `delivered`/`undelivered` |
| Mobile push (Android and cross-platform) | FCM, FID-first with legacy registration token compatibility | Contract implemented / runtime unqualified | FCM acceptance and explicit failures |
| Mobile push (Apple) | APNs HTTP/2 provider API | Contract implemented / runtime unqualified | APNs acceptance |
| Web Push | RFC 8030, RFC 8291, RFC 8292 | Contract implemented / runtime unqualified | Push-service acceptance; user-agent acknowledgement only where the service offers receipts |
| In-app inbox | Own database | Optional stable | `PERSISTED`, `SEEN`, `READ` |
| Webhook | HTTP client platform | Extension | Whatever the receiving HTTP contract states |
## What each grade requires
| Grade | Requires |
|---|---|
| Stable | durable, multi-worker-safe, callback-supported, recoverable, provider-wire-qualified |
| Contract implemented / runtime unqualified | durable, multi-worker-safe, callback-supported |
| Optional stable | durable |
| Extension | nothing; the receiving contract owns its own guarantees |
| Experimental | nothing; the grade is the warning |
`recoverable` was met on 2026-08-15 by `WorkerCrashRecoveryContractTest`, which walks the four
phases a dispatch passes through — claimed, attempt written, request started, body committed — and
asserts for each that the delivery becomes claimable again or becomes a question for the provider,
never both and never neither.
The remaining unmet claim, and what would meet it:
- **provider-wire-qualified** — a real provider sandbox call producing an immutable, uploaded
artifact with a correlation id. No request has ever left the process in CI.
## Evidence levels
`NONE``PLATFORM_QUEUED``PROVIDER_ACCEPTED``NETWORK_OR_CARRIER_ACCEPTED`