Repository navigation
Hosted: EEA/UK withdrawal, account closure, and support paths - #1413
Merged
Merged
Conversation
POST /api/billing/withdraw records a withdrawal from the held subscription (dormouse_withdrawals, migration 017) before answering, emails the durable acknowledgement to the Stripe billing email, ends the subscription at once, and refunds every paid invoice payment in full; the cron retries either step. GET /api/billing offers it within three weeks of the start to an EEA, UK, or unknown billing country, and shows the latest withdrawal. POST /api/account/close needs a recent login, cancels every current subscription in Stripe, then records the closure and deletes the account in one statement; billing closed, it refuses an account still holding one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ccount app Checkout discloses the EEA/UK withdrawal right, where the online withdrawal is, the support path, and the model form. /billing adds the Withdrawal row to the confirmation and the Withdraw from contract function, which shows the contract, the statement, and where the acknowledgement goes before Confirm withdrawal, then keeps the acknowledgement. The account page links to it and gains Close account, whose dialog says what closing does to the plan first. The founders opt-in names the profile picture it shows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rt paths The Terms' withdrawal section covers every subscription contract, describes the online function as built, and takes the model form from the shared constant; account closure is self-service and cancels the subscription at once. Privacy records withdrawals and closures, Postmark's acknowledgements, and self-service deletion. pricing.md promotes the withdrawal and closure gates above the fold; hosted.md documents the withdraw route and Account closure; security-hosted gains FAIL IF S288 (withdrawal) and S289 (closure). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deploying mouseterm with
|
| Latest commit: |
68a205a
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://2c0ba29e.mouseterm.pages.dev |
| Branch Preview URL: | https://hosted-billing-rights.mouseterm.pages.dev |
dormouse-bot
left a comment
Collaborator
There was a problem hiding this comment.
After a member withdraws and later buys again, /billing still leads with the old "Withdrawal received" card, which says "Your plan has ended", above the confirmation of the new plan. The summary returns the account's latest withdrawal whatever subscription is now held, and HostedPage renders it unconditionally. The suggestion keeps the card while it describes the held subscription (its settlement still pending) or while nothing is held.
GET /api/billing returned the account's latest withdrawal whatever it now held, so after withdrawing and buying again /billing still led with "Withdrawal received" above the new plan. It now returns it only while nothing is held or it is the held subscription's, its settlement pending. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dormouse-bot
approved these changes
Oct 28, 2026
# Conflicts: # .github/audit/hosted.md # docs/specs/hosted.md # docs/specs/security-hosted.md # hosted/server/account-app.ts # hosted/server/tests/billing-routes.test.ts # scripts/security-rule-ids.json # scripts/spec-word-budgets.json # website/src/pages/Privacy.tsx
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dormouse-bot
approved these changes
Oct 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Billing PR 4b, on main after #1407 and #1408. Billing stays closed.
S289)./checkoutbefore purchase and in the/billingconfirmation, with the model form and where the withdrawal function is.POST /api/billing/withdrawrecords the withdrawal in a new table (migration017) before it answers. It then emails the acknowledgement, with the statement and its date and time, to the Stripe billing email, ends the subscription at once, and refunds every paid invoice payment in full, tax included and with no use deduction. If a step fails, the withdrawal still stands and the 10-minute cron retries it.S290).POST /api/account/closerequires a login from the last 10 minutes. It expires any open checkout and cancels every current subscription in Stripe, then records the closure and deletes the account in one statement. While billing is closed, an account that still holds a subscription gets a 503 and is kept. The dialog explains remaining access and refund eligibility before closing.support@dormouse.sh) are on the pages and in the Terms.pricing.md's withdrawal and closure gates move above the fold.Decisions for review:
TERMS_VERSION(2026-10-28), so the version string doesn't distinguish this revision. Before launch only the admin account has accepted any terms.Legal wording for review:
website/src/lib/hosted-withdrawal.ts: the statement and the model form.website/src/pages/Terms.tsx: withdrawal now covers "a Hosted subscription contract" rather than the initial one, and adds "An automatic renewal does not start a new withdrawal period". The online function is described as built, and the closure paragraph is rewritten.website/src/pages/Privacy.tsx: the withdrawal and closure records, Postmark, retention, and self-service closure.hosted/src/Withdrawal.tsx,hosted/src/Plan.tsx(the Withdrawal row, the support-cancel sentence, and the founders label, which now names the profile picture),hosted/src/Closure.tsx, and the acknowledgement email inhosted/server/withdrawal.ts.Not verified yet: StripeDev models neither refunds nor immediate cancel, so withdrawal and closure run end to end only against the test fake. Nobody has walked them in the running app.
Left for a later PR: renewal, annual, price-change and California notices; the dispute-suspension notice; billing-email routing for notices; and notice-delivery records.
Rule IDs:
S289andS290(renumbered after #1408 tookS288).🤖 Generated with Claude Code