|
| 1 | +# Billing And Trial |
| 2 | + |
| 3 | +Hosted Compass uses Stripe Checkout (subscription mode, 7-day trial, $8/month) |
| 4 | +and the Stripe Billing Portal. There is no Stripe.js and no publishable key in |
| 5 | +the web bundle. |
| 6 | + |
| 7 | +Self-host installs omit the `stripe:` config block. `/api/config` then reports |
| 8 | +`billing.isConfigured: false`, the web never shows a paid gate, and event |
| 9 | +writes stay open. |
| 10 | + |
| 11 | +## What users see |
| 12 | + |
| 13 | +- **Never signed up:** the existing 7-day anonymous `localStorage` trial and |
| 14 | + `TrialGateModal`. Unchanged. |
| 15 | +- **Signed up, no card yet:** `awaiting_checkout`, read-only, `BillingGateModal` |
| 16 | + with Subscribe (Stripe Checkout). |
| 17 | +- **Trialing / active / past_due:** writable. `past_due` also shows a banner. |
| 18 | +- **Expired / canceled:** read-only until they subscribe again. A later |
| 19 | + Checkout does not grant another trial. |
| 20 | + |
| 21 | +There is no `POST /api/billing/trial/start`. A trial only begins through |
| 22 | +Stripe Checkout (`trial_period_days` on the first subscription). |
| 23 | + |
| 24 | +Existing accounts are not grandfathered. `bun run cli backfill-billing` places |
| 25 | +rows without `billing.subscriptionStatus` onto a 7-day trial. The default |
| 26 | +`BACKFILL_CUTOFF` is far in the future so every such row is included; set it |
| 27 | +to a past instant to grandfather newer signups. Those rows have no Stripe |
| 28 | +subscription id, so they self-expire locally when `trialEndsAt` passes. |
| 29 | + |
| 30 | +## Staging |
| 31 | + |
| 32 | +Set `STRIPE_SECRET_KEY` (restricted `rk_test_...`), `STRIPE_WEBHOOK_SECRET`, |
| 33 | +and `STRIPE_PRICE_ID` on the `staging-cloud` GitHub Environment. Config-only |
| 34 | +deploys need `./compass restart`. Confirm `/api/config` shows |
| 35 | +`billing.isConfigured: true`. |
| 36 | + |
| 37 | +`staging-selfhosted` must not get those secrets — it is the live regression |
| 38 | +that self-host stays writable. |
| 39 | + |
| 40 | +Sales tax (`automatic_tax`) is a Stripe Dashboard decision, not a code one, |
| 41 | +and should be settled before production keys. |
| 42 | + |
| 43 | +## Key files |
| 44 | + |
| 45 | +- Plan/price copy: `packages/core/src/constants/billing.constants.ts` |
| 46 | +- Status derivation: `packages/backend/src/billing/services/billing.service.ts` |
| 47 | +- Checkout / portal: `packages/backend/src/billing/services/stripe.service.ts` |
| 48 | +- Webhook: `packages/backend/src/billing/services/billing.webhook.service.ts` |
| 49 | +- Write guard: `packages/backend/src/billing/billing.guard.ts` |
| 50 | +- Web access: `packages/web/src/billing/useAppAccess.ts` |
0 commit comments