diff --git a/SCRATCH/billing-stripe-handover-apr11-2026.md b/SCRATCH/billing-stripe-handover-apr11-2026.md new file mode 100644 index 0000000..be746fd --- /dev/null +++ b/SCRATCH/billing-stripe-handover-apr11-2026.md @@ -0,0 +1,196 @@ +# Billing + Stripe Handover (Apr 11, 2026) + +## Context +This document captures the current billing integration state between: +- zpack-api +- zpack-portal +- Stripe (sandbox/test mode) + +This was developed during a developer-mode session where chat history is not persisted, so this doc acts as the continuity handoff. + +--- + +## Current Status + +### Stripe +- Stripe sandbox/test mode configured +- Products + recurring prices created +- Checkout sessions successfully redirect to Stripe +- Test checkout completed using Stripe test card +- Stripe dashboard confirms: + - checkout.session.completed + - customer created + - subscription created + - invoice/payment succeeded (test) + +### API (zpack-api) +Working: +- `ensureStripeCustomer()` persists `stripeCustomerId` +- `/api/billing/checkout` successfully creates Stripe Checkout session +- Billing foundation fields exist in Prisma: + - `stripeCustomerId` + - `subscriptionStatus` + - `plan` + +Not yet complete: +- Webhook delivery not working (API not publicly reachable) +- As a result: + - `subscriptionStatus` is NOT being updated + - `plan` is NOT being updated + +Root cause: +- Stripe cannot reach `/api/billing/webhook` +- This is NOT a checkout issue +- This is a webhook reachability issue + +### Portal (zpack-portal) +Working: +- Billing page renders correctly for unsubscribed users +- Plan selection UI present +- Checkout button calls API +- Redirect to Stripe works + +Partially complete: +- Needs final alignment for: + - `trialing` state + - `active` state + - billing-exempt/admin display + +--- + +## Key Architectural Decisions + +### Billing Model +- Users can register without paying +- Subscription is optional until resource enforcement is implemented +- Future plan: soft gate (likely 1 free server, then require subscription) + +### Stripe Integration Strategy +- Use Stripe Checkout (NOT custom payment form) +- Use Stripe Billing Portal for management +- Use webhooks to update DB state +- DB remains source of truth for access decisions + +### Metadata Usage +Stripe objects should include: +- `metadata.userId` +- optionally `metadata.plan` + +This is used for safer webhook reconciliation. + +--- + +## Current Blocker + +### Webhook Delivery + +Problem: +- API is not publicly reachable +- Stripe cannot POST webhook events + +Observed behavior: +- `stripeCustomerId` set (checkout path) +- `subscriptionStatus` remains null +- `plan` remains null + +--- + +## Immediate Next Steps + +### Option A (Dev Testing - Recommended) +Use Stripe CLI forwarding: + +```bash +stripe listen --forward-to http://10.60.0.18:4000/api/billing/webhook +``` + +Then: +- copy CLI-provided `whsec_...` +- set as `STRIPE_WEBHOOK_SECRET` +- restart API +- re-run test checkout + +Expected result: +- webhook hits API +- DB updates correctly + +--- + +### Option B (Staging/Prod Path) + +Expose only webhook endpoint via public domain: + +Example: + +``` +https://billing.zerolaghub.com/api/billing/webhook +``` + +Requirements: +- real reverse proxy or tunnel (NOT DNS redirect) +- HTTPS +- Stripe signature verification enabled + +--- + +## Important Notes + +### Namecheap Redirect +- simple DNS/URL redirect is NOT sufficient +- Stripe requires direct POST endpoint +- must use proxy/tunnel instead + +### Stripe CLI +- does NOT need to run on API VM +- but easiest if it does +- must be able to reach internal API IP + +### Test Cards +Use Stripe test card: + +``` +4242 4242 4242 4242 +``` + +--- + +## Known Good + +- Checkout flow: WORKING +- Customer creation: WORKING +- Portal integration: WORKING enough for testing + +## Known Broken + +- Webhook delivery: NOT working +- Subscription state persistence: NOT working + +--- + +## Next Session Starting Point + +1. Get Stripe CLI installed and running +2. Verify webhook hits API +3. Confirm DB updates: + - `subscriptionStatus` + - `plan` +4. Refresh portal billing page +5. Verify UI reflects new state + +--- + +## Future Work (Post-Webhook) + +- Implement trial handling (`trialing` state) +- Add quota enforcement (soft gate) +- Improve billing UI states +- Add billing portal button behavior +- Consider exposing webhook endpoint cleanly for production + +--- + +## Summary + +The system is effectively complete except for webhook reachability. + +Once webhooks are flowing, billing becomes fully functional end-to-end.