rastrillo / abono Public

abono v0.1: Stripe memberships for rastrillo apps

abono sends readers to Stripe's hosted Checkout, records the subscriptions
Stripe reports, lets the owner give memberships away, and tells the app
which plan a person holds. It works on the site's own Stripe key, by card,
with a 30-day grace after a failed renewal. The app keeps roles and
accounts through two callbacks (Holder, OnChange). It ships partials, an
approved English catalog, a starter-page generator, a fake Stripe for
tests (abonotest), a development sandbox and an example app.

Extracted from Patrix's paid memberships. Design and plan:
docs/superpowers/specs/2026-10-21-abono-design.md and
docs/superpowers/plans/2026-10-22-abono-v0.1.md in rastrillo.

Squashed from v0.1 into main.
claude agent, operated by paul@keymail.dev 38344cf752cdb246001756962db5687388fdbbf1 parent 5524ac6
100 files changed, +15782 −1
  • .amadan/ci +6 −0
  • .amadan/ci.d/10-vet +3 −0
  • .amadan/ci.d/20-fmt +3 −0
  • .amadan/ci.d/30-test +3 −0
  • .amadan/ci.d/40-race +3 −0
  • .amadan/ci.d/50-browser +3 −0
  • .gitignore +6 −0
  • Makefile +45 −0
  • README.md +3 −1
  • SKILL.md +77 −0
  • abono.go +187 −0
  • abono_test.go +183 −0
  • abonotest/abonotest.go +159 −0
  • abonotest/abonotest_test.go +513 −0
  • adopt.go +159 −0
  • adopt_test.go +238 −0
  • catalog.go +115 −0
  • catalog_test.go +49 −0
  • checkout.go +340 −0
  • checkout_test.go +279 −0
  • cmd/abono/main.go +164 −0
  • cmd/abono/main_test.go +318 −0
  • cmd/abono/pages/abono_pages.go.tmpl +849 −0
  • cmd/abono/pages/account.html.tmpl +33 −0
  • cmd/abono/pages/done.html.tmpl +35 −0
  • cmd/abono/pages/owner-end.html.tmpl +18 −0
  • cmd/abono/pages/owner-members.html.tmpl +80 −0
  • cmd/abono/pages/owner-offers.html.tmpl +66 −0
  • cmd/abono/pages/owner-stripe.html.tmpl +24 −0
  • cmd/abono/pages/plan.html.tmpl +30 −0
  • cmd/abono/pages/pricing.html.tmpl +20 −0
  • comps.go +78 −0
  • comps_test.go +101 −0
  • describe.go +103 −0
  • describe_test.go +97 −0
  • doc.go +10 −0
  • example/README.md +53 −0
  • example/abono_pages.go +849 −0
  • example/app.go +356 −0
  • example/app_test.go +821 −0
  • example/browser_test.go +85 −0
  • example/catalog.go +57 −0
  • example/catalog_test.go +108 −0
  • example/go.mod +38 −0
  • example/go.sum +97 −0
  • example/locales/en.toml +5 −0
  • example/main.go +72 −0
  • example/migrations/0001_init.sql +3 −0
  • example/models.go +109 −0
  • example/templates/abono/account.html +33 −0
  • example/templates/abono/done.html +35 −0
  • example/templates/abono/owner-end.html +18 −0
  • example/templates/abono/owner-members.html +80 −0
  • example/templates/abono/owner-offers.html +66 −0
  • example/templates/abono/owner-stripe.html +24 −0
  • example/templates/abono/plan.html +30 −0
  • example/templates/abono/pricing.html +20 −0
  • example/templates/account.html +4 −0
  • example/templates/layout.html +27 −0
  • example/templates/signin.html +3 −0
  • export_test.go +13 −0
  • go.mod +26 −0
  • go.sum +77 −0
  • holdings.go +273 −0
  • holdings_test.go +282 −0
  • internal/fakestripe/fake.go +977 −0
  • internal/fakestripe/fake_test.go +724 −0
  • internal/fakestripe/pages.go +298 −0
  • internal/stripeapi/client.go +324 −0
  • internal/stripeapi/client_test.go +232 −0
  • internal/stripeapi/signature.go +57 −0
  • internal/stripeapi/signature_test.go +87 −0
  • locales/en.toml +143 −0
  • locks.go +58 −0
  • migrations.go +16 −0
  • migrations/0001_init.sql +87 −0
  • offers.go +306 −0
  • offers_test.go +311 −0
  • owner.go +61 −0
  • owner_test.go +114 −0
  • reconcile.go +118 −0
  • reconcile_test.go +226 −0
  • sandbox.go +101 −0
  • sandbox_test.go +397 −0
  • schema_test.go +159 −0
  • skillmd_test.go +45 −0
  • stripe_double_test.go +174 −0
  • sync.go +389 −0
  • sync_test.go +774 −0
  • templates.go +40 −0
  • templates/abono-billing-button.html +13 −0
  • templates/abono-paywall.html +17 −0
  • templates/abono-plan-card.html +18 −0
  • templates/abono-plan-picker.html +15 −0
  • templates/abono-price.html +8 −0
  • templates/abono-status.html +23 −0
  • templates/abono-subscribe-button.html +16 −0
  • templates_test.go +735 −0
  • webhook.go +244 −0
  • webhook_test.go +411 −0

CI passed — run details

CI log
=== vet ===
go vet ./...
=== fmt ===
=== test ===
go test ./... -count=1
ok  	amadan.net/rastrillo/abono	3.854s
ok  	amadan.net/rastrillo/abono/abonotest	0.148s
ok  	amadan.net/rastrillo/abono/cmd/abono	2.574s
ok  	amadan.net/rastrillo/abono/internal/fakestripe	0.083s
ok  	amadan.net/rastrillo/abono/internal/stripeapi	0.020s
ok  	example	0.506s
=== race ===
CGO_ENABLED=1 go test ./... -race -count=1
ok  	amadan.net/rastrillo/abono	17.003s
ok  	amadan.net/rastrillo/abono/abonotest	1.972s
ok  	amadan.net/rastrillo/abono/cmd/abono	4.528s
ok  	amadan.net/rastrillo/abono/internal/fakestripe	1.166s
ok  	amadan.net/rastrillo/abono/internal/stripeapi	1.045s
ok  	example	4.268s
=== browser ===
ok  	example	2.131s

landed from v0.1

.amadan/ci

Loading diff…

.amadan/ci.d/10-vet

Loading diff…

.amadan/ci.d/20-fmt

Loading diff…

.amadan/ci.d/30-test

Loading diff…

.amadan/ci.d/40-race

Loading diff…

.amadan/ci.d/50-browser

Loading diff…

.gitignore

Loading diff…

Makefile

Loading diff…

README.md

Loading diff…

SKILL.md

Loading diff…

abono.go

Loading diff…

abono_test.go

Loading diff…

abonotest/abonotest.go

Loading diff…

abonotest/abonotest_test.go

Loading diff…

adopt.go

Loading diff…

adopt_test.go

Loading diff…

catalog.go

Loading diff…

catalog_test.go

Loading diff…

checkout.go

Loading diff…

checkout_test.go

Loading diff…

cmd/abono/main.go

Loading diff…

cmd/abono/main_test.go

Loading diff…

cmd/abono/pages/abono_pages.go.tmpl

Loading diff…

cmd/abono/pages/account.html.tmpl

Loading diff…

cmd/abono/pages/done.html.tmpl

Loading diff…

cmd/abono/pages/owner-end.html.tmpl

Loading diff…

cmd/abono/pages/owner-members.html.tmpl

Loading diff…

cmd/abono/pages/owner-offers.html.tmpl

Loading diff…

cmd/abono/pages/owner-stripe.html.tmpl

Loading diff…

cmd/abono/pages/plan.html.tmpl

Loading diff…

cmd/abono/pages/pricing.html.tmpl

Loading diff…

comps.go

Loading diff…

comps_test.go

Loading diff…

describe.go

Loading diff…

describe_test.go

Loading diff…

doc.go

Loading diff…

example/README.md

Loading diff…

example/abono_pages.go

Loading diff…

example/app.go

Loading diff…

example/app_test.go

Loading diff…

example/browser_test.go

Loading diff…

example/catalog.go

Loading diff…

example/catalog_test.go

Loading diff…

example/go.mod

Loading diff…

example/go.sum

Loading diff…

example/locales/en.toml

Loading diff…

example/main.go

Loading diff…

example/migrations/0001_init.sql

Loading diff…

example/models.go

Loading diff…

example/templates/abono/account.html

Loading diff…

example/templates/abono/done.html

Loading diff…

example/templates/abono/owner-end.html

Loading diff…

example/templates/abono/owner-members.html

Loading diff…

example/templates/abono/owner-offers.html

Loading diff…

example/templates/abono/owner-stripe.html

Loading diff…

example/templates/abono/plan.html

Loading diff…

example/templates/abono/pricing.html

Loading diff…

example/templates/account.html

Loading diff…

example/templates/layout.html

Loading diff…

example/templates/signin.html

Loading diff…

export_test.go

Loading diff…

go.mod

Loading diff…

go.sum

Loading diff…

holdings.go

Loading diff…

holdings_test.go

Loading diff…

internal/fakestripe/fake.go

Loading diff…

internal/fakestripe/fake_test.go

Loading diff…

internal/fakestripe/pages.go

Loading diff…

internal/stripeapi/client.go

Loading diff…

internal/stripeapi/client_test.go

Loading diff…

internal/stripeapi/signature.go

Loading diff…

internal/stripeapi/signature_test.go

Loading diff…

locales/en.toml

Loading diff…

locks.go

Loading diff…

migrations.go

Loading diff…

migrations/0001_init.sql

Loading diff…

offers.go

Loading diff…

offers_test.go

Loading diff…

owner.go

Loading diff…

owner_test.go

Loading diff…

reconcile.go

Loading diff…

reconcile_test.go

Loading diff…

sandbox.go

Loading diff…

sandbox_test.go

Loading diff…

schema_test.go

Loading diff…

skillmd_test.go

Loading diff…

stripe_double_test.go

Loading diff…

sync.go

Loading diff…

sync_test.go

Loading diff…

templates.go

Loading diff…

templates/abono-billing-button.html

Loading diff…

templates/abono-paywall.html

Loading diff…

templates/abono-plan-card.html

Loading diff…

templates/abono-plan-picker.html

Loading diff…

templates/abono-price.html

Loading diff…

templates/abono-status.html

Loading diff…

templates/abono-subscribe-button.html

Loading diff…

templates_test.go

Loading diff…

webhook.go

Loading diff…

webhook_test.go

Loading diff…