Skip to content

Goal: Invitation Mail Server

Wire the deployment of a partition-level system email server into partition creation and update, and deliver the common-module library classes that let any Module / Component send emails through it — analogous to how common-module provides the classes any Module / Component uses to access a database. The first intended consumer is the invitation flow (today the inviting user must copy/paste the invitation message); adopting the capability in accounts is a follow-up project, not part of this one.

RepositoryRolePlanned Changes
infrastructurePartition provisioning (CDK, amm.sh)Provision the system email server (domain system.{partition}.{base}) as part of partition creation/update, extending the Phase-4 partition-email deliverables (stacks/purpose/partition-email.ts, amm.sh email steps); deliver the server token to consuming components as a secret
common-moduleShared Kotlin libraryPrimary code deliverable: email-sending library classes usable by any Module / Component, configured from the partition-provisioned secret (analogous to the database-access classes)
operationsBackend componentRuntime wiring needed for components to consume the capability (e.g., Helm/ESO secret projection, configuration surface); exact scope determined during design
documentationProject artifacts + current-system docsProject documents under roadmap/system/messaging/invitation-mail-server/; updates to current-system runtime/OAM email pages
  1. Creating or updating a partition provisions (idempotently) the partition’s system email server on domain system.{partition}.{base}, with its server token generated at deployment and delivered to consuming components as a secret — never stored in the database.
  2. common-module publishes library classes with which any Module / Component can send email through the partition’s system server, demonstrated by an integration-tested sending path.
  3. Provisioning is repeatable and drift-checked consistently with the existing partition-email infrastructure.
  4. All changes ship with tests, CHANGELOG entries, and documentation updates per repository conventions.

Current invitation flow — documented in Invite User to Tenant. The Invitation entity lives in the Accounts component; on invite the system generates an invitation URL and a sample message that the inviting user must send manually (MVP2 constraint 2). This project delivers the sending capability; the follow-up accounts adoption project retires the manual step.

Email infrastructure — this project builds directly on the completed email-integration project:

  • Phase 4 (Runtime Platform Updates) landed per-partition mail sub-zones ({partition}.ardamails.com), per-partition Postmark account-token and encryption-key secrets, and IAM roles — provisioned through amm.sh and stacks/purpose/partition-email.ts in infrastructure.
  • Phase 5a shipped the supporting common-module APIs (TokenCipher, idempotency helpers, AppError.Application, sanitizeHeader).
  • Phase 5b shipped the ShopAccess/Email module in operations (per-tenant Postmark server provisioning, sending, webhook handling).

What is missing: a system-owned email server per partition for administrative mail, provisioned as part of partition creation/update rather than tenant onboarding, and a reusable library through which any component sends mail with it.

Deliberate simplification vs. per-tenant email. The per-tenant path (email-integration DQ-012) encrypts tenant server tokens in the database because tenants are created at runtime. The system server has no per-tenant configurability: its token is generated at partition deployment, delivered to the components that need it as a secret, and never stored in the database — so none of the token-encryption machinery applies to this project.

Standing decisions that do apply (see the email-integration decision log):

  • Mail root domain ardamails.com, parametrized everywhere (DQ-009). The system sending domain is fixed at design time as system.{partition}.{base} with base = ardamails.com.
  • Secret delivery via opamm.sh → CFN NoEcho parameter → Secrets Manager → ESO (documented in secret-delivery-pattern).
  • Operator surfaces integrated into amm.sh, not standalone CLIs (DQ-R1-022).
  • System email server provisioning (domain system.{partition}.{base}) as part of partition create/update (infrastructure).
  • Server-token generation at partition deployment and delivery to consuming components as a secret.
  • common-module email-sending library classes usable by any Module / Component.
  • Runtime wiring in operations needed to consume the capability, as the design requires.
  • Documentation: project artifacts, current-system updates, operator notes.
  • accounts changes — adopting the capability in the invitation flow is a follow-up project; MVP2 constraint 2 of Invite User to Tenant is retired there, not here.
  • Per-tenant email capabilities and token encryption (delivered by email-integration Phase 5b; not applicable to the system server).
  • New corporate/marketing sending domains (Phase 3 scope).
  • Changes to the invitation lifecycle (states, transitions, entities).
  • Frontend changes.
  1. Follow the established email-integration architecture: thin-wrapper Postmark constructs, amm.sh idempotency/security rules, secret-delivery pattern, CFN stack-name immutability.
  2. The system sending domain is system.{partition}.{base} with the base domain parametrized (ardamails.com today, per DQ-009).
  3. The system server token is never stored in the database; it reaches consumers only as a deployment-delivered secret.
  4. No breaking changes to the deployed partition-email stacks; changes must cdk diff clean-or-additive against deployed partitions.
  5. Rollout follows the established partition order: dev → {stage || demo} → prod.
  6. Postmark accounts: production partitions on PostmarkProd, non-production on PostmarkNonProd.

Copyright: (c) Arda Systems 2025-2026, All rights reserved