Skip to content

release: Stripe Connect Express — the platform mints the tenant account (E1-E7) - #235

Merged
mahmutkaya merged 8 commits into
mainfrom
develop
Sep 5, 2026
Merged

mahmutkaya merged 8 commits into
mainfrom
develop

Conversation

@mahmutkaya

Copy link
Copy Markdown
Contributor

Release — Stripe Connect Express: the platform mints the tenant's account

Eight commits (#227#234). This is the full E1–E7 migration from Connect Standard to Connect Express,
which is what ADR-011 always specified — the implementation
had drifted to Standard.

PR Slice
#227 E1 — persist the account we mint, before the registry PR, with a slug-derived idempotency key
#228 E2 — mint an Express account, prefilled, three capabilities in one call
#229 E3 — the provenance flip: one registry PR carries stripe_account: and online-payments
#230 E4 — /onboarding/payments/<token>, minting a fresh Stripe link per request
#231 E6 — the control plane says what Express actually does, + Referrer-Policy: no-referrer
#232 E5 — account.updated, so we learn when a restaurant finishes
#233 E7a — the registry entry carries the finished payments_link_url:
#234 E7b — ADR-011 amendment, and it corrects its own earlier Standard claim

THREE migrations, founder-run BEFORE the app rollout

  1. 20260905190000_stripe_connect_account
  2. 20260905210000_connect_account_onboarding_token
  3. 20260905230000_stripe_account_status

All additive. Nothing in this release reads them until an account is minted, and none can be minted until the
owner-side prerequisites below exist.

Why E1 shipped first

No column stored acct_ anywhere. A crash between minting a live Stripe account and composing the
registry PR would have lost a real account with no record it existed. Idempotency measured against Stripe:
same key + same body returns the same account; a one-character key change returns a different one.

What is still inert

Every tenant is flat / 0 bps. No tenant has a stripe_account — verified with a positive control. The
mint cannot succeed until the platform key carries Connect -> write, and until then every online-payments
tenant takes the last-resort deferral path, which is deliberately kept: without it a failed mint would
mean no tenant at all rather than a tenant without card payments.

Known product limitation, recorded not hidden

Stripe fixes an account's country permanently at creation and we store no country. Country is derived from
currency (CHF, GBP, USD, AED) and EUR is refused, because seven countries share it. A EUR restaurant does
not get card payments until a founder acts by hand. Filed in BACKLOG with the fix costed.

Rollout

Run the three migrations with ghcr.io/piwas-21/sofra:migrate, then compose pull sofra && up -d sofra.
Verify /api/health reports this merge commit and POST /api/webhooks/stripe still answers 400.

…2) (#228)

* feat(payments): mint a tenant Express connected account, prefilled (E2)

* docs(env): the platform key now needs Connect -> write, and only in the control plane (E2)

* chore(payments): NON_IBAN_COUNTRIES is a Set (SonarCloud S7776)
… Stripe link per request (E4) (#230)

* feat(payments): the restaurant's own onboarding page, minting a fresh Stripe link per request (E4)

* chore(payments): read-only props on the onboarding page (SonarCloud S6759)
…finished (E7a) (#233)

* feat(payments): the registry entry carries the tenant payments link, finished (E7a)

* chore(payments): build the payments link with URL(), not a backtracking regex (SonarCloud S5852)
@sonarqubecloud

sonarqubecloud Bot commented Sep 5, 2026

Copy link
Copy Markdown

@mahmutkaya
mahmutkaya merged commit 7ebf3d1 into main Sep 5, 2026
23 checks passed
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.

1 participant