Commit 05c3725
feat: billing entitlements — Marketplace plans drive tier limits and the hosted paid gate (#66)
* feat: billing entitlements — Marketplace plans drive tier limits and the hosted paid gate
Turn purchased plans into enforced entitlements, the monetization layer on
top of the shipped limit knobs (docs/pricing.md):
- config: PlanTier (starter/team/dedicated) with the pricing-matrix limits,
effective_limits precedence (explicit TOML wins per field), and a
[billing] require_plan gate for hosted deployments.
- store (schema v6): account_plans + installation_accounts — Marketplace
bills accounts, tenancy keys installations; the mapping joins them.
Uninstall forgets the mapping but keeps the account's plan.
- webhook: marketplace_purchase deliveries (purchased/changed/cancelled,
trial state, pending changes deferred) upsert the plan idempotently and
land in the audit trail; installation events keep the account mapping
current; intake resolves plan-tier limits and, with require_plan, records
plan-less installations as ignored:no_plan.
- worker: claim-time concurrency caps merge plan tiers under explicit TOML
caps, re-read each claim so plan changes apply without restart.
Unknown plan names fail safe to Starter limits so a listing rename never
grants unlimited service or locks a paying customer out.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Val Alexander <bunsthedev@gmail.com>
* fix(webhook,store): apply marketplace plan transitions atomically with delivery dedup
Review finding: the handler recorded the delivery id in one transaction and
applied the plan in another. A storage failure between the two marked the
delivery seen while dropping the transition — a redelivery would dedupe and
never repair it, leaving a cancelled account entitled forever or a paying
customer locked out under require_plan.
record_delivery_with_plan now lands the dedup row and the plan upsert in one
Immediate transaction (mirroring record_delivery_sync's task handling), so
'delivery seen' and 'plan applied' cannot diverge. Stale replays still cannot
clobber newer state. Audit remains non-fatal: observability, not entitlement.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Val Alexander <bunsthedev@gmail.com>
---------
Signed-off-by: Val Alexander <bunsthedev@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent 63296ff commit 05c3725
9 files changed
Lines changed: 1051 additions & 7 deletions
File tree
- config
- crates
- config/src
- store/src
- webhook/src
- worker/src
- docs
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
54 | 63 | | |
55 | 64 | | |
56 | 65 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
96 | 96 | | |
97 | 97 | | |
98 | 98 | | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
99 | 111 | | |
100 | 112 | | |
101 | 113 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 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 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
36 | 136 | | |
37 | 137 | | |
38 | 138 | | |
| |||
737 | 837 | | |
738 | 838 | | |
739 | 839 | | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
740 | 846 | | |
741 | 847 | | |
742 | 848 | | |
| |||
1488 | 1594 | | |
1489 | 1595 | | |
1490 | 1596 | | |
| 1597 | + | |
1491 | 1598 | | |
1492 | 1599 | | |
1493 | 1600 | | |
| |||
2406 | 2513 | | |
2407 | 2514 | | |
2408 | 2515 | | |
| 2516 | + | |
| 2517 | + | |
| 2518 | + | |
| 2519 | + | |
| 2520 | + | |
| 2521 | + | |
| 2522 | + | |
| 2523 | + | |
| 2524 | + | |
| 2525 | + | |
| 2526 | + | |
| 2527 | + | |
| 2528 | + | |
| 2529 | + | |
| 2530 | + | |
| 2531 | + | |
| 2532 | + | |
| 2533 | + | |
| 2534 | + | |
| 2535 | + | |
| 2536 | + | |
| 2537 | + | |
| 2538 | + | |
| 2539 | + | |
| 2540 | + | |
| 2541 | + | |
| 2542 | + | |
| 2543 | + | |
| 2544 | + | |
| 2545 | + | |
| 2546 | + | |
| 2547 | + | |
| 2548 | + | |
| 2549 | + | |
| 2550 | + | |
| 2551 | + | |
| 2552 | + | |
| 2553 | + | |
| 2554 | + | |
| 2555 | + | |
| 2556 | + | |
| 2557 | + | |
| 2558 | + | |
| 2559 | + | |
| 2560 | + | |
| 2561 | + | |
| 2562 | + | |
| 2563 | + | |
| 2564 | + | |
| 2565 | + | |
| 2566 | + | |
| 2567 | + | |
| 2568 | + | |
| 2569 | + | |
| 2570 | + | |
| 2571 | + | |
| 2572 | + | |
| 2573 | + | |
| 2574 | + | |
| 2575 | + | |
| 2576 | + | |
| 2577 | + | |
| 2578 | + | |
0 commit comments