diff options
Diffstat (limited to 'Biz/PodcastItLater')
| -rw-r--r-- | Biz/PodcastItLater/STRIPE_TESTING.md | 75 | ||||
| -rw-r--r-- | Biz/PodcastItLater/Web.nix | 4 | ||||
| -rw-r--r-- | Biz/PodcastItLater/Web.py | 4 |
3 files changed, 72 insertions, 11 deletions
diff --git a/Biz/PodcastItLater/STRIPE_TESTING.md b/Biz/PodcastItLater/STRIPE_TESTING.md index 00910ec..63cfdf6 100644 --- a/Biz/PodcastItLater/STRIPE_TESTING.md +++ b/Biz/PodcastItLater/STRIPE_TESTING.md @@ -315,15 +315,72 @@ Full list: https://stripe.com/docs/testing#cards ## Production Deployment -Before going to production: - -1. Switch to live mode keys (remove `_test_` from keys) -2. Create products/prices in live mode Stripe dashboard -3. Set up live webhook endpoint in Stripe dashboard -4. Update STRIPE_WEBHOOK_SECRET to live mode secret -5. Set AREA=Live in production environment -6. Test with real payment methods (or use test mode in production at first) -7. Monitor webhook events and logs closely +### Prerequisites + +1. **Stripe Live Mode Setup:** + - Create products/prices in live mode Stripe dashboard + - Get live mode API keys (sk_live_...) + - Set up webhook endpoint at: `https://podcastitlater.bensima.com/stripe/webhook` + - Configure webhook events: checkout.session.completed, customer.subscription.*, invoice.payment_failed + - Copy webhook signing secret (whsec_...) + +2. **Environment Variables:** + Create `/run/podcastitlater/env` on production server with: + ```bash + # Authentication + SECRET_KEY=<generate-with-openssl-rand-hex-32> + SESSION_SECRET=<generate-with-openssl-rand-hex-32> + + # Email (for magic links) + EMAIL_FROM=noreply@podcastitlater.bensima.com + SMTP_SERVER=smtp.mailgun.org + SMTP_PASSWORD=<mailgun-smtp-password> + + # Stripe (use test mode first, then switch to live) + STRIPE_SECRET_KEY=sk_test_... # or sk_live_... + STRIPE_WEBHOOK_SECRET=whsec_... + STRIPE_PRICE_ID_PERSONAL=price_... + STRIPE_PRICE_ID_PRO=price_... + ``` + +3. **Build and Deploy:** + ```bash + # On development machine, build the service + bild --time 0 Biz/PodcastItLater/Web.py + + # Deploy to production server (method depends on your deployment setup) + # The Web.nix service configuration handles: + # - HTTPS via nginx with automatic SSL (Let's Encrypt) + # - BASE_URL set to https://podcastitlater.bensima.com + # - AREA=Live for production mode + # - Data directory at /var/podcastitlater + ``` + +### Deployment Steps + +1. **Start with Test Mode:** + - Use `STRIPE_SECRET_KEY=sk_test_...` initially + - Test the full flow with test cards + - Verify webhooks are received and processed + +2. **Switch to Live Mode:** + - Update environment variables to use `sk_live_...` + - Update price IDs to live mode prices + - Update webhook secret to live mode webhook + - Restart service + +3. **Verify Deployment:** + - Visit https://podcastitlater.bensima.com + - Test login flow + - Check billing page loads + - Try checkout flow (cancel before paying if testing) + - Monitor logs for errors + +4. **Monitor Production:** + - Check webhook events in database + - Monitor subscription states + - Watch for payment failures + - Set up alerts for critical errors ## Monitoring diff --git a/Biz/PodcastItLater/Web.nix b/Biz/PodcastItLater/Web.nix index e66043d..40bbe88 100644 --- a/Biz/PodcastItLater/Web.nix +++ b/Biz/PodcastItLater/Web.nix @@ -42,6 +42,10 @@ in { # EMAIL_FROM=noreply@podcastitlater.bensima.com # SMTP_SERVER=smtp.mailgun.org # SMTP_PASSWORD=your-smtp-password + # STRIPE_SECRET_KEY=sk_live_your_stripe_secret_key + # STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret + # STRIPE_PRICE_ID_PERSONAL=price_your_personal_price_id + # STRIPE_PRICE_ID_PRO=price_your_pro_price_id test -f /run/podcastitlater/env ''; script = '' diff --git a/Biz/PodcastItLater/Web.py b/Biz/PodcastItLater/Web.py index b5d41dd..6d3cf0a 100644 --- a/Biz/PodcastItLater/Web.py +++ b/Biz/PodcastItLater/Web.py @@ -1568,7 +1568,7 @@ def billing_checkout(request: Request, data: FormData) -> Response: try: checkout_url = Billing.create_checkout_session(user_id, tier, BASE_URL) - return RedirectResponse(url=checkout_url) + return RedirectResponse(url=checkout_url, status_code=303) except ValueError as e: logger.exception("Checkout error") return Response(f"Error: {e!s}", status_code=400) @@ -1583,7 +1583,7 @@ def billing_portal(request: Request) -> Response: try: portal_url = Billing.create_portal_session(user_id, BASE_URL) - return RedirectResponse(url=portal_url) + return RedirectResponse(url=portal_url, status_code=303) except ValueError as e: logger.exception("Portal error") return Response(f"Error: {e!s}", status_code=400) |
