Skip to content

fix(backend): serialize mongodb-memory-server startup - #518

Open
samxu01 wants to merge 1 commit into
mainfrom
ops/TASK-080-flaky-ci-mongodb-memory-server
Open

fix(backend): serialize mongodb-memory-server startup#518
samxu01 wants to merge 1 commit into
mainfrom
ops/TASK-080-flaky-ci-mongodb-memory-server

Conversation

@samxu01

@samxu01 samxu01 commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Resolves TASK-080. Serializes in-memory MongoDB startup in backend test utilities so concurrent suite setup cannot race MongoMemoryServer.create. Adds async-mutex to backend devDependencies. Rollback plan: revert the test utility guard and package dependency if follow-up validation shows no longer needed. Zero-downtime: ✓.

samxu01 pushed a commit that referenced this pull request Aug 6, 2026
Three users want to pay, so this wires the money path onto the entitlement
seam that already existed. `entitlements.pro` was already the single gate the
product reads; Stripe now writes it.

**The webhook is the only source of truth.** Nothing in the checkout success
path grants anything — the redirect is attacker-controllable and a session can
be abandoned after redirect. Only a signature-verified event moves the flag.

**Idempotent by durable marker.** Stripe retries for up to three days and
guarantees neither once-only delivery nor ordering. `BillingEvent`'s unique
index is the lock, claimed BEFORE the user is touched (test asserts the
ordering): a crash between the two would otherwise apply a change with no
record, and the retry would apply it twice.

**Entitlement is DERIVED from subscription status, never toggled.** Every
handler recomputes `pro` from the status Stripe reports, so out-of-order
delivery converges instead of latching — pinned by a revoke-then-regrant test.
`active`/`trialing` grant; everything else revokes.

**Checkout grants only when money settled** (`payment_status === 'paid'`). A
completed session with an async or failed payment is not money.

**Raw body, mounted before express.json().** `constructEvent` verifies the
exact bytes; a re-serialized body fails verification, which is the single most
common way this integration breaks. Follows the existing Discord pattern in
server.ts, and a test asserts the handler receives a Buffer.

**The exit always works.** `POST /billing/portal` gives self-serve
cancellation. A user who cannot find the exit disputes the charge instead. And
revoking Pro leaves `cloudAgents` untouched — separate entitlements, pinned.

**UI** — a v2 Plan panel on /v2/settings reading the same `=== true` check the
backend gates on, so it can never claim a tier the API would refuse. It never
writes the flag; after checkout the user may briefly still read Free, and the
copy says so rather than faking optimistic state. en/zh parity asserted.

Ships INERT: all three of STRIPE_SECRET_KEY / STRIPE_PRICE_ID /
STRIPE_WEBHOOK_SECRET must be set or every billing route returns 503 rather
than half-working. Documented in .env.example; keys belong in Secret Manager.

43 new tests (21 service, 14 route, 8 panel). Backend suite compared against a
same-commit baseline: identical failure set apart from one known-flaky
mongodb-memory-server ordering case that passes 4/4 in isolation (#518).
lilyshen0722 added a commit that referenced this pull request Aug 6, 2026
* feat(billing): Stripe subscriptions end to end (#768)

Three users want to pay, so this wires the money path onto the entitlement
seam that already existed. `entitlements.pro` was already the single gate the
product reads; Stripe now writes it.

**The webhook is the only source of truth.** Nothing in the checkout success
path grants anything — the redirect is attacker-controllable and a session can
be abandoned after redirect. Only a signature-verified event moves the flag.

**Idempotent by durable marker.** Stripe retries for up to three days and
guarantees neither once-only delivery nor ordering. `BillingEvent`'s unique
index is the lock, claimed BEFORE the user is touched (test asserts the
ordering): a crash between the two would otherwise apply a change with no
record, and the retry would apply it twice.

**Entitlement is DERIVED from subscription status, never toggled.** Every
handler recomputes `pro` from the status Stripe reports, so out-of-order
delivery converges instead of latching — pinned by a revoke-then-regrant test.
`active`/`trialing` grant; everything else revokes.

**Checkout grants only when money settled** (`payment_status === 'paid'`). A
completed session with an async or failed payment is not money.

**Raw body, mounted before express.json().** `constructEvent` verifies the
exact bytes; a re-serialized body fails verification, which is the single most
common way this integration breaks. Follows the existing Discord pattern in
server.ts, and a test asserts the handler receives a Buffer.

**The exit always works.** `POST /billing/portal` gives self-serve
cancellation. A user who cannot find the exit disputes the charge instead. And
revoking Pro leaves `cloudAgents` untouched — separate entitlements, pinned.

**UI** — a v2 Plan panel on /v2/settings reading the same `=== true` check the
backend gates on, so it can never claim a tier the API would refuse. It never
writes the flag; after checkout the user may briefly still read Free, and the
copy says so rather than faking optimistic state. en/zh parity asserted.

Ships INERT: all three of STRIPE_SECRET_KEY / STRIPE_PRICE_ID /
STRIPE_WEBHOOK_SECRET must be set or every billing route returns 503 rather
than half-working. Documented in .env.example; keys belong in Secret Manager.

43 new tests (21 service, 14 route, 8 panel). Backend suite compared against a
same-commit baseline: identical failure set apart from one known-flaky
mongodb-memory-server ordering case that passes 4/4 in isolation (#518).

* docs(billing): record why automatic_tax is absent from the Checkout session

The Stripe price is now tax_behavior: inclusive, so a customer pays exactly
the advertised $12 in every jurisdiction rather than $12 plus whatever their
region adds. Without that setting the Australian preview billed $13.20 against
a landing page promising $12.

automatic_tax stays off: Stripe Tax is not activated on the account and
enabling it would fail session creation. Inclusive pricing is the half that
cannot be changed later without moving the sticker price, so it is set now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeUH4HVDsDHYPsHJthXjB8

* fix(landing): the Pro card promised "Free in beta" above a $12 price

The badge shipped with the pricing rewrite and survived the commit that turns
real billing on, so the page currently advertises the paid tier as free in
both locales ("Free in beta" / "公测期免费") directly above "$12/human/mo".
Charging someone who signed up under that banner is a dispute, not a
misunderstanding.

Removed rather than reworded: the accent border already marks the featured
tier, and every short badge available for a paid plan is either a price
promise we would have to keep or a popularity claim we cannot substantiate.
The absolutely-positioned rule went with it.

Guarded by a test asserting no tier that shows a non-zero price describes
itself as free. Scoped to the cost-describing fields only — the feature
bullets legitimately say "Everything in Cloud free", which names a tier
rather than making a price claim. Verified by reintroducing the badge and
watching both locales fail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeUH4HVDsDHYPsHJthXjB8

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.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.

2 participants