merge the sms-service spec docs
This commit is contained in:
105
progress/tech/PROJECT-sms-notifications-checklist.md
Normal file
105
progress/tech/PROJECT-sms-notifications-checklist.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# SMS Notification Service — Cross-Repo Project
|
||||
|
||||
You have full read-write access to everything under this project directory.
|
||||
|
||||
## Repos
|
||||
|
||||
- **sms-service** — New Deno/Hono service (the primary implementation target)
|
||||
- **endorser-ch** — Reference for API patterns, auth middleware, DB conventions. Minimal changes expected (no new endpoints needed for Phase 1).
|
||||
- **crowd-funder-for-time-pwa** — Time Safari app (Vue/Capacitor). UI integration for phone registration and notification settings.
|
||||
- **README-gift-economies** — Project docs. Full spec at `progress/tech/PROJECT-sms-notifications.md`.
|
||||
|
||||
## Full Spec
|
||||
|
||||
Read `README-gift-economies/progress/tech/PROJECT-sms-notifications.md` for the complete design. Key decisions already made:
|
||||
|
||||
- **Auth for user requests**: Forward caller's JWT to endorser-ch `GET /api/v2/report/rateLimits` to validate and extract DID. No DID resolver needed in the SMS service.
|
||||
- **Auth for scheduled endorser-ch calls**: User generates a long-lived JWT; the app sends it to the SMS service when notifications are enabled. The SMS service stores it and uses it for `alertSearch` calls.
|
||||
- **Long-lived JWT lifecycle**: Not sent at registration. Sent when notifications are enabled. App refreshes it (e.g., every 90 days) by checking expiry on settings screen open.
|
||||
- **Verification**: 6-digit code, 15-minute expiry, new code overrides old, max 3 codes/hour with 1-hour cooldown after limit. Phone must be verified before any notification can be enabled.
|
||||
- **Database**: SQLite (consider SQLCipher for encryption at rest).
|
||||
- **SMS provider**: Twilio, behind an interface for swappability.
|
||||
- **UI**: Side-by-side notification channels — group by notification type (daily reminder, activity digest), show on-device and SMS as peer delivery channel rows.
|
||||
|
||||
## Implementation Plan — Phase 1: Core Infrastructure
|
||||
|
||||
### Step 1: sms-service project scaffolding
|
||||
- [x] Initialize Deno + TypeScript project in `sms-service/`
|
||||
- [x] Set up `src/`, `test/`, `sql/` directory structure
|
||||
- [x] Add dependencies: Hono, @db/sqlite, twilio, node-cron
|
||||
- [x] Add env config loading (--env-file): `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `TWILIO_PHONE_NUMBER`, `ENDORSER_API_URL`, `SMS_DB_PATH`
|
||||
- [x] Set up deno.json tasks (start, dev, test, check)
|
||||
|
||||
### Step 2: Database schema and migrations
|
||||
- [x] Create `sql/` migration files for:
|
||||
- [x] `sms_user` table (phoneNumber, issuerDid, pendingDid, storedJwt, jwtExpiresAt, verified, verificationCode, verificationExpiry, verificationAttempts, codesRequestedThisHour, cooldownUntil, timestamps)
|
||||
- [x] `sms_notification_pref` table (userId, notificationType, enabled, sendTimeUtc, timezoneOffset, reminderMessage, alertSearchParams, timestamps)
|
||||
- [x] `sms_send_log` table (userId, notificationType, sentAt, status, providerMessageId, errorMessage)
|
||||
- [x] DB initialization on service startup with auto-migration runner
|
||||
|
||||
### Step 3: JWT-forwarding auth middleware
|
||||
- [x] Middleware that extracts `Authorization: Bearer <JWT>` from incoming requests
|
||||
- [x] Forwards to endorser-ch `GET /api/v2/report/rateLimits` with the same Authorization header
|
||||
- [x] Extracts and caches (60s by JWT hash) the caller's DID
|
||||
- [x] Sets `c.set("issuerDid")` for downstream handlers
|
||||
- [x] Returns 401 on endorser-ch rejection
|
||||
|
||||
### Step 4: Phone registration and verification endpoints
|
||||
- [x] `POST /api/sms/register` — validate E.164 US-only, rate-limit checks (cooldown, codes-per-hour), generate 6-digit code, hash with PBKDF2, store, send via Twilio
|
||||
- [x] `POST /api/sms/verify` — check attempts (max 5), check expiry (15 min), compare code, set verified=true. Handle DID reassignment (pendingDid flow).
|
||||
- [x] `DELETE /api/sms/register` — remove phone, all prefs, clear stored JWT
|
||||
|
||||
### Step 5: Stored JWT management
|
||||
- [x] `PUT /api/sms/jwt` — accepts a long-lived JWT from the app, stores it with its expiry for the authenticated user
|
||||
- [x] Validate the JWT is valid by forwarding to endorser-ch before storing
|
||||
- [ ] Return JWT expiry status in `GET /api/sms/preferences` response
|
||||
|
||||
### Step 6: Twilio SMS integration
|
||||
- [x] Wrap Twilio behind a provider interface (`SmsProvider` with `sendSms(to, body)`)
|
||||
- [x] Implement TwilioProvider using the Twilio SDK (lazy-loaded on first send)
|
||||
- [x] Add a mock/log provider for development and testing
|
||||
- [x] Log all sends to `sms_send_log`
|
||||
|
||||
## Implementation Plan — Phase 2: Notification Preferences & Scheduler
|
||||
|
||||
### Step 7: Preference endpoints
|
||||
- [ ] `GET /api/sms/preferences` — return all prefs for authenticated user, plus JWT expiry status and phone verification status
|
||||
- [ ] `PUT /api/sms/preferences` — update prefs. Reject enabling if phone not verified. Reject enabling `alert_search` if no valid stored JWT.
|
||||
- [ ] `GET /api/sms/history` — return recent send log entries
|
||||
|
||||
### Step 8: Periodic scheduler
|
||||
- [ ] node-cron job running every 15 minutes
|
||||
- [ ] Query enabled prefs where sendTimeUtc falls in current 15-min window
|
||||
- [ ] For `reminder`: send the user's custom message
|
||||
- [ ] For `alert_search`: call endorser-ch `alertSearch` using stored JWT, summarize results, send SMS
|
||||
- [ ] Idempotency: track last send time per pref to avoid duplicates
|
||||
- [ ] Skip users with expired JWTs for alert_search (reminder still works)
|
||||
|
||||
## Implementation Plan — Phase 3: App Integration
|
||||
|
||||
### Step 9: Time Safari notification settings UI
|
||||
- [ ] Find existing notification settings in crowd-funder-for-time-pwa
|
||||
- [ ] Add phone number registration/verification UI (inline in settings)
|
||||
- [ ] Refactor notification settings to show side-by-side channels per notification type
|
||||
- [ ] Pre-fill SMS settings from on-device settings as defaults
|
||||
- [ ] Silent JWT refresh on settings screen open
|
||||
|
||||
## Build & Run
|
||||
|
||||
```bash
|
||||
# sms-service (Deno)
|
||||
cd sms-service && deno task dev
|
||||
|
||||
# endorser-ch (reference only, run for testing auth forwarding)
|
||||
cd endorser-ch && pkgx npm install && pkgx npm start
|
||||
|
||||
# crowd-funder (for UI work)
|
||||
cd crowd-funder-for-time-pwa && pkgx npm install && pkgx npm run serve
|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
- sms-service uses Deno with Hono (jsr:@hono/hono), SQLite (jsr:@db/sqlite), and TypeScript natively
|
||||
- Follow endorser-ch patterns for route structure, error handling, and DB access
|
||||
- Use TypeScript throughout
|
||||
- Use `pkgx` prefix for node/npm/npx commands (endorser-ch, crowd-funder). sms-service uses `deno task` directly.
|
||||
@@ -245,45 +245,7 @@ Minimal changes to the endorser-ch server:
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Core Infrastructure
|
||||
- [ ] Set up new Node.js service with SQLite database
|
||||
- [ ] Implement JWT-forwarding auth middleware (validate JWTs via endorser-ch `rateLimits` endpoint)
|
||||
- [ ] Implement phone registration and verification endpoints (including DID reassignment flow)
|
||||
- [ ] Implement stored JWT management (store user-issued JWTs, track expiry, refresh endpoint)
|
||||
- [ ] Integrate Twilio SDK for sending SMS
|
||||
|
||||
### Phase 2: Notification Preferences & Scheduler
|
||||
- [ ] Implement preference storage and API endpoints
|
||||
- [ ] Build the periodic scheduler (15-minute interval)
|
||||
- [ ] Implement `reminder` notification type (custom message send)
|
||||
- [ ] Implement `alert_search` notification type (fetch + summarize + send)
|
||||
|
||||
### Phase 3: App Integration
|
||||
- [ ] Add phone number registration UI to Time Safari settings
|
||||
- [ ] Add notification preference controls
|
||||
- [ ] Add send history view
|
||||
|
||||
### Phase 4: Hardening
|
||||
- [ ] Delivery status webhooks from Twilio (track delivered vs. failed)
|
||||
- [ ] Retry logic for failed sends
|
||||
- [ ] Admin dashboard for monitoring send rates and failures
|
||||
- [ ] Opt-out via SMS reply (STOP keyword handling)
|
||||
- [ ] Upgrade to service DID delegation auth (replacing stored user JWTs)
|
||||
|
||||
### Phase 5: Paid Tier -- Higher Limits & International SMS
|
||||
- [ ] Integrate a payment mechanism (e.g., Stripe, or crypto/gift-economy credit)
|
||||
- [ ] Add `sms_user` columns for payment status and tier (`free` / `paid`)
|
||||
- [ ] Enforce US-only phone numbers for free tier; allow international numbers for paid tier
|
||||
- [ ] Raise daily rate limits for paid users (e.g., free: 2 messages/day, paid: 10 messages/day)
|
||||
- [ ] Add payment status checks to the send path and preference validation
|
||||
- [ ] Time Safari UI for payment/upgrade flow
|
||||
|
||||
### Phase 6: Event-Triggered SMS from Partner Functions
|
||||
- [ ] Add `POST /api/sms/send` endpoint to SMS service (service-to-service auth)
|
||||
- [ ] Add per-event-type opt-in preferences (profile messages, meeting invites, etc.)
|
||||
- [ ] Integrate first trigger in endorser-ch (e.g., profile messaging)
|
||||
- [ ] Add event-type rate limiting per recipient
|
||||
- [ ] Extend Time Safari settings UI for event-type opt-in/opt-out
|
||||
See [project checklit](./PROJECT-sms-notifications-checklist.md)
|
||||
|
||||
## Future Requirement: Event-Triggered SMS from Partner Functions
|
||||
|
||||
|
||||
Reference in New Issue
Block a user