|
| 1 | +# Avalanche Canada SMS Service |
| 2 | + |
| 3 | +A serverless application that lets users text their GPS coordinates to a phone number and receive a summary of current avalanche conditions from [Avalanche Canada](https://avalanche.ca) for that location. |
| 4 | + |
| 5 | +## How It Works |
| 6 | + |
| 7 | +1. Text your coordinates (e.g. `51.04, -115.06`) to the service phone number |
| 8 | +2. The server identifies which Avalanche Canada forecast region covers that location |
| 9 | +3. You receive an SMS reply with the current danger ratings and avalanche problems |
| 10 | + |
| 11 | +Example reply (fits in a single 160-character SMS): |
| 12 | + |
| 13 | +``` |
| 14 | +Kananaskis |
| 15 | +Feb 23 |
| 16 | +Alp:Considerable TL:Moderate BT:Low |
| 17 | +Storm Slabs, Wind Slabs |
| 18 | +avalanche.ca |
| 19 | +``` |
| 20 | + |
| 21 | +## Tech Stack |
| 22 | + |
| 23 | +- **Runtime:** Node.js / TypeScript |
| 24 | +- **Framework:** [Hono](https://hono.dev) (runs on Cloudflare Workers or AWS Lambda) |
| 25 | +- **SMS:** [Twilio](https://twilio.com) |
| 26 | +- **Data Source:** [Avalanche Canada API](https://api.avalanche.ca) |
| 27 | +- **Summarization:** Template-based (no LLM) |
| 28 | + |
| 29 | +## Setup |
| 30 | + |
| 31 | +### Prerequisites |
| 32 | + |
| 33 | +- Node.js 20+ |
| 34 | +- A Twilio account with a phone number |
| 35 | +- Cloudflare account (for Workers deployment) or AWS account (for Lambda) |
| 36 | + |
| 37 | +### Install |
| 38 | + |
| 39 | +```bash |
| 40 | +npm install |
| 41 | +``` |
| 42 | + |
| 43 | +### Environment Variables |
| 44 | + |
| 45 | +Copy the example file and fill in your Twilio credentials: |
| 46 | + |
| 47 | +```bash |
| 48 | +cp .env.example .env |
| 49 | +``` |
| 50 | + |
| 51 | +See [.env.example](./.env.example) for all available variables. |
| 52 | + |
| 53 | +### Development |
| 54 | + |
| 55 | +```bash |
| 56 | +npm run dev |
| 57 | +``` |
| 58 | + |
| 59 | +This starts a local Wrangler dev server. Set `VALIDATE_TWILIO_SIG=false` in your `.env` to skip Twilio signature checks during local development. |
| 60 | + |
| 61 | +### Test |
| 62 | + |
| 63 | +```bash |
| 64 | +npm test |
| 65 | +``` |
| 66 | + |
| 67 | +### Deploy to Cloudflare Workers |
| 68 | + |
| 69 | +1. **Authenticate with Cloudflare:** |
| 70 | + |
| 71 | + ```bash |
| 72 | + npx wrangler login |
| 73 | + ``` |
| 74 | + |
| 75 | + This opens a browser window for OAuth. You only need to do this once. |
| 76 | + |
| 77 | +2. **Set Twilio secrets:** |
| 78 | + |
| 79 | + ```bash |
| 80 | + npx wrangler secret put TWILIO_ACCOUNT_SID |
| 81 | + npx wrangler secret put TWILIO_AUTH_TOKEN |
| 82 | + ``` |
| 83 | + |
| 84 | + You'll be prompted to enter each value. These are stored encrypted and never appear in your code or config. |
| 85 | + |
| 86 | +3. **Deploy:** |
| 87 | + |
| 88 | + ```bash |
| 89 | + npm run deploy |
| 90 | + ``` |
| 91 | + |
| 92 | + Wrangler will output the deployed URL (e.g. `https://avalanche-canada-sms.<your-subdomain>.workers.dev`). |
| 93 | + |
| 94 | +4. **Configure Twilio webhook:** |
| 95 | + |
| 96 | + In the [Twilio console](https://console.twilio.com/), go to your phone number's configuration and set the incoming message webhook to: |
| 97 | + |
| 98 | + ``` |
| 99 | + https://avalanche-canada-sms.<your-subdomain>.workers.dev/sms/incoming |
| 100 | + ``` |
| 101 | + |
| 102 | + Method: `HTTP POST` |
| 103 | + |
| 104 | +5. **Test end-to-end:** Send an SMS with coordinates to your Twilio number and verify you receive a forecast reply. |
| 105 | + |
| 106 | +**AWS Lambda:** Use your preferred Lambda deployment tool (SST, Serverless Framework, etc.) with the [Hono AWS Lambda adapter](https://hono.dev/docs/getting-started/aws-lambda). |
| 107 | + |
| 108 | +## Admin Dashboard |
| 109 | + |
| 110 | +Access the status dashboard at `/admin` to view live health checks of dependent services: |
| 111 | + |
| 112 | +- **Avalanche Canada API** — verifies the forecast endpoint is responding |
| 113 | +- **Twilio** — verifies credentials are valid and the API is reachable |
| 114 | + |
| 115 | +Shows overall status (ok / degraded / down), per-service status with latency, and auto-refreshes every 30 seconds. |
| 116 | + |
| 117 | +## Supported Input Formats |
| 118 | + |
| 119 | +- Raw coordinates: `51.0447 -115.0632` or `51.0447, -115.0632` or `51.0447N 115.0632W` |
| 120 | +- iOS location sharing (Apple Maps links) |
| 121 | +- Android location sharing (Google Maps links, including shortened `maps.app.goo.gl` URLs) |
| 122 | + |
| 123 | +## Documentation |
| 124 | + |
| 125 | +- [SPECIFICATION.md](./SPECIFICATION.md) — full technical specification |
| 126 | +- [CLAUDE.md](./CLAUDE.md) — development guidelines for Claude Code |
0 commit comments