Skip to main content

SPEC 021 — Notifications

FieldValue
StatusVERIFIED
PriorityP2
Backendequa-server/modules/notifications/
FrontendN/A (backend-only — emails rendered server-side)
Verified2026-02-28 (13/13 tasks PASS, 9/9 ACs PASS)

1. Feature Purpose

The Notifications module handles all outbound transactional email for the Equa platform. It implements a Notifier interface (from common) that accepts a user ID and a notification object, renders HTML from Handlebars templates, and delivers via a configurable transport layer. Every critical user journey — sign-up verification, magic link login, team invitations, password resets, and support contacts — depends on this module.

2. Current State (Verified)

2.1 Transport Configuration

DetailValue
LibraryNodemailer
Transport selectionEMAIL_TRANSPORTER env var (see table below)
AWS SESRegion from AWS_SES_REGION (default us-east-1); API version 2010-12-01
SMTPConfigured via SMTP_HOST, SMTP_PORT, SMTP_SECURE, SMTP_USER, SMTP_PASS
Buffer (dev)Saves emails as .eml + .txt files in temp/ directory
No-OpEMAIL_TRANSPORTER=none disables all sending
From addressFROM_EMAIL_NAME (default Equa) + FROM_EMAIL_ADDRESS (default equabot@equastart.io)
Global BCCOptional GLOBAL_BCC (comma-separated) for compliance/audit copies

Transport Selection Logic (services.ts:96-113)

EMAIL_TRANSPORTER ValueTransportNotes
(unset/empty)AWS SESDefault production transport
smtpSMTP (Nodemailer)Uses SMTP_* env vars
devBufferSaves to temp/ as .eml + .txt
noneNo-Op (emptyNotifier)Disables all email sending

2.2 Template Engine

DetailValue
EngineHandlebars (.handlebars files)
Template directoryequa-server/modules/notifications/src/templates/ (10 files)
Partial directoryequa-server/modules/notifications/src/partials/ (3 files)
CompilationnoEscape: true — templates compiled at startup, cached in memory
Data bindingTemplate variables passed as context object per send call

2.3 Email Templates (10)

TemplatePartialConsumerTrigger
magicLinkmainauthUser requests magic link login
emailVerificationmainauthUser registers or changes email
passwordResetmainauthUser requests password reset
passwordChangedmainauthPassword successfully changed
userInvitationmainNewreferralUser invited to platform
sendCompanyInfomainreferralCompany information shared
organizationInvitationmainNeworganizations, adminUser invited to organization
organizationInvitationConvertiblemainNew(no active consumer)Convertible instrument invitation
contactSupportmainbillingSupport request submitted
adminOrganizationCreatedmainOrgorganizationsNew organization created

2.4 Layout Partials (3)

PartialStyleUsed By
mainGreen Equa brand (#33BB40), 538px width, confidentiality footer6 templates
mainNewDark header (#304651), Nunito Sans, 600px responsive, dark/light mode3 templates
mainOrgOrganization-branded, 100% width, Nunito Sans, minimal1 template

2.5 Environment Variables

VariableRequiredDefaultSource
EMAIL_TRANSPORTERNo(SES)services.ts:96
AWS_ACCESS_KEY_IDIf SESaws.ts:17
AWS_SECRET_ACCESS_KEYIf SESaws.ts:18
AWS_SES_REGIONNous-east-1services.ts:110
SMTP_HOSTIf SMTPmail.equastart.ioservices.ts:88
SMTP_PORTIf SMTP465services.ts:89
SMTP_SECUREIf SMTPtrueservices.ts:90
SMTP_USERIf SMTP''services.ts:91
SMTP_PASSIf SMTP''services.ts:92
FROM_EMAIL_NAMENoEquaservices.ts:140
FROM_EMAIL_ADDRESSNoequabot@equastart.ioservices.ts:141
GLOBAL_BCCNoservices.ts:116

3. Data Model

The Notifications module does not maintain its own persistent entities. Sent emails are fire-and-forget. Related entities that trigger notifications:

EmailVerifications (from SPEC 001)

ColumnTypeConstraints
useruuidFK to Users
codevarcharVerification code sent via email

TempPasswords (from SPEC 001)

ColumnTypeConstraints
useruuidFK to Users
passwordHashvarcharTemporary password hash for reset flow

Invitations (from SPEC 012)

ColumnTypeConstraints
iduuidPK
emailvarcharInvitee email address
organizationuuidFK to Organizations
invitedByuuidFK to Users
statusvarcharpending, accepted, expired

4. Module Interface

The module exposes a Notifier factory, not direct API endpoints:
ExportTypeDescription
newNodeMailerNotifierFactoryCreates a Notifier from transport, templates, and user lookup
newNodemailerSesTransporterFactoryCreates SES-backed transport
newNodemailerSmtpTransporterFactoryCreates SMTP transport
newNodemailerBufferTransporterFactoryCreates buffer transport for testing
combineNodeMailerMethodsUtilitySends via multiple transports simultaneously
newEmailTemplateMapFactoryLoads and compiles all Handlebars templates
newSesClientFactoryCreates AWS SES client
newAwsConnectionConfigFactoryBuilds AWS config from environment
Consumer modules receive a Notifier function via dependency injection and call it with a user ID and notification object containing the template name, subject, and template arguments.

5. Frontend Components

None. All email content is rendered server-side using Handlebars templates. Users interact with notifications only through their email client.

6. Business Rules

  1. Transport selectionEMAIL_TRANSPORTER env var selects transport; unset defaults to SES; none disables sending entirely.
  2. Global BCC — When GLOBAL_BCC is set, every outbound email is BCC’d to those addresses for compliance.
  3. Template caching — Templates compiled once at startup; changes require server restart.
  4. No retry on failuresendMail() is called with no retry or dead letter queue.
  5. SES sandbox — In sandbox mode, emails can only reach verified addresses; production requires SES production access.
  6. Rate limiting — Deferred to transport providers (SES/SMTP enforce their own limits).
  7. noEscape renderinghandlebars.compile(template, { noEscape: true }) renders all variables as raw HTML. Intentional for HTML emails; template variables must be sanitized upstream.
  8. From address — All emails use the same sender; per-organization customization is not supported.
  9. No delivery tracking — The module does not track delivery status, opens, or clicks.

7. Acceptance Criteria

  • AC-1: All source files documented with exact line references
  • AC-2: Notifier interface and flow documented
  • AC-3: All 3 transport types documented (SES, SMTP, Buffer)
  • AC-4: Template system documented (loading, rendering, partials)
  • AC-5: All 10 email templates catalogued with purpose and consumers
  • AC-6: All 3 layout partials documented
  • AC-7: AWS SES configuration documented with environment variables
  • AC-8: All consumer modules identified
  • AC-9: Deployment mapping covers desktop, staging, and production

8. Risks

RiskImpactMitigation
Missing magicLink in authNotificationTemplatesHigh — magic link emails throw at runtimeAdd magicLink: 'magicLink' to auth/src/types.ts
aws-sdk v2 deprecationMedium — SDK in maintenance modeMigrate to @aws-sdk/client-ses v3
No retry/queue mechanismMedium — critical emails silently lost on failureAdd dead-letter queue or retry for critical email types
noEscape: true in HandlebarsMedium — XSS risk if user content injectedSanitize template variables upstream
Mandrill dead codeLow — commented-out implementation still exportedRemove dead mandrill code
organizationInvitationConvertible unusedLow — template exists with no active consumerVerify if captable should use it; deprecate if not