# CareMeet — consultation link delivery

Patients receive their consultation link over WhatsApp, SMS or email. The doctor console currently copies the link; this makes it automatic.

## Architecture

```
API creates room ──> notifications row (status: queued)
                              │
                     notification_worker.php  (systemd daemon)
                              │
              ┌───────────────┼───────────────┐
        WhatsApp Cloud      SMS gateway     email
```

Dispatch is deliberately **out of the request path**. A slow WhatsApp API call must never sit inside the request that creates a consultation, or a Meta outage becomes a booking outage.

## Two things that will bite you — plan around them now

**WhatsApp templates need Meta approval, and it takes days.** Business-initiated messages cannot be free text; they must use a pre-approved template. Healthcare wording gets scrutinised. Templates must be registered as **UTILITY**, not MARKETING, or delivery is throttled. Meta bills per conversation window.

*Consequence for sales:* do not promise a hospital WhatsApp delivery on day one of go-live. Plan for SMS to carry the first month while templates clear review. Submit templates the day a client signs, not the week they go live.

**Indian SMS requires TRAI DLT registration** of both the sender header and the exact message template. An unregistered template is **dropped silently by the carrier** — it does not bounce, it does not error, it simply never arrives. This is the hardest delivery failure to diagnose, so when SMS "isn't working", check DLT registration before anything else.

## Message content rule

Templates carry no clinical detail. A consultation link arriving on a shared family phone must not disclose why the patient is seeing a doctor. Name, hospital, time, link — nothing more. The default templates follow this; keep tenant overrides to the same standard.

The link points to a token-minting page, never to a token. A forwarded message must not be a working set of call credentials.

## Patient OTP join

Where a hospital enables `require_patient_otp`, the token endpoint returns `otp_required` instead of a token. The patient enters a 6-digit code sent to the number the appointment was booked against.

The threat is mundane and real: consultation links get forwarded in family WhatsApp groups. OTP binds the join to the registered phone.

Codes expire in 10 minutes, allow 5 attempts, then burn. Resend has a 60-second cooldown.

## Provider credentials

Per-tenant WhatsApp tokens and SMS keys are stored encrypted with AES-256-GCM (`Core/Crypto.php`). The master key lives in config, outside the web root, never in the database — a database dump alone must not yield working credentials for every hospital on the platform.

Generate it once:

```bash
php -r "echo base64_encode(random_bytes(32));"
```

Rotating this key invalidates every stored provider secret. Every hospital must re-enter theirs.

## Deploy

```bash
mysql caremeet < caremeet_schema_notifications.sql
systemctl enable --now caremeet-notifications
```

One worker is plenty at current volume. It is stateless — run more if the queue backs up.
