Skip to content

add payment/billing#224

Open
rafizamankhan wants to merge 6 commits into
mainfrom
feature/3-payment-billing
Open

add payment/billing#224
rafizamankhan wants to merge 6 commits into
mainfrom
feature/3-payment-billing

Conversation

@rafizamankhan

Copy link
Copy Markdown
Contributor

Add Stripe billing at organizational level, webhooks and necessary logs.

Resolves #3

@rafizamankhan rafizamankhan self-assigned this Jul 3, 2026
@chriscarrollsmith

Copy link
Copy Markdown
Contributor

Plan: land billing on a dedicated stripe branch (not main)

We reviewed this PR and agree the implementation is solid, but billing is optional and cross-cuts core files — similar to how deployment targets live on modal / hetzner. Recommendation: close this PR to main and publish billing on a stripe branch, with core template changes propagating via the existing workflow.

One-time bootstrap

  1. Create stripe from this branch (not merge to main).
  2. Fix .env.example regression (restore full main template, append billing block).
  3. Push stripe, close PR add payment/billing #224 to main with pointer to stripe.
  4. Small doc-only PR to main (pointers to optional branches).
  5. Add stripe to propagate.yml matrix (+ optional pyproject.toml/uv.lock overlay resolver, mirroring Modal).

What lives where

Area main stripe
stripe dep, billing routes/utils/models absent full PR implementation
main.py billing middleware, routers, webhook CSRF skip absent present
db.py billing permissions / role backfill absent present
organization.py Stripe cancel on delete absent present
Billing templates / tests / 07-billing.qmd absent present
.env.example core vars only core + billing block

Expected conflict-prone files during propagation: main.py, pyproject.toml, db.py, organization.py, header/org templates, tests/conftest.py, .env.example.

CI

  • test.yml: run on main and stripe; Stripe dummy env on stripe only.
  • propagate.yml: matrix.branch: [modal, hetzner, stripe] with auto-resolver for dependency overlay conflicts.

main docs (separate PR)

  • Overview/customization/deployment: pointer to stripe branch + merge recipe (git merge upstream/stripe).
  • README: optional branches table (stripe, modal, hetzner).
  • Contributing: note that core PRs may need conflict guidance for stripe.

Fork paths

Starting point Action
New SaaS fork Fork with default branch stripe, or git checkout stripe
Existing main fork git merge upstream/stripe, resolve core-file conflicts
No billing stay on main

On stripe, billing is always on — no BILLING_ENABLED flag on main (code simply absent there).

Follow-up on this branch before stripe push

  • .env.example regression
  • Drop BILLING_ENABLED (stripe branch is always-on)
  • Nav middleware: avoid extra DB round-trip on hot paths
  • Webhook: don’t permanently claim ignored events as processed
  • Footer redesign → separate PR to main
  • Standardize permission checks on has_permission
  • Narrow type hints (set[str], etc.)
  • Custom exceptions for Stripe failures (not generic 503 / wrong 403)
  • Review load_dotenv() at import time in main.py

Issue #3 will be resolved against stripe, not main.

Restore .env.example, drop BILLING_ENABLED, optimize nav middleware,
fix webhook retry semantics, use custom Stripe exceptions, standardize
has_permission checks, and revert unrelated footer redesign.
@chriscarrollsmith

Copy link
Copy Markdown
Contributor

Follow-up commit pushed (a9f578d) addressing the review checklist from the stripe-branch plan:

  • .env.example: restored full template vars; billing block appended at bottom
  • BILLING_ENABLED: removed — billing is always on for this branch (stripe branch model)
  • Nav middleware: skips non-GET, /static, and /webhooks; single DB query via resolve_billing_nav_href
  • Webhooks: expected events with missing metadata now return RETRYABLE → claim released, HTTP 500 (Stripe retries); unknown event types still IGNORED with claim kept
  • Footer redesign: reverted here; separate PR to main (see below)
  • Permissions: read_billing uses user.has_permission() consistently
  • Exceptions: ActiveSubscriptionError, StripeServiceUnavailableError, StripeSessionError
  • load_dotenv(): moved back to lifespan (not import time); removed main.py E402 ignore

Footer split: #225 (or whatever number gh assigns)

@chriscarrollsmith

Copy link
Copy Markdown
Contributor

Footer split PR: #226

rafizamankhan and others added 3 commits July 7, 2026 13:46
Resolve conflicts: keep stripe dep in pyproject.toml, combine Stripe
test env with main's CSRF browser fixtures, adopt main's utc_naive helpers.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add payments/billing system

2 participants