Skip to content

Add SMS adapter with pluggable backends (Twilio first) #14

Description

@joamag

Problem (Why)

Pushi has no SMS delivery path, so use cases like OTPs, alerts and transactional messages fall outside the platform even though the pub/sub, subscription and routing machinery is already in place. SMS providers vary by region and cost, so hard-wiring a single vendor would force a rewrite later. A pluggable SMS adapter with Twilio as the first backend gives immediate coverage while keeping the door open for additional providers (e.g. Vonage, AWS SNS).

Description (What)

Introduce an SMSHandler adapter with a small provider abstraction so concrete backends can be selected via configuration, shipping Twilio as the first backend. An SMS subscription model stores a destination phone number per subscription, overridable per published event. Twilio credentials (account SID, auth token, from-number) follow the existing App-model + environment-variable configuration pattern.

Implementation (How)

  1. Define an SMS backend abstraction (a small SMSBackend base with a send_sms(to, message, **opts) method) plus a TwilioBackend implementation, selected by config, in src/pushi/base/sms.py.
  2. Add SMSHandler(handler.Handler) implementing load, add, remove, subscribe, unsubscribe, send(app_id, event, json_d, invalid={}) and a direct send_to_numbers(...); resolve the active backend and honor per-event number overrides over the stored subscription number.
  3. Call the Twilio Messages REST API via netius.clients.HTTPClient with HTTP basic auth, consistent with existing HTTP usage.
  4. Add App-model config fields in src/pushi/app/models/app.py (sms_provider, twilio_sid, twilio_token, twilio_from) with global env-var fallbacks via appier.conf.
  5. Add the SMS subscription model in src/pushi/app/models/sms.py with fields (number, event) and handler-sync lifecycle hooks.
  6. API: add an SMSController in src/pushi/app/controllers/sms.py exposing GET/POST /sms and DELETE /sms/<number> (list/subscribe/unsubscribe).
  7. API client: add SMSAPI in src/pushi/api/sms.py with create_sms / delete_sms / subscribe_sms / unsubscribe_sms.
  8. Register the handler in State.load_handlers() in src/pushi/base/state.py and export new symbols from the four __init__.py files.
  9. Add tests in src/pushi/test/sms.py (backend selection, Twilio payload/auth, per-event override, subscription sync) using the mock-owner pattern.
  10. Update README.md, add an examples/sms/ example, and add a [Unreleased] CHANGELOG entry.

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions