Skip to content

PRD: SMS campaigns

ModuleMarketing (EXT-02)PRD IDPRD-CMP-001
StatusPlannedOwnerMarketing squad
Date2026-03-13Versionv0.1
Packagesmq-sms · @nx/identity · @nx/coreURDCMP

TL;DR

Gives Marketing a real SMS delivery channel so messages reach customers' phones, not just a queue. A standalone mq-sms module wraps the VNPAY SMS provider, an ApplicationSMSComponent wires it into identity, and the first consumer - OTP request and verification - proves the channel end to end. This is the load-bearing send path that the planned campaign-to-segment send (URD-CMP-001) will reuse.

1. Context & Problem

The Marketing module's Campaigns & Automation feature needs a way to actually deliver messages to customers. Per the module Non-Goals, KICKO does not build its own delivery infrastructure - it integrates an external provider. Today there is no SMS send path at all: nothing in the platform can hand a text message to a carrier, so neither authentication (OTP) nor any future campaign can reach a customer's phone.

This increment stands up the SMS-delivery groundwork - a third-party provider integration, the application component that uses it, and provider/credential configuration - and exercises it with the first concrete consumer (OTP). The campaign-to-segment send itself is layered on top later; building the channel first unblocks both auth and marketing.

2. Goals & Non-Goals

Goals

  • Stand up an mq-sms third-party module wrapping the VNPAY SMS provider (request helpers, request/response models, controller).
  • Add an ApplicationSMSComponent to identity and integrate SMS sending into the application.
  • Load SMS provider configuration (credentials, environment) through the configuration service, with idempotent (upsert) seeding and tolerant migration handling.
  • Build the first SMS consumer - OTP request and verification - with an SMS OTP sender and a log-only sender for non-prod.

Non-Goals

  • The campaign-to-segment send itself (URD-CMP-001) - sending a planned campaign to a customer segment is layered on top of this channel, not in this increment.
  • Triggered / drip automation (URD-CMP-002) and A/B testing & reporting (URD-CMP-003).
  • Building delivery infrastructure beyond integrating the external VNPAY provider (per module Non-Goals).
  • Email / other-channel delivery.

3. Success Metrics

MetricTarget / signal
Channel availabilitySMS send path returns provider acceptance for valid requests; failures surfaced, not silently dropped
OTP deliverabilityOTP request → SMS delivered → verify succeeds end to end
Config safetyMissing/invalid SMS config does not crash startup; seeding is idempotent across restarts
Reuse readinessThe same channel is callable by a future campaign sender with no provider rework

4. Personas & Use Cases

PersonaGoal in this feature
Customer (recipient)Receive an OTP (and later, campaign messages) on their phone
End user authenticatingRequest and verify an OTP to complete sign-in
Owner / Manager (Marketing)Eventually reuse this channel to reach segments via campaigns
Platform operatorConfigure VNPAY credentials/environment without redeploying code

Core scenarios: configure the VNPAY SMS provider once → an application flow (OTP request) asks the SMS channel to send → mq-sms builds an encrypted VNPAY request and dispatches it → the recipient gets the text → OTP verify confirms the code.

5. User Stories

  • As an end user authenticating, I want to receive an OTP by SMS and verify it, so that I can complete sign-in securely.
  • As a platform operator, I want SMS provider credentials and environment loaded from configuration, so that I can switch providers/environments without a code change.
  • As a platform operator, I want missing SMS config to be tolerated at startup, so that environments without SMS don't break boot.
  • As a Marketing owner, I want a reusable SMS send channel, so that the planned campaign-to-segment send can reach customers without new provider work.
  • As a developer, I want a log-only sender in non-prod, so that I can exercise SMS flows without spending real messages.

6. Functional Requirements

#RequirementURD ref
FR-1Provide an mq-sms third-party module exposing an SMS send path (controller + request/response models)URD-CMP-001
FR-2Integrate the VNPAY SMS provider via request helpers and VNPAY constants/typesURD-CMP-001
FR-3Encrypt SMS payloads before dispatch to the providerURD-CMP-001
FR-4Expose an ApplicationSMSComponent in identity that the application calls to send SMSURD-CMP-001
FR-5Load SMS provider config (credentials, environment) via the configuration service, seeded with upsert (idempotent)URD-CMP-001
FR-6Tolerate missing SMS configuration at startup/migration without failing bootURD-CMP-001
FR-7Provide OTP request and verification on top of the SMS channel, with an SMS OTP sender and a log-only sender for non-prodURD-CMP-001
FR-8Centralize OTP configuration in the configuration service; hash OTP secrets via Bun.passwordURD-CMP-001

Full requirement text and acceptance criteria live in the Marketing URD. This PRD references them rather than restating them.

7. Non-Functional Requirements

AreaRequirement
SecuritySMS payloads are encrypted before reaching the provider; OTP secrets are hashed (Bun.password), never stored in clear
ConfigurabilityProvider credentials/environment live in configuration, not code; switchable without redeploy
ResilienceMissing/invalid SMS config is tolerated at startup; failures surface rather than crashing the application
IdempotencyConfig seeding uses upsert - repeated startups/migrations converge to one record
ObservabilityA log-only sender exists for non-prod so flows are testable without real sends
i18nUser-facing OTP messaging supports bilingual content ({ en, vi })

8. UX & Flows

This channel has no merchant-facing screen of its own in this increment; it is invoked by application flows (OTP today, campaign send later). Provider credentials are managed through configuration.

9. Data & Domain

EntityRole
SMS request / response modelsShape of an outbound SMS and its provider acknowledgement (mq-sms)
TMQSMSClientConfigProvider client configuration type (credentials, endpoint)
SMS provider configPer-environment provider settings in the INTEGRATION config group, with environment field
OTP configCentralized OTP settings in the configuration service
OTP recordThe issued/hashed OTP used by request + verify

Conceptual only - full schema and provider detail live in the developer outreach docs.

10. Dependencies & Assumptions

Depends on

  • VNPAY SMS provider - the external carrier integration the channel wraps.
  • @nx/core configuration service - provider/OTP config loading, upsert seeding, migrations.
  • @nx/identity - hosts the ApplicationSMSComponent and the OTP controller/service.

Assumptions

  • Valid VNPAY SMS credentials and an environment are provided per deployment (or SMS is intentionally disabled).
  • Bun.password is available for OTP hashing.
  • A future campaign sender will reuse this channel rather than integrating a provider of its own.

11. Risks & Open Questions

Risk / questionMitigation / status
Campaign-to-segment send (URD-CMP-001) is not yet built on this channelChannel + OTP shipped first; campaign send is the next increment - PRD stays planned until then
Single provider (VNPAY) couplingChannel abstracts the provider behind mq-sms; a second provider can slot in behind the same component
Missing SMS config could break bootStartup/migration made tolerant of absent SMS config
Provider outage / delivery failureFailures surfaced to callers; non-prod uses log-only sender
Cost of real sends during testingLog-only sender for non-prod environments

12. Release Plan & Launch Criteria

AspectPlan
PhaseP2 - SMS delivery channel for Campaigns & Automation
RolloutChannel available where VNPAY config is present; OTP consumer enabled in identity
MigrationSMS provider config seeded into the INTEGRATION config group via upsert; environment field added; tolerant of missing config
Launch criteriaOTP request → SMS delivered → verify verified end to end; config seeding idempotent across restarts; missing config does not break startup
MonitoringSMS send success/failure rate, OTP verify success rate, provider error responses

13. FAQ

Does this send marketing campaigns to customers yet? No. This increment delivers the SMS channel and its first consumer (OTP). The campaign-to-segment send (URD-CMP-001) is layered on top in a later increment - which is why this PRD is still planned.

Why is OTP here if this is a Marketing PRD? OTP is auth-facing, but it is the first and load-bearing consumer of the exact SMS channel that campaigns will reuse. Proving the channel through OTP de-risks the marketing send.

Which provider does it use? VNPAY SMS, wrapped by the mq-sms third-party module. The provider sits behind the channel so it can be swapped or extended.

How are credentials managed? Through the configuration service (INTEGRATION group), with an environment field and idempotent upsert seeding - no redeploy needed to change them.

What happens in non-prod or when SMS isn't configured? A log-only sender stands in for real sends, and missing SMS config is tolerated at startup so boot doesn't fail.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.