| name | rails-inertia-stripe-billing |
| description | Use this skill when the user wants Stripe subscription billing for a Rails + Inertia.js + React + TypeScript app: Plan PORO, Account::Subscription, Account::Billing concern, Stripe Checkout, Billing Portal, plan switching (upgrade/downgrade), webhook-driven sync, admin comping, feature limits, admin notification settings, billing mailers, and the related frontend pages/tests. |
Stripe Subscription Billing
Install Stripe subscription billing on a Rails 8 + Inertia.js + React + TypeScript project.
The asset bundle is the source of truth and should overwrite the matching billing files in the target project.
Use This Skill For
- Plan PORO (Free + Pro Monthly/Yearly, Stripe price IDs from ENV)
- Account::Subscription model (Stripe state mirror)
- Account::Billing concern (plan resolution, lifecycle hooks, comping)
- Account::Limited concern (feature limits, usage tracking, overrides)
- Stripe Checkout flow (new subscriptions)
- Stripe Billing Portal (manage payment, cancel)
- Plan switching via Billing Portal flow_data (monthly <-> yearly)
- Webhook-driven subscription sync (checkout.session.completed, updated, deleted)
- Admin comping via BillingWaiver (account-scoped)
- Admin notification settings (SiteSetting, email toggles)
- Billing mailers (subscription activated, account cancellation, admin notifications)
- Identity email -> Stripe customer email sync
- Public pricing page with auth-aware CTAs
- In-app billing page with subscription state UI
- Checkout success page with polling
Prerequisites
- Draft UI skill already applied (layouts, sidebar, public pages, admin pages)
- Auth + Tenant skill already applied (Identity/User/Account pattern, Cancellable, Incineratable)
- Rails 8.1+, PostgreSQL
- A clean worktree is strongly preferred before running the installer
What It Installs
- Gem:
stripe (via bundle add)
- Models (10 new): Plan, Account::Subscription, Account::BillingWaiver, Account::UsageOverride, Account::Billing, Account::Limited, SiteSetting, DashboardReport, DashboardDateRange, Identity::NotifiesAccountsOfEmailChange
- Controllers (9 new): SubscriptionsController, BillingPortalsController, Upgrades/DowngradesController, Stripe::WebhooksController, Admin::Accounts::BillingWaiversController, Admin::Settings::NotificationsController, BillingPortalConfiguration concern
- Controllers (8 modified): InertiaController (shared plan props), PagesController (pricing plans), CustomersController (billing data), DashboardsController, Authentication (pricing intent), RegistrationsController, SessionsController, BillingsController
- Mailers (3 new): SubscriptionMailer, AccountMailer, AdminNotificationMailer + 8 view templates (HTML + text)
- Jobs (1 new): Account::SyncStripeCustomerEmailJob
- Frontend (4 new): subscription/show, notifications/show, date-range-picker component, timezone lib
- Frontend (11 modified): billing/show, pricing, customers/index+show, dashboard/show, settings/show, menus/show, app-sidebar, status-badge, format-date, types/index
- Config: Stripe initializer, updated routes (patched, not overwritten for development.rb)
- Docs: stripe-billing-guide.md (comprehensive operational guide)
- Tests: 14 new test files + 2 support helpers + 1 fixture + 2 modified test files
Installer Contract
Run:
bash $SKILL_DIR/scripts/setup.sh $PROJECT_ROOT
The setup script does all of this:
- adds the
stripe gem and runs bundle install
- verifies auth-tenant prerequisite (Account with Cancellable)
- removes stale files from the pre-billing admin settings structure
- copies the final billing implementation from
assets/ into the project
- patches
config/environments/development.rb to enable perform_deliveries (targeted patch, not overwrite)
- replaces
Enlead/enlead with the target app name (from config/application.rb)
- updates
CLAUDE.md with the stripe-billing-guide note when that file exists
- creates
.env entries for Stripe keys when missing
- deletes old incremental billing migrations and generates a clean baseline set
This skill intentionally overwrites the matching billing files. Modified files include the billing-enhanced versions on top of what auth-tenant provides.
Portability
The asset files use Enlead/enlead as template placeholders. The setup script replaces them with the target project's module name (extracted from config/application.rb). This covers:
- Mailer subjects (
"Your Enlead Pro subscription is active" → "Your MyApp Pro subscription is active")
- Mailer defaults (
"Enlead <noreply@enlead.app>" → "MyApp <noreply@my_app.app>")
- Admin notification prefixes (
"[Enlead]" → "[MyApp]")
- Test assertions matching project name
- Documentation references
Files that are NOT overwritten (patched instead):
config/environments/development.rb — only adds perform_deliveries = true
CLAUDE.md — only inserts the stripe-billing-guide reference line
Migration Policy
The skill generates only these baseline migrations (consolidated from the implementation history):
CreateAccountSubscriptions — subscription state with scheduled plan change columns
CreateAccountBillingWaivers — admin comping
CreateAccountUsageOverrides — admin usage overrides for testing
CreateSiteSettings — admin notification settings
Those templates encode the final schema shape:
account_subscriptions: plan_key, stripe_customer_id (unique), stripe_subscription_id (unique, nullable), status, period dates, cancel_at, next_amount_due_in_cents, scheduled_plan_key, scheduled_starts_at
account_billing_waivers: unique account_id, cascade FK
account_usage_overrides: contacts, projects, team_members (all nullable integers)
site_settings: notification_recipients (string), notify_new_subscription, notify_account_cancellation (booleans)
After the script finishes, run:
bin/rails db:migrate
Verification
Run:
bin/rubocop --autocorrect
npm run check && npm run lint:fix
bin/rails test test/models test/integration test/mailers
Stripe Setup After Installation
See docs/stripe-billing-guide.md for the complete setup, including:
- Create Stripe products and prices (monthly + yearly) via Stripe CLI or Dashboard
- Set environment variables in
.env: STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_MONTHLY_PRICE_ID, STRIPE_YEARLY_PRICE_ID, STRIPE_BILLING_PORTAL_CONFIGURATION_ID
- Configure Billing Portal in Stripe Dashboard: enable subscription updates with both prices, cancellation, payment method updates, invoice history, and schedule-at-period-end for downgrade conditions
- Forward webhooks locally:
stripe listen --forward-to localhost:3000/stripe/webhooks
Customization Points
After running the skill, customize:
- Plan definitions:
Plan::PLANS in app/models/plan.rb (names, prices, limits, Stripe price IDs)
- Feature limits: Add new features to
Plan::PLANS limits hash + account_usage_overrides columns + Account::Limited#compute_usage_for
- Pricing page content: Feature list and FAQ in
app/frontend/pages/pages/pricing.tsx
- Admin sidebar: Billing nav items in
components/admin/app-sidebar.tsx
- Mailer subjects and templates:
app/mailers/ and app/views/{subscription,account,admin_notification}_mailer/
- Notification settings:
SiteSetting model toggles in app/models/site_setting.rb
- Stripe API version: Pinned in
config/initializers/stripe.rb — update when upgrading the stripe gem
Files Removed by Installer
These files from the pre-billing admin settings structure are deleted:
app/controllers/admin/settings/billings_controller.rb
app/controllers/admin/settings/teams_controller.rb
app/frontend/pages/admin/settings/billing/ (directory)
app/frontend/pages/admin/settings/team/ (directory)
Source Of Truth
Treat the files in assets/ as the desired end state for billing behavior in this repo family. The docs/stripe-billing-guide.md is the architecture reference for future billing work.