# 두 번 선언되는 성질 5:/** Why a plaintext contact point is being revealed. Every reveal is auditable. */ 6:public record AccessContext(String purposeCode, String actorRef, boolean auditRequired) { 7: 8: public AccessContext { 9: Objects.requireNonNull(purposeCode, "purposeCode"); 10: Objects.requireNonNull(actorRef, "actorRef"); 11: if (purposeCode.isBlank() || actorRef.isBlank()) { 12: throw new IllegalArgumentException("purposeCode and actorRef must not be blank"); 13: } 14: } 15: 16: /** Context used by the dispatch pipeline immediately before a provider call. */ 17: public static AccessContext dispatch(String providerProfileId) { 18: return new AccessContext("DISPATCH", providerProfileId, false); 19: } 11: /** Decrypt a value for an audited purpose. */ 12: ContactPointValue reveal(ProtectedContactPoint protectedValue, AccessContext context); # 유일한 구현의 복호화 메서드 86: public ContactPointValue reveal(ProtectedContactPoint protectedValue, AccessContext context) { 87: Objects.requireNonNull(protectedValue, "protectedValue"); 88: Objects.requireNonNull(context, "context"); 89: SecretKeyMaterial key = keys.keyById(protectedValue.keyId()); 90: byte[] plaintext = 91: decrypt( 92: key, 93: protectedValue.nonce(), 94: associatedData(protectedValue.type()), 95: protectedValue.ciphertext()); 96: return parse(protectedValue.type(), new String(plaintext, StandardCharsets.UTF_8)); 97: } # 저장소 전체에서 이 레코드를 만드는 곳 application/notification/platform/security/AccessContext.java:17: public static AccessContext dispatch(String providerProfileId) { application/notification/platform/security/AccessContext.java:18: return new AccessContext("DISPATCH", providerProfileId, false); adapter/outbound/notification/platform/security/AesGcmContactPointProtectorTest.java:27: assertThat(protector.reveal(first, AccessContext.dispatch("ses-primary"))).isEqualTo(value); adapter/outbound/notification/platform/security/AesGcmContactPointProtectorTest.java:65: assertThatThrownBy(() -> protector.reveal(moved, AccessContext.dispatch("ses-primary"))) adapter/outbound/notification/platform/security/AesGcmContactPointProtectorTest.java:86: assertThatThrownBy(() -> protector.reveal(rotated, AccessContext.dispatch("ses-primary"))) adapter/outbound/notification/platform/provider/ses/SesNotificationProviderAdapter.java:115: AccessContext.dispatch(submission.profile().profileId().value())); adapter/outbound/notification/platform/provider/webpush/WebPushNotificationProviderAdapter.java:90: AccessContext.dispatch(submission.profile().profileId().value())); adapter/outbound/notification/platform/provider/smtp/SmtpNotificationProviderAdapter.java:90: AccessContext.dispatch(submission.profile().profileId().value())); adapter/outbound/notification/platform/provider/twilio/TwilioSmsProviderAdapter.java:86: AccessContext.dispatch(submission.profile().profileId().value())); adapter/outbound/notification/platform/provider/fcm/FcmBatchCoordinator.java:70: AccessContext.dispatch(submission.profile().profileId().value())); adapter/outbound/notification/platform/provider/apns/ApnsNotificationProviderAdapter.java:84: AccessContext.dispatch(submission.profile().profileId().value())); # 세 필드 접근자 호출 수 (저장소 전체) purposeCode : 0 actorRef : 7 auditRequired : 0 actorRef 가 잡히는 곳 application/notification/platform/admin/NotificationAdminApplicationService.java:138: actor.actorRef(), application/notification/platform/admin/NotificationAdminApplicationService.java:189: actor.actorRef(), application/notification/platform/admin/NotificationAdminApplicationService.java:267: actor.actorRef(), application/notification/platform/admin/NotificationAdminApplicationService.java:321: actor.actorRef(), adapter/outbound/notification/platform/observation/LoggingNotificationAudit.java:34: event.actorRef(), adapter/outbound/persistence/notification/platform/JpaAdminOperationStore.java:44: actor.actorRef(), adapter/outbound/persistence/notification/platform/JpaAdminOperationStore.java:101: actor.actorRef(), # 감사 설비는 있다 application/notification/platform/observation/NotificationAuditPort.java:4:public interface NotificationAuditPort { adapter/outbound/notification/platform/dispatch/ProviderRuntimeRegistryTest.java:183: private static final class RecordingAudit implements NotificationAuditPort { adapter/outbound/notification/platform/observation/LoggingNotificationAudit.java:23: implements NotificationAuditPort, NotificationSecurityAuditPort {