Tidy relay-internal detail; add client-side relay contract
- Add Client-side contract with the relay sub-section: env vars (RECAP_RELAY_BASE_URL, RECAP_RELAY_OPERATOR_KEY ↔ relay_cloud_operator_key), auth direction the client SENDS, the 12 /relay/* endpoints the consumer actually calls (verified against providers/relay.js + billing-routes.js + subscription-reminders.js). - Drop two relay-internal references now canonical in ../recap-relay/AGENTS.md: the extendUserTier function name and the Adjacent-repo bullet's "Private; ships via make install only" sentence.
This commit is contained in:
@@ -78,9 +78,18 @@ vendor/keysat-licensing-client/ local-link Keysat SDK
|
|||||||
- **Trial IP cap is per-IP for IPv4, per-/64 prefix for IPv6.** Dual-stack home networks would otherwise bypass it via privacy-extension address rotation.
|
- **Trial IP cap is per-IP for IPv4, per-/64 prefix for IPv6.** Dual-stack home networks would otherwise bypass it via privacy-extension address rotation.
|
||||||
- **`safeFilename()` already exists** for any user-content → on-disk path. Use it; don't roll your own.
|
- **`safeFilename()` already exists** for any user-content → on-disk path. Use it; don't roll your own.
|
||||||
- **The relay owns cloud Pro/Max tier + expiry** (core-decoupling; `docs/core-decoupling-plan.md`). In multi-mode, paid status is `users.tier` — cached from the relay, keyed by the Recaps user-id — NOT a per-user Keysat license. Don't gate cloud paid features by `keysat_license`; the license only matters for self-hosted "take it home" portability. Cloud requests carry `X-Recap-User-Id` + the operator key; server-to-server tier reads/writes go through `providers/relay.js`.
|
- **The relay owns cloud Pro/Max tier + expiry** (core-decoupling; `docs/core-decoupling-plan.md`). In multi-mode, paid status is `users.tier` — cached from the relay, keyed by the Recaps user-id — NOT a per-user Keysat license. Don't gate cloud paid features by `keysat_license`; the license only matters for self-hosted "take it home" portability. Cloud requests carry `X-Recap-User-Id` + the operator key; server-to-server tier reads/writes go through `providers/relay.js`.
|
||||||
- **Self-serve purchase has two rails, both prepaid (no auto-renew yet).** Bitcoin = a BTCPay invoice rendered as an INLINE Lightning QR on-screen — the relay fetches the BOLT11 server-to-server, so the buyer never loads BTCPay (replicate the buy-credits inline flow; do NOT redirect to a hosted checkout). Card = a Zaprite one-time hosted order (Zaprite's API has no recurring — see ROADMAP). Both settle webhooks land at the relay's `extendUserTier`; the frontend just polls `/api/billing/status`. Expiry reminders go out via the existing System-SMTP transport (`smtp.js`): the relay enumerates who's expiring (`GET /relay/expiring-subscriptions`), Recaps maps user-id → email and sends.
|
- **Self-serve purchase has two rails, both prepaid (no auto-renew yet).** Bitcoin = a BTCPay invoice rendered as an INLINE Lightning QR on-screen — the relay returns the BOLT11 server-to-server, so the buyer never loads BTCPay (replicate the buy-credits inline flow; do NOT redirect to a hosted checkout). Card = a Zaprite one-time hosted order (Zaprite's API has no recurring — see ROADMAP). Both settle webhooks land on the relay (it owns subscription expiry); the frontend just polls `/api/billing/status`. Expiry reminders go out via the existing System-SMTP transport (`smtp.js`): the relay enumerates who's expiring (`GET /relay/expiring-subscriptions`), Recaps maps user-id → email and sends.
|
||||||
- **Tier credit allotments are operator-config-driven, never hardcoded.** The cards' "N relay credits each period" comes from the relay's tier-quota config (`credits_per_period` on `/relay/tier-plans`); `null` → "Unlimited". Don't bake a number or "Unlimited" into the UI.
|
- **Tier credit allotments are operator-config-driven, never hardcoded.** The cards' "N relay credits each period" comes from the relay's tier-quota config (`credits_per_period` on `/relay/tier-plans`); `null` → "Unlimited". Don't bake a number or "Unlimited" into the UI.
|
||||||
|
|
||||||
|
### Client-side contract with the relay
|
||||||
|
|
||||||
|
Endpoint shapes + auth model are documented canonically in `../recap-relay/AGENTS.md`. The client side is:
|
||||||
|
|
||||||
|
- **Env vars** — `RECAP_RELAY_BASE_URL` (default `https://relay.recaps.cc`) + `RECAP_RELAY_OPERATOR_KEY` (matches the relay's `relay_cloud_operator_key`). Both gitignored; reference names, never values. Resolved in `server/relay-default.js` and `server/config.js`.
|
||||||
|
- **Auth direction (what the client SENDS)** — cloud calls send `X-Recap-Operator-Key` + `X-Recap-User-Id`; self-hosted calls send `X-Recap-Install-Id` (+ optional `Authorization: <license>`). Set the same `X-Recap-Job-Id` on transcribe + analyze in one summary so the relay bills one credit, not two.
|
||||||
|
- **Endpoints called** — `/relay/{transcribe, transcribe-url, summarize-url, summarize-url/:jobId/events, analyze, balance, user-tier, user-tier/:id, tier-invoice, tier-zaprite-order, tier-plans, expiring-subscriptions}`. Settle webhooks land on the relay side, never here.
|
||||||
|
- **Files** — `server/providers/relay.js` (transcribe/summarize/analyze + tier reads/writes), `server/billing-routes.js` (purchase orchestration), `server/subscription-reminders.js` (polls `/relay/expiring-subscriptions`).
|
||||||
|
|
||||||
## Always
|
## Always
|
||||||
|
|
||||||
- **Bump the version before `make install`.** StartOS dedupes sideloads by version string — installing the same version twice silently no-ops. Use `make bump` or edit `startos/versions/index.ts` + add a `vN.ts` file. Applies to EVERY iteration, even a one-line edit.
|
- **Bump the version before `make install`.** StartOS dedupes sideloads by version string — installing the same version twice silently no-ops. Use `make bump` or edit `startos/versions/index.ts` + add a `vN.ts` file. Applies to EVERY iteration, even a one-line edit.
|
||||||
@@ -102,7 +111,7 @@ vendor/keysat-licensing-client/ local-link Keysat SDK
|
|||||||
|
|
||||||
## Adjacent repo
|
## Adjacent repo
|
||||||
|
|
||||||
- `../recap-relay` — the operator-side credit-metered service this client talks to. Owns Gemini/Parakeet/Sortformer routing, diarization, internal-meeting analysis, the operator dashboard at `/admin/*`. Private; ships via `make install` only, never `make deploy`. Reference it but do not change it from inside this repo.
|
- `../recap-relay` — the operator-side credit-metered service this client talks to. Owns Gemini/Parakeet/Sortformer routing, diarization, internal-meeting analysis, and the operator dashboard. See `../recap-relay/AGENTS.md` for its endpoint shapes, build/deploy rules, and roadmap. Reference it but do not change it from inside this repo.
|
||||||
|
|
||||||
## Current state
|
## Current state
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user