diff options
| -rw-r--r-- | AGENTS.md | 30 | ||||
| -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 | ||||
| -rw-r--r-- | Omni/Bild.nix | 2 |
5 files changed, 101 insertions, 14 deletions
@@ -343,14 +343,38 @@ task ready ## Build and Test Commands -Build the task manager: +### bild + +`bild` is the universal build tool. It can build and test everything in the repo. + +Examples: +```bash +bild --test Omni/Bild.hs # Build and test a namespace +bild --time 0 Omni/Cloud.nix # Build with no timeout +bild --plan Omni/Test.hs # Analyze build without building +``` + +### run.sh + +`run.sh` is a convenience wrapper that builds (if needed) and runs a namespace. + +Examples: ```bash -bild --time 0 Omni/Task.hs +Omni/Ide/run.sh Omni/Task.hs # Build and run task manager +Omni/Ide/run.sh Biz/PodcastItLater/Web.py # Build and run web server ``` +This script will: +1. Check if the binary exists in `_/bin/` +2. Build it if it doesn't exist (exits on build failure) +3. Execute the binary with any additional arguments + +### Test Commands + Run tests: ```bash -task test +task test # Run task manager tests +bild --test Omni/Task.hs # Build and test a namespace ``` ## Integration with Git 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) diff --git a/Omni/Bild.nix b/Omni/Bild.nix index 364bac3..d3d5301 100644 --- a/Omni/Bild.nix +++ b/Omni/Bild.nix @@ -134,6 +134,7 @@ pkg-config ripgrep rustc + stripe-cli tree wemux ; @@ -262,6 +263,7 @@ lolcat ormolu ripgrep + stripe-cli tree wemux ]; |
