Commit d414763
authored
feat(checkout): let buyers choose Server capacity (#7782)
Adds the capacity step to self-hosted checkout. the field is ignored
until [#325
](Stirling-Tools/Stirling-PDF-SaaS#325) lands.
<img width="1262" height="487" alt="image"
src="https://github.com/user-attachments/assets/c22d0b15-103a-491a-bd98-df772e63c71b"
/>
## What it does
A capacity stage between billing period and payment, for the **Server
tier only**. Enterprise is priced per seat and Free has nothing to size,
so both go straight to payment exactly as before.
The stepper counts **servers**, because that is the unit we sell. Every
figure beside it is stated in **users**, because that is the unit an
admin measures. The line item does the translation, so a buyer picks "3
servers" and reads "300 users" without converting anything themselves.
`server_quantity` now rides `createCheckoutSession` through to the edge
function. Before this the base line item was always `quantity: 1`, and
the only way to buy more capacity was Stripe's own portal after the
fact.
## Two guards on the stepper
**It cannot go below current usage.** An installation running 240 users
cannot buy fewer than three servers. Reducing capacity is a renewal
conversation, not something checkout should do by stranding accounts
that already exist.
**At five servers, or a thousand users, it offers an enterprise quote**
beside the purchase. Deliberately an option and not a gate — self-serve
checkout still completes. `onContactSales` is optional, so the door only
appears where a caller wires it up.
## Review notes
- **`USERS_PER_SERVER = 100` is a frontend constant** in
`utils/capacity.ts`. The authoritative value lives on `pricing_policy`
and is resolved server-side at licence-issue time, but before a purchase
there is no licence to read it from and the packaging RPC is not
anon-callable. The comment says so. A follow-up could serve it from
`stripe-price-lookup`, which the plan page already calls; I kept it out
of scope so this PR stays inside one repo.
- The `SELF_SERVE_MAX_SERVERS` bound here is cosmetic. `create-checkout`
clamps server-side against the policy, so a crafted request cannot
exceed it regardless of what the stepper allows.
- No copy sweep needed — `plan.features.usersIncluded` already reads
"100 users included" on main.
## Testing
- 5 unit tests on the capacity arithmetic and the enterprise-door
threshold.
- 5 Storybook stories: single server, multiple servers monthly,
constrained by current users, below current usage (blocked), and the
enterprise door.1 parent 7604729 commit d414763
11 files changed
Lines changed: 437 additions & 3 deletions
File tree
- frontend/editor
- public/locales/en-US
- src/proprietary
- services
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6311 | 6311 | | |
6312 | 6312 | | |
6313 | 6313 | | |
| 6314 | + | |
| 6315 | + | |
| 6316 | + | |
| 6317 | + | |
| 6318 | + | |
| 6319 | + | |
| 6320 | + | |
| 6321 | + | |
| 6322 | + | |
| 6323 | + | |
| 6324 | + | |
| 6325 | + | |
| 6326 | + | |
| 6327 | + | |
| 6328 | + | |
| 6329 | + | |
| 6330 | + | |
6314 | 6331 | | |
6315 | 6332 | | |
6316 | 6333 | | |
| |||
Lines changed: 24 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
| 22 | + | |
21 | 23 | | |
22 | 24 | | |
23 | 25 | | |
| |||
83 | 85 | | |
84 | 86 | | |
85 | 87 | | |
| 88 | + | |
86 | 89 | | |
87 | 90 | | |
88 | 91 | | |
| |||
106 | 109 | | |
107 | 110 | | |
108 | 111 | | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
109 | 116 | | |
110 | 117 | | |
111 | 118 | | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
112 | 125 | | |
113 | 126 | | |
114 | 127 | | |
| |||
234 | 247 | | |
235 | 248 | | |
236 | 249 | | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
237 | 261 | | |
238 | 262 | | |
239 | 263 | | |
| |||
Lines changed: 3 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
76 | 77 | | |
77 | 78 | | |
78 | 79 | | |
| 80 | + | |
79 | 81 | | |
80 | 82 | | |
81 | 83 | | |
| |||
111 | 113 | | |
112 | 114 | | |
113 | 115 | | |
| 116 | + | |
114 | 117 | | |
115 | 118 | | |
116 | 119 | | |
| |||
Lines changed: 5 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
| 24 | + | |
23 | 25 | | |
24 | 26 | | |
25 | 27 | | |
| |||
50 | 52 | | |
51 | 53 | | |
52 | 54 | | |
| 55 | + | |
53 | 56 | | |
54 | 57 | | |
55 | 58 | | |
| |||
64 | 67 | | |
65 | 68 | | |
66 | 69 | | |
| 70 | + | |
| 71 | + | |
67 | 72 | | |
68 | 73 | | |
69 | 74 | | |
| |||
Lines changed: 80 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
0 commit comments