summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AGENTS.md30
-rw-r--r--Biz/PodcastItLater/STRIPE_TESTING.md75
-rw-r--r--Biz/PodcastItLater/Web.nix4
-rw-r--r--Biz/PodcastItLater/Web.py4
-rw-r--r--Omni/Bild.nix2
5 files changed, 101 insertions, 14 deletions
diff --git a/AGENTS.md b/AGENTS.md
index e1f35f5..b39c1a1 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -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
];