This FRD ships @dmwd-io/sms as an optional package that re-exports twilio as the platform standard for SMS messaging via Twilio. The value is standards and drift prevention, not a custom abstraction. Platform conventions (env var names, defaults) are documented on top of the library’s own API.
Introduction
Overview
Per ADR-014 (Open Source First), we designate twilio as the community library for SMS messaging and re-export it through @dmwd-io/sms without building a custom provider interface on top. The package documents the platform env var conventions — TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, and TWILIO_FROM_NUMBER — so all services initialize the client consistently. No custom XProvider interface is built; the twilio library’s own API is the interface.
Goals
Designate twilio as the platform standard for SMS messaging per ADR-014.
Re-export twilio through @dmwd-io/sms so all services import from one canonical location.
Document TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, and TWILIO_FROM_NUMBER as the platform env var conventions.
Include OTP and alert message templates with variable interpolation.
Non-Goals
Building a custom SmsProvider interface or adapter layer — the library’s own API is the interface (per ADR-014).
Implementing a production-ready AWS SNS adapter or other vendor adapters.
Managing phone number provisioning or carrier lookup.
Building an admin UI for SMS templates.
Handling MMS or rich media messages.
Scope
In Scope
Area
Description
Thin re-export
@dmwd-io/sms re-exports twilio as the platform standard
Template function producing a 6-digit OTP message with expiry
Alert template
Template function producing a plain-text alert notification
Template interpolation
String interpolation utility for custom templates
Unit tests
Coverage of template functions and re-export surface
Documentation
Storybook MDX docs with usage examples
Out of Scope
Area
Reason
Custom provider interface or adapter layer
ADR-014: library API is the interface
Vendor-specific adapters beyond Twilio
Twilio is the designated platform standard
Phone number validation
Handled by form-validation utilities
Delivery webhooks / inbound SMS
Requires server infrastructure not in scope for a library
Message queue integration
Consumer responsibility
Internationalization of templates
Deferred to i18n effort
Users and Pain Points
User Groups
User
Description
Needs
Application developers
Engineers building features that send SMS (OTP, alerts)
A stable, testable interface they can program against without coupling to a vendor SDK
QA engineers
Team members verifying SMS-dependent flows
A mock adapter that lets them assert on sent messages without real SMS delivery
Platform engineers
Engineers wiring production adapters
A clear contract so adapters are consistent and swappable
Pain Points
User
Pain Point
Impact
Application developers
Direct Twilio/SNS SDK calls scattered across services, each with different error handling
Vendor lock-in; inconsistent error handling; hard to test
QA engineers
No way to verify SMS content in automated tests without a real provider
Tests are slow, flaky, or skip SMS verification entirely
Platform engineers
No shared schema for delivery results; each service defines its own
Monitoring and alerting logic is duplicated and inconsistent
Definitions
Term
Definition
Provider
An object that implements the SmsProvider interface and sends messages through a specific channel (Twilio, SNS, mock)
Delivery result
A typed object describing the outcome of a send attempt: delivered, failed, pending, or rate-limited
OTP
One-Time Password: a short-lived numeric code sent via SMS for identity verification
Template
A function that accepts variables and returns a formatted message string
Mock adapter
An in-memory SmsProvider implementation that records messages for test assertions
Current State
Existing Behavior
There is no shared SMS abstraction. Individual services call vendor SDKs directly, each with ad-hoc error handling and result parsing.
Current Limitations
No contract interface exists; each service defines its own send function.
No typed delivery result schema; services parse vendor-specific responses inline.
No mock adapter; integration tests either skip SMS or use real providers with test credentials.
OTP message text is hardcoded in multiple places with inconsistent wording.
Existing Workarounds
Developers copy-paste Twilio initialization code between services.
Tests stub fetch or the vendor SDK at the HTTP level, which is brittle and vendor-coupled.
Proposed Solution
Summary
Ship @dmwd-io/sms as a thin re-export of twilio, designating it as the platform standard per ADR-014. No custom interface is built — the library’s API is the interface. The package adds only platform conventions on top: env var names and template utilities.
import { Twilio } from'@dmwd-io/sms';
const client = newTwilio(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN
);
await client.messages.create({
from: process.env.TWILIO_FROM_NUMBER,
to: '+15551234567',
body: createOtpMessage('123456', 10),
});
Platform env var conventions:
TWILIO_ACCOUNT_SID — Twilio account SID
TWILIO_AUTH_TOKEN — Twilio auth token
TWILIO_FROM_NUMBER — sender phone number in E.164 format
Key Capabilities
@dmwd-io/sms re-exports all exports from twilio verbatim.
createOtpMessage(code, expiryMinutes) and createAlertMessage(title, body) template functions.
interpolate(template, variables) utility for custom templates.
No custom provider interface or adapter layer.
User Experience
Not applicable (library, no UI).
Developer Experience
Developers import from @dmwd-io/sms instead of twilio directly, initialize the client with the documented env vars, and use template utilities for consistent message wording. The import path is the only convention enforced — the full twilio API is available.
Requirements
ID
Requirement
Priority
Notes
FR-001
The library must re-export twilio from @dmwd-io/sms
Must
Thin re-export per ADR-014
FR-002
The library must document TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_FROM_NUMBER as platform env vars
Must
Standards enforcement
FR-003
The library must provide OTP and alert template functions
Must
Variable interpolation
FR-004
The library should provide a generic interpolate utility
Should
For custom templates
FR-005
The library could ship a ConsoleSmsProvider for local dev logging
Could
Logs to stdout
Priority Definitions
Priority
Meaning
Must
Required for this feature to ship.
Should
Important, but can be deferred if needed.
Could
Nice to have. Not required for initial release.
Functional Requirements
ID
Requirement
User Benefit
Priority
FUNC-001
@dmwd-io/sms re-exports all named exports from twilio
Canonical import path for all SMS usage
Must
FUNC-002
Platform env var names are documented in the package README and Storybook docs
Consistent client initialization across services
Must
FUNC-003
createOtpMessage(code, expiryMinutes) returns a string containing the code and expiry
Consistent OTP wording across services
Must
FUNC-004
createAlertMessage(title, body) returns a formatted alert string
Consistent alert format
Must
FUNC-005
interpolate(template, vars) returns a string with variables substituted
Custom template support without string concatenation
Should
Non-Functional Requirements
ID
Requirement
Category
Priority
NFR-001
The library must have twilio as a peer dependency, not a bundled dependency
Maintainability
Must
NFR-002
All public types must be exported from the package entry point
Maintainability
Must
NFR-003
The library must not log or persist phone numbers by default
Security
Must
NFR-004
The library must support tree-shaking so consumers can import only what they need
All twilio exports are available via @dmwd-io/sms — no subset or wrapper.
Phone number format validation is the caller’s responsibility.
twilio must be installed by the consuming package; it is a peer dependency.
Accessibility Requirements
ID
Requirement
Notes
A11Y-001
Not directly applicable; this is a headless library
No UI surface
Checklist
Keyboard support is defined. (N/A — no UI)
Focus behavior is defined. (N/A — no UI)
Screen reader behavior is defined. (N/A — no UI)
Color contrast requirements are met. (N/A — no UI)
Reduced motion behavior is considered. (N/A — no UI)
Semantic HTML expectations are documented. (N/A — no UI)
ARIA usage is defined only where needed. (N/A — no UI)
Content and Documentation Requirements
ID
Requirement
Location
Priority
DOC-001
API reference with all exported types and functions
Storybook MDX
Must
DOC-002
Usage guide showing env var setup and client initialization
Storybook MDX
Must
DOC-003
Template function usage examples
Storybook MDX
Must
DOC-004
Template customization guide
Storybook MDX
Should
DOC-005
Migration guide for services currently calling twilio directly
Storybook MDX
Should
Documentation Should Include
Overview of the ADR-014 rationale (re-export, not custom interface)
When to use the library vs. direct SDK calls
Installation and peer dependency setup
Env var names and where to source them
Basic usage with createOtpMessage
Advanced usage: custom templates, batch sending
API reference for all exports
Common mistakes (e.g., not validating phone numbers before send)
Dependencies
Dependency
Type
Owner
Status
Notes
TypeScript 5.x
Engineering
David Holmes
Ready
Build toolchain
Vitest
Engineering
David Holmes
Ready
Test runner
twilio
Peer
Twilio
Ready
Platform standard per ADR-014
Risks and Tradeoffs
Risk / Tradeoff
Impact
Mitigation
Twilio API changes break consumers
Major version bumps in twilio may require updates across services
Pin twilio peer dependency range; communicate breaking changes in changelog
Template functions may be too rigid
Different products may need different OTP wording
Ship interpolate utility so consumers can build custom templates
No retry logic in the contract
Callers must implement their own retry
Keep the library focused on re-export and templates; retry is an application concern
Consumers bypass @dmwd-io/sms and import twilio directly
Drift re-emerges
Lint rule enforcing @dmwd-io/sms as the import path (future work)
Open Questions
ID
Question
Owner
Status
Resolution
Q-001
Should send accept an E.164 type or a plain string for phone numbers?
David Holmes
Open
—
Q-002
Should we ship a ConsoleSmsProvider for local dev in the initial release or defer?
David Holmes
Open
—
Q-003
Should an ESLint rule enforce @dmwd-io/sms over direct twilio imports?
David Holmes
Open
—
Acceptance Criteria
ID
Criteria
Related Requirement
AC-001
import { Twilio } from '@dmwd-io/sms' resolves correctly
FR-001
AC-002
TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_FROM_NUMBER are documented in the package README and Storybook
FR-002
AC-003
createOtpMessage("123456", 10) returns a string containing both the code and the expiry
FUNC-003
AC-004
createAlertMessage("Title", "Body") returns a formatted string with both arguments
FUNC-004
AC-005
All public types are re-exported from the package index
NFR-002
AC-006
Unit tests pass with full coverage of the template functions
FR-003
AC-007
Storybook MDX docs render without errors and include usage examples
DOC-001
LLM Handoff Instructions
Expected LLM Behavior
Follow the requirements and acceptance criteria in this document.
Do not expand scope beyond the In Scope section.
Respect the Out of Scope section.
Ask for clarification only when a requirement cannot be safely interpreted.
Prefer existing design system patterns over inventing new ones.
Preserve public API compatibility unless this document says otherwise.
Update documentation and Storybook examples when behavior changes.
Add or update tests that map to the acceptance criteria.
Implementation steps
Create the packages/sms/ directory if it does not exist.
Add package.json with twilio as a peer dependency and @dmwd-io/sms as the package name.
Create src/index.ts that contains export * from 'twilio' plus the template utilities.
Document env var names (TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_FROM_NUMBER) in the package README and Storybook MDX.
Run pnpm typecheck to confirm no type errors.
LLM Should Not
Build a custom SmsProvider interface or adapter layer — the twilio library’s API is the interface per ADR-014.
Connect to real SMS providers during tests.
Add new dependencies without justification.
Change unrelated components.
Include phone numbers or PII in test fixtures (use obviously fake numbers like +15550001234).
Implement retry or queue logic.
Decision Log
Date
Decision
Reason
Owner
2026-05-26
Use discriminated union for delivery results instead of status codes
Type narrowing makes caller error handling safer
David Holmes
2026-05-26
Zero runtime dependencies
Library must be lightweight and vendor-neutral
David Holmes
2026-05-26
Ship mock adapter as part of the library, not a separate package
Reduces friction for testing; mock is small
David Holmes
2026-06-02
Reframed per ADR-014 (Open Source First): adopt twilio as thin re-export rather than building a custom provider interface. Library API is the interface.
ADR-014 eliminates unnecessary abstraction over well-maintained community libraries
David Holmes
Document History
Date
Author
Change
2026-05-26
David Holmes
Initial draft
2026-06-02
David Holmes
Reframed per ADR-014: ship as thin re-export of twilio, drop custom interface.