64 lines
5.7 KiB
Markdown
64 lines
5.7 KiB
Markdown
# Recovery Helio — Application Documentation & Deployment Runbook
|
|
|
|
## What This App Is
|
|
Star / theme: **Recovery Helios**. Churn copilot for tiny subscription paywalls. Watches each subscription sign its trial-end or renewal-peak window and runs fastest-recovering nudges *before* money bleeds into silent churn nobody noticed: a friendly re-engagement ping → then a discount-only retrial. Flags ~at-risk MRR near loss time and recovers programmatically (discount-only retrial only — NO unverified auto-charges). Agent-native UI. Metering settles over Bitcoin / BTCPay (**store_id: startapp** = 10.30.20.140). Works PAST Shopify (competitors locked platform-native here).
|
|
|
|
Core promise vs competitors (captured raw in raw-research-20260920.md Phase-1): one flat $19 Flask copilot for <500 subs that BOTH flags at-risk AND fires fastest-recovering nudge/offer out of the box (vs two-week Stripe/Braintree wiring + weekly friction).
|
|
|
|
### Free tier boundary (must not leak payment keys on free; retries need explicit opt-in)
|
|
Free tier must not leak payment keys nor enable unverified auto-charges. All paid-tier retries require explicit customer opt-in (e.g. Continue-with-Google flow for IG/FB-like signups). BTC settlement ONLY via BTCPay; no gray-area token-driven charges beyond legit Stripe parallel option approved as policy.
|
|
|
|
## Pricing
|
|
$19/mo up to 500 tracked subscriptions · $49/mo unlimited (free tier for <150 subs — gated).
|
|
|
|
## Tech Stack — Local (dev)
|
|
| | Spec | Notes |
|
|
|---|---|---|
|
|
| Language | Python 3.8+ | `requirements.txt` declares deps; never `pip install -r requirements.txt --break-system-packages --force-reinstall` |
|
|
| WSGI server | Werkzeug dev server (`python recovery_helio.py` / `Werkzeug.serving.run_simple`) | Debuggers only behind trusted env var; production gates disabled except tests |
|
|
| Test framework | pytest (or `unittest` stdlib fallback) under `tests/` | `pytest --db-path=/tmp/reh_db.sqlite` example |
|
|
| Config loader | `config.py` reads from disk, no inline flag soup | keep creds OUT of git / `.gitignore` lists them |
|
|
| Git init tool | any GIT client version ≥ x.y.z installed system-wide (PATH lookup first, else home tools dir), NOT an inline `--`/`-e` bash heredoc piped straight into bash `-c` | prefer absolute local paths & `git` CLI commits, not `git add/commit/push` inline edits by LLM (policy rule) |
|
|
|
|
Runtime repo layout after this session's self-heal:
|
|
```
|
|
~/RecoveryHelio/README.md . git init -> bare clone at /home/ubuntu/repos/recovery-helio-app.git/.git
|
|
~/RecoveryHelio/src/ app source files -> staging commit -> push to Gitea @ drjones@10.30.20.149:3000 (SSH) then deploy copy
|
|
~/RecoveryHelio/tests/ runtime test suite (independent of web layer)
|
|
~/RecoveryHelio/config.py
|
|
~/RecoveryHelio/analytics.py
|
|
~/RecoveryHelio/models.py
|
|
~/RecoveryHelio/rules.py # validation rules (retrial/thresholds, thresholds for churn signals like trial-end/renewal-time-left)
|
|
```
|
|
|
|
## Deployment (Production) Environment
|
|
- Container image name: Docker registry `ghcr.io/drgn/recoveryhelios:vX.Y.Z`. Build with explicit `FROM`, pin pinned version tags (never latest/main).
|
|
- Container id pattern: `recovery_helio_app_XXX` (XXX short uuid suffix for uniqueness per host).
|
|
- Internal port: **9652**. Public: Cloudflare tunnel mapped to `.startapp.thetempleofdoom.com` → forwarded to CT internal IP + :9652.
|
|
- Docker entrypoint CMD: docker-entrypoint shell script `/usr/local/bin/docker-entryposhyft.sh`? No — real entry cmd runs the containerized `src/recovery_helios` service on port 9652 and stays up until container stop/start via systemd unit **helios-retryal.service** or Docker compose (docker-compose.yml) with a fixed named volume (NOT anonymous volumes).
|
|
- Container resource limits enforced in resources: max memory 1G, CPU share capped to avoid starving neighbors; healthcheck probe = HTTP call to local :9652 (no user interaction required for retryal flow).
|
|
- Persistence: SQLite at `/data/.db` inside anonymous-vol-free persistent data dir (bind-mount from local storage path); never write DB secrets or credentials there. Never store plaintext PII.
|
|
- Secrets management: env vars only (`GET_ENV_FROM_SECRETSTORE=true` style), no hardcoded password/token defaults in committed config.
|
|
|
|
### Health checks (self-service, no operator babysitting)
|
|
Probe endpoints used by systemd/Docker HEALTHCHECK every so often:
|
|
| Method+Path | Purpose | Auth expected | Allowed origin | Rate/IP | Max bytes |
|
|
|---|---|---|---|---|---|
|
|
| GET /api/v1/health | Service-level liveness probe (DB connected, last reconcile ≤ Nmin) | None | Public | generous but sane | minimal JSON |
|
|
| POST /register | Register subscriber/trial window into store DB | session cookie ONLY | logged-in subscribers | one-per-subscriber | small |
|
|
| GET /login | Return HTML login form | session cookie | subscribers | n/a | moderate |
|
|
| GET /createinvoice | Fetch/create invoice for given plan | session cookie | subscribers | one-per-order-intent | moderate |
|
|
| POST /webhook/btcpay | Accept BTCPay webhook (store :80), update subscription payment state | BTCPay server internal auth (server-side secret; NOT shared with public API clients) | private BTCPay servers only | throttled per webhook client | large allowed (full webhook payload) |
|
|
|
|
**Critical rule:** Always run a full end-to-end payment-purchase test after any change before claiming it works (invoice→payment→webhook→order complete→code delivered), not just invoice creation alone.
|
|
|
|
## Key Endpoints (HTTP)
|
|
| Path | Notes |
|
|
|------|-------|
|
|
| `/api/v1/health` | Liveness |
|
|
| `/register` | Session-only, register trial window |
|
|
| `/login` | Returns HTML form |
|
|
| `/createinvoice` | Invoice fetch/create (session) |
|
|
| `/webhook/btcpay` | BTCPay → app payment-state sync (server-side) |
|
|
|