Skip to content

Implement simple orchestrated email notification pattern - #2

Open
imagineux wants to merge 1 commit into
mainfrom
codex/design-java-spring-boot-email-notification-service-zcn4c0
Open

Implement simple orchestrated email notification pattern#2
imagineux wants to merge 1 commit into
mainfrom
codex/design-java-spring-boot-email-notification-service-zcn4c0

Conversation

@imagineux

Copy link
Copy Markdown
Owner

Motivation

  • Provide a boring, low-cognitive-load pattern for publish-only email notifications with a single orchestration flow and tiny per-notification code.
  • Centralize YAML-driven notification configuration and make adding new notifications as simple as config + template + one small model builder.
  • Share rendering and publishing concerns so domain code only calls a single entry point and does not implement transport or template logic.

Description

  • Add a typed configuration object NotificationProperties and a NotificationCatalog wrapper to load notifications.email.<TYPE> entries from application.yml.
  • Implement EmailNotificationOrchestrator which looks up config, resolves a NotificationModelBuilder registry, builds the template model, uses a TemplateRenderer to render HTML, constructs EmailPublicationRequest, and forwards it to an EmailPublicationPublisher interface.
  • Introduce NotificationModelBuilder<T> strategy interface and two concrete builders (HoldListCreatedModelBuilder, HoldListRemovedModelBuilder) plus example payload records to show how to extend the system.
  • Add shared interfaces/implementations: TemplateRenderer + ThymeleafTemplateRenderer, EmailPublicationPublisher + placeholder LoggingEmailPublicationPublisher, example Thymeleaf templates, and example domain usage in HoldListDomainService.

Testing

  • Added focused unit tests: NotificationCatalogTest (config lookup and missing-config behavior) and EmailNotificationOrchestratorTest (render+publish happy path, disabled behavior, and payload-type mismatch guard).
  • Attempted to run mvn test, but execution failed due to environment/network dependency resolution (Maven Central returned HTTP 403 while resolving the Spring Boot parent POM), so tests could not be executed in this environment.
  • The included tests are small and deterministic and are expected to pass when dependencies are resolvable and a normal Maven environment is available.

Codex Task

@bolt-new-by-stackblitz

Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f303c3a25c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

assertEquals("hold-list-created", renderer.templatePath);
assertEquals("HL-123", renderer.model.get("holdListId"));
assertEquals(1, publisher.published.size());
assertEquals("Hold list created", publisher.published.getFirst().subject());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid Java 21-only List#getFirst in Java 17 test code

This assertion uses List#getFirst(), which is only available on Java 21+; the project explicitly targets Java 17 in pom.xml, so test compilation will fail in the configured runtime once dependencies resolve. Please switch to a Java 17-compatible access pattern (for example get(0)) so the test suite can compile and run.

Useful? React with 👍 / 👎.

if (!candidate.payloadType().isInstance(payload)) {
throw new IllegalArgumentException(
"Payload type mismatch for " + type + ". Expected "
+ candidate.payloadType().getSimpleName() + " but got " + payload.getClass().getSimpleName()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard null payload before building mismatch error message

When notify is called with a null payload, isInstance(payload) returns false and this branch evaluates payload.getClass(), which throws NullPointerException instead of the intended IllegalArgumentException. That turns a controlled validation failure into an unexpected runtime error for callers that may pass nulls.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant