Skip to content

Refactor @sthrift/service-sendgrid package to provide a ServiceSendGrid facade with mock for local development #223

@nnoce14

Description

@nnoce14

Problem

Developers currently rely on SendGrid for email template verification, which requires sending real emails and a valid API key. This makes local development and testing workflows cumbersome. This effort aligns with the overall direction we are heading for disconnected development, which allows local development to progress without reliance on any external integrations.

Public Interface Direction

The key consideration is that @sthrift/transactional-email-service should be just a package with a single interface in it. It has to be generic enough to support multiple 3rd party vendors. The publicly exposed interface for the facade should be minimal, hiding all proprietary details and specific datatypes that are part of the SendGrid library, exposing only the absolute simplest interface necessary to get the job done. The code within the facade should translate this simple public interface into the proprietary calls to the email provider's API. This ensures we can swap implementations of mail sending services without having to change the public interface or upstream logic—enabling a true plug-and-play approach (e.g., swapping in Azure Communication Services). We should take this approach for all of our 3rd party integrations going forward.

We should start by defining the public interface first—such as:

  • @sthrift/transactional-email-service (only defines the facade interface; the rest of the system refers only to this interface)

Then, the specific implementations are fully interchangeable and can be swapped without impacting upstream code:

  • @sthrift/transactional-email-service-sendgrid-v3 (facade-implementation)
  • @sthrift/transactional-email-service-sendgrid-v4 (facade-implementation)
  • @sthrift/transactional-email-service-azure-communication (facade-implementation, example only)
  • @sthrift/transactional-email-service-mock (facade-implementation)

For this task, only concrete implementations for transactional email service sendgrid and transactional email service mock are required. Azure Communication Services is provided as an example of how this architecture enables easily swappable integrations and may be explored in the future.

Configuration Approach

The @sthrift/api package will be responsible for determining which facade implementation is actually registered at application startup. This should be determined by environment variable values.

Proposal

Refactor the existing @sthrift/service-sendgrid package so it becomes the facade for ServiceSendGrid. This facade should:

  • Expose the same interface for sending emails as the current implementation.
  • The implementation should determine which email service to use based on the value of the SENDGRID_API_KEY environment variable. If the environment variable is set for local development, the mock implementation should be used; if set for production/remote, the actual SendGrid service should be used.

Mock Implementation

  • Instead of sending emails, the mock should save the HTML email template (including all styling) to a local folder (suggested: tmp/ inside the service-sendgrid package).
  • Ensure the folder is included in .gitignore so downloaded templates are not committed.
  • This enables developers to verify email content and styling locally without using SendGrid.
  • You can explore existing mock implementations such as:

Acceptance Criteria

  • @sthrift/transactional-email-service package provides a minimal, generic interface for sending transactional emails, hiding all proprietary details.
  • Only two concrete implementations are required for this task:
    • @sthrift/transactional-email-service-sendgrid-v3 (or v4) as the SendGrid implementation
    • @sthrift/transactional-email-service-mock as the mock implementation
  • The mock implementation saves HTML emails to tmp/ and never sends to SendGrid.
  • The mock's output folder is ignored by git.
  • The @sthrift/api package determines which implementation is registered at app startup via environment variables.
  • The system remains fully compatible with existing logic and can easily swap new providers in the future (e.g., Azure Communication Services).
  • The implementation does not need to replicate SendGrid exactly, only provide local verification for email templates.
  • API and integration are unchanged for consumers of the package.

Related Code & References

With the help of below repo:-
https://github.com/CellixJs/cellixjs/tree/main

Take the reference of below files:-
packages/ocom/domain/src/domain/events/types/community-created.ts
packages/ocom/domain/src/domain/services/community/community-provisioning.service.ts
packages/ocom/domain/src/domain/contexts/community/community/community.ts
packages/ocom/event-handler/src/handlers/integration/community-created--provision-member-and-default-role.ts
apps/api/src/index.ts

Create an event for ReservationRequestCreation, should behave in a similar way to how community creation is handled in cellix, but the actual service being called by the event handler will have its functionality changed. It should instead fetch relevant infomration bout the user needed for the transactional-email-service function being called, then also taking a dependency and receiving a parameter of that service, in a similar way to how domaindatasource is passed down in the cellix service, call the transactional-email-servic and send an email to the sharer of the listing that the reservation request is connected to. So in simpler terms notifiying the listing owner that their listing was reserved.

Sub-issues

Metadata

Metadata

Labels

enhancementNew feature or request

Projects

Status

In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions