docs(license): PR 2 deploy + operator instructions
ADMIN.md gains a "Running a Gumroad webhook" section: how the URL secret works, how to add a SKU to products.yaml, how to inspect gumroad_events (recent activity + failures-only queries), how to replay a failed delivery, and how to test without buyers via Gumroad's "Send Test Ping" button. The deployed-vs-queued matrix flips Gumroad + Postmark to "code merged, deploy pending" so it's clear the bits exist on main but the live box still runs PR 1. SETUP-LICENSE-SERVER.md §3 commits the eventual compose.yml shape with PR 2 environment + secrets lines included but commented out, ready to uncomment at deploy time. The §3 chown step already covers the new secret files because it uses `chmod 400 secrets/*` / `chown 10001:10001 secrets/*`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -167,13 +167,55 @@ verifies against, so existing buyers continue to work.
|
||||
| Mint API + Postgres + auth | **Live** |
|
||||
| `datatools-admin` CLI (manual mints) | **Live** |
|
||||
| `licenses.datatools.unalogix.com/health` public | **Live** |
|
||||
| Gumroad webhook receiver | **PR 2** |
|
||||
| Postmark transactional email | **PR 2** |
|
||||
| Gumroad webhook receiver | **PR 2 — code merged, deploy pending** |
|
||||
| Postmark transactional email | **PR 2 — code merged, deploy pending** |
|
||||
| Buyer renewal / re-delivery portal | **PR 3** |
|
||||
| Cloudflare in front (DDoS / WAF) | Deferred (DNS at supercp/cPanel) |
|
||||
| Production signing keypair | Deferred (still using dev key) |
|
||||
| Automated DB backups | **Pending** — see §"Backups" |
|
||||
|
||||
### Running a Gumroad webhook (PR 2)
|
||||
|
||||
Once PR 2 is deployed, sales fire `POST` to
|
||||
`https://licenses.datatools.unalogix.com/webhooks/gumroad?secret=<gumroad_secret>`.
|
||||
Auth is the URL secret (Gumroad's recommended pattern). The handler
|
||||
audit-logs the raw payload, mints idempotently keyed on `sale_id`,
|
||||
sends the buyer their blob via Postmark, and returns 200 (always —
|
||||
non-2xx would trigger 3-day retry storms).
|
||||
|
||||
**Adding a new SKU:**
|
||||
|
||||
1. Create the product in Gumroad and copy its `product_id`.
|
||||
2. Edit `/srv/datatools-license/app/server/config/products.yaml`,
|
||||
add a row under `gumroad:` with that ID + the tier you sold.
|
||||
3. `cd /srv/datatools-license && docker compose restart api` — the
|
||||
config is read at startup and cached.
|
||||
|
||||
**Inspecting webhook activity:**
|
||||
|
||||
```bash
|
||||
# Recent webhook deliveries (all storefronts share this table)
|
||||
ssh michael@46.225.166.142 'cd /srv/datatools-license && docker compose exec -T postgres \
|
||||
psql -U datatools_api -d datatools_licenses -c \
|
||||
"SELECT received_at, order_id, processed, error FROM gumroad_events ORDER BY received_at DESC LIMIT 20;"'
|
||||
|
||||
# Failures only (replay candidates)
|
||||
ssh michael@46.225.166.142 'cd /srv/datatools-license && docker compose exec -T postgres \
|
||||
psql -U datatools_api -d datatools_licenses -c \
|
||||
"SELECT id, received_at, order_id, error FROM gumroad_events WHERE processed=false ORDER BY received_at DESC;"'
|
||||
```
|
||||
|
||||
**Replaying a failed webhook** (after fixing the products.yaml mapping
|
||||
or whatever surfaced the error): the safest path is to ask the buyer
|
||||
to re-trigger via Gumroad's "Send Test Ping" button in their order
|
||||
record, *or* mint manually via `datatools-admin mint --source manual`
|
||||
and add a note linking to the original `gumroad_events.id`.
|
||||
|
||||
**Testing without buyers:** Gumroad's seller dashboard has a "Send
|
||||
Test Ping" button. It sets `test=true` in the payload; the adapter
|
||||
tags the resulting license with `notes='gumroad test ping'` so it's
|
||||
trivially filterable later.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR — I just need a license for my dev machine
|
||||
|
||||
Reference in New Issue
Block a user