diff --git a/README.md b/README.md index 05b4bc08..58dfc4a4 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ WaboSign is a fork of [DocuSeal](https://github.com/docusealco/docuseal) under A - Mobile-optimized signing flow - 14 UI languages - API + Webhooks for integrations -- SMS invitations / verification +- SMS invitations via [BulkVS](SMS.md) - Bulk send via CSV / XLSX import - Google Workspace SSO ([setup guide](GOOGLE_SSO.md)) - Conditional fields and formulas diff --git a/SMS.md b/SMS.md new file mode 100644 index 00000000..622194ea --- /dev/null +++ b/SMS.md @@ -0,0 +1,104 @@ +# SMS + +WaboSign sends signing-invitation SMS via configurable providers. v1 ships [BulkVS](https://www.bulkvs.com) only; the architecture leaves room for additional providers behind the same `Sms.send_message` interface. + +## What you get + +- A self-serve `/settings/sms` page where admins paste their BulkVS Basic Auth header and From number. +- A **Send test** card on the same page for verifying the config with a one-off SMS to any phone number. +- Per-submitter **Send SMS** button on the submission detail page (`/submissions/:id`). +- "Send SMS on save" toggle in the submitter edit dialog — already wired into `SubmittersController#maybe_resend_email_sms`, now actually fires the job. +- Per-account body template override at `/settings/personalization` → "Signature request SMS". Supports `{account.name}`, `{submitter.link}`, `{submitter.name}`, `{submitter.first_name}`, `{submission.name}`, `{sender.name}` and the rest of the existing `ReplaceEmailVariables` vocabulary. +- Sidekiq job (`SendSubmitterInvitationSmsJob`, retry: 5) so a failed BulkVS request retries on its own. + +## Configuring BulkVS + +In the [BulkVS portal](https://portal.bulkvs.com/), open the **API** tab and copy the pre-encoded **Basic Auth Header** value (it's a single base64 string like `dXNlcjp0b2tlbg==`; do NOT include the literal `Basic ` prefix). + +In WaboSign: +1. Sign in as an admin → **Settings** → **SMS**. +2. Toggle **Enable SMS** on. +3. Paste the BulkVS Basic Auth token. +4. Set **From Number** in E.164 (digits-only with country code, e.g. `15551234567`). +5. *(Optional)* set the **Delivery Status Webhook** to a URL BulkVS will POST status events to. WaboSign does not yet process these inbound events — the field is stored on the config and forwarded to BulkVS so the receipts flow somewhere of your choosing. +6. Save. +7. Use the **Send test** card to verify with a number you own. Errors from BulkVS (bad credentials, malformed number, etc.) come back as `Sms::ProviderError` and are shown inline. + +## How sending happens + +``` +User clicks "Send SMS" on /submissions/:id + → SubmittersSendSmsController#create + → SendSubmitterInvitationSmsJob.perform_async (Sidekiq, retry: 5) + → Sms.send_message(account:, to:, text:) + → Sms::Providers::Bulkvs#deliver + → HTTPS POST to https://portal.bulkvs.com/api/v1.0/messageSend + → returns BulkVS JSON + → SubmissionEvent.create!(event_type: 'send_sms') + → Submitter.sent_at ||= Time.current +``` + +The "send SMS on save" toggle in the submitter edit dialog takes the same code path via [SubmittersController#maybe_resend_email_sms](app/controllers/submitters_controller.rb). + +Body substitution runs through the existing [`ReplaceEmailVariables`](lib/replace_email_variables.rb) module. The account-level template at `submitter_invitation_sms` overrides the i18n default `submitter_invitation_sms_body_sign` when set. + +## Adding another provider + +Two-step extension: + +1. **Implement the provider class** at `lib/sms/providers/.rb`. The interface is `#new(config)` + `#deliver(to:, text:, webhook: nil)`. Raise `Sms::ProviderError` on non-2xx responses. See [`lib/sms/providers/bulkvs.rb`](lib/sms/providers/bulkvs.rb) for shape. + +2. **Register the provider** in three places: + - `Sms::SUPPORTED_PROVIDERS` in [`lib/sms.rb`](lib/sms.rb). + - The `case provider` switch in `Sms.send_message`. + - The `