Appearance
Reform Assistant — Developer docs
Reform Assistant is the family-facing cloud portal for the Hermes "Prison Reform" Securus eMessage service. Families sign up, add their incarcerated loved one (the inmate), and pay for a plan through Stripe. Once payment lands, the portal marks the inmate as waiting to be connected; the Hermes host picks that up, registers the inmate with the Securus skill, and grants a monthly message allowance. The portal then shows usage reported back by Hermes.
Everything lives in one folder of the Hermes repository, cloud/reform-assistant/, which has its own package.json and lockfile (it is not part of the root npm workspaces).
What is in the box
| Piece | Technology | Where |
|---|---|---|
| API and request routing | One Cloudflare Worker, TypeScript, no framework, no runtime dependencies | src/ |
| Persistence | Cloudflare D1 (SQLite), binding DB | migrations/0001_init.sql, migrations/0002_checkout_sessions.sql |
| Event archive | Cloudflare R2 bucket reform-assistant-files, binding FILES | Stripe webhook payloads (stripe/events/) and duplicate-subscription records (stripe/duplicates/) |
| Static site | Plain HTML, CSS, and ES-module JavaScript served by Workers Static Assets, binding ASSETS | public/ |
| Billing | Stripe Checkout, Billing Portal, and webhooks over the REST API with fetch (no Stripe SDK) | src/billing.ts, src/stripe_webhook.ts |
| Hermes link | Bearer-token JSON endpoints under /api/hermes/ plus a standard-library Python cron script | src/hermes.ts, hermes_bridge/portal_sync.py |
Architecture at a glance
Family-facing traffic and billing:
text
Family browser
|
v
+---------------------------------------------+
| Cloudflare Worker (src/index.ts) |
| /api/* -> Worker routes (JSON) |
| others -> env.ASSETS.fetch (public/) |
+-----+---------------+-----------+-----------+
| | |
v v v
D1 (DB) R2 (FILES) Stripe REST API
users, stripe/ Checkout sessions,
sessions, events/ Billing Portal
inmates, <id>.json
subscriptions,
connections,
usage_events,
stripe_events
^
| POST /api/stripe/webhook (Stripe-Signature verified)
StripeHermes link (the Worker never calls Hermes; Hermes polls the Worker):
text
Hermes cron (no-agent job, every few minutes)
|
v
hermes_bridge/portal_sync.py
| Authorization: Bearer <HERMES_LINK_TOKEN>
| GET /api/hermes/connections?status=pending
| POST /api/hermes/connections/<id>/ack
| GET /api/hermes/allowances
| POST /api/hermes/usage
v
Cloudflare Worker ---> D1
|
v (local subprocess + local Securus store)
Securus skill skills/communication/securus-emessage/scripts/securus_poc.py
add_contact, stamps show / grant / revokePlans
The Worker's GET /api/plans is the single source for plan data; the landing page shows the same numbers as static HTML.
| id | label | price | billing | save | messages per month |
|---|---|---|---|---|---|
monthly | Monthly | $8.00 | per month | none | 40 |
quarterly | 3 months | $21.60 | billed once | 10% | 40 |
annual | 12 months | $81.60 | billed once | 15% | 40 |
The allowance is per month on every plan. Quarterly and annual subscribers are billed once but get the same 40 messages in each calendar month of their billing period; the portal and the Hermes bridge work with a monthly window inside the Stripe billing period (see Monthly allowance window).
Where to go next
- What the product is made of: Product primitives (rules and where each is enforced) and the Feature map (F01-F17, with tests and end-to-end steps).
- New to the repository: Getting started, then Architecture.
- Wiring payments: the Stripe section: setup, checkout and billing portal, webhooks, testing payments and going live.
- Shipping it: Cloudflare deployment.
- Connecting Hermes: Hermes bridge.
- Looking something up: HTTP API, Data model, Security and Frontend.
- Running it in production: Runbook and Testing.