Skip to content

Operate useSend as the multi-brand email platform #5

Description

@vladbisceanu

Current state

The production service is live at send.growthpath.systems from this public fork's growthpath-mail branch. Amazon SES production access is approved, the bisceanu.com sending identity and callback path are working, and the first product integration is prepared but must be reconciled with current bisceanu.com main before cutover.

Before real subscriber traffic, finish the native Railway health gate and a verified Postgres recovery path. Reconcile this fork with upstream v1.9.7 separately so the local BullMQ connection fix is not carried twice. Then deploy and prove the bisceanu integration before migrating the remaining products and retiring Loops.

Spec

Outcome. Self-hosted useSend on Railway is the shared email platform for bisceanu.com, growthpath.systems, heralded.ai, and Bookling marketing. One internal team owns the brands, separated by sending domain and contact book. It supports transactional sends and campaigns; product workflows remain in each product backend.

Phase 1. Operate useSend with Postgres and Redis at send.growthpath.systems, using Amazon SES in eu-west-1. Harden production, migrate the bisceanu contact form completely, and prove transactional delivery, campaign unsubscribe behavior, bounce suppression, and idempotent retries.

Phase 2. Migrate each remaining product through an independently closable issue in its repository. Product email that has a deliberate separate abstraction remains outside this program.

Done when. Every in-scope Loops send and list runs on useSend, deliverability is verified per brand from received mail, recoverability and health gates are proven, and the obsolete Loops accounts are closed.

Appetite. One focused slice for production hardening, one for the bisceanu cutover, then roughly two to four days across the remaining product repositories.

Design

  • Ownership: this fork owns the application and the complete service lifecycle: upstream reconciliation, pull requests, deployments, Railway, SES/SNS, sending-domain DNS, Postgres, Redis, backups, health, and this program.
  • Consumer boundary: each product repository owns its useSend integration, templates, runtime variables, product deployment, workflow scheduling, and acceptance proof.
  • Setup boundary: setup-works owns Builder OS, fleet setup, and shared credential plumbing only.
  • Access model: one internal team contains first-party sending domains and contact books. External customers do not receive dashboard accounts; customer-facing tenancy is a separate decision.
  • Hosting: Railway provides an isolated service lifecycle. send.growthpath.systems is the dashboard; mail.<sending-domain> remains available for SES custom MAIL FROM.
  • Delivery gate: every PR to growthpath-mail runs one stable GitHub Actions gate covering type-checking, tests, and the production Docker build. Protect the branch with that exact Actions context, required PRs, admin enforcement, no approval count, and no force-push or deletion bypass. Railway deploys only the protected post-merge push.
  • Readiness: startup fails closed on migration errors. Railway runs the migration command before deploy and waits for /api/health; that route uses bounded Postgres and Redis probes and reports the Railway commit SHA so provider metadata and live response identify the same artifact.
  • Migration safety: review every Prisma migration for compatibility with the still-running deployment. Use expand/contract changes when both versions can overlap; a backup is recovery evidence, not permission for a destructive migration.
  • Recovery: Railway PITR is the primary Postgres control. Wait for the initial base backup and healthy WAL coverage, then restore a named timestamp into a private sibling service. Attach no app or worker, validate only redacted schema and aggregate evidence, and delete the temporary service after proof.
  • Security and licence: the public AGPL fork remains the complete corresponding source. Provider callbacks stay authenticated, external requests bounded, and suppression and unsubscribe behavior preserved.
  • Data safety: pin application versions, review Prisma migrations, and verify a fresh recoverable Postgres backup before any production upgrade because startup applies migrations.
  • Idempotency: Redis protects short retry windows; product backends retain durable uniqueness for sends that must never repeat.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/infraDocker, CI, Railway, AWS, DNS, Postgres, Redis, and operationsarea/webapps/web: dashboard, API, delivery, campaigns, contactspriority/p1Next; a named piece of worktype/featureNew capability or a change to what the product does

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions