Commit 73eb6e6
feat: don't create customers for customer seats (#8789)
* feat: implement member model support for customer seats
Decouple seat members from Customer entities by adding a member_model_enabled
feature flag. When enabled, Members exist independently under the billing
customer (purchaser), with customer_id on CustomerSeat referencing the
purchaser rather than the seat occupant. Includes new email column on
CustomerSeat for pending invitations.
🤖 Generated with Claude Code
Co-Authored-By: Claude Haiku 4.5 <[email protected]>
* chore: remove accidentally committed .npmrc file
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* fix: correct test assertions for member_model_enabled behavior
The test was expecting seat.customer_id to equal the seat member's customer,
but with member_model_enabled=True, seat.customer_id should equal the billing
customer (subscription owner). Updated assertions to match the actual
implementation behavior.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* refactor: address PR review comments and add missing tests
- Simplify revoke_seat by clearing all identifiers unconditionally
- Combine validation conditions into single check in assign_seat
- Add Order.product.organization eager loading in repository
- Move MemberRepository import to top of file
- Add imports guideline to CLAUDE.md
- Add tests for member_model_enabled flows:
- test_claim_seat_with_member_model_enabled
- test_revoke_seat_with_member_model_enabled
- test_resend_invitation_with_member_model_enabled
- test_assign_seat_rejects_customer_id_when_member_model_enabled
- test_assign_seat_requires_email_when_member_model_enabled
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* refactor: simplify seat assignment with SeatAssignmentTarget pattern
Introduce SeatAssignmentTarget dataclass to unify the seat creation logic.
The only branching point is now resolving the target (who the seat is for),
while seat creation, token generation, and notifications are unified.
Changes:
- Add SeatAssignmentTarget dataclass with customer_id, member_id, email, seat_member_email
- Add _resolve_member_model_target() for member_model_enabled=True path
- Add _resolve_legacy_target() for member_model_enabled=False path
- Refactor assign_seat() to use unified seat creation logic
- Simplify claim_seat() to share validation and claim logic between paths
This reduces code duplication and makes the feature flag logic clearer.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
---------
Co-authored-by: Claude Haiku 4.5 <[email protected]>1 parent 903d966 commit 73eb6e6
File tree
8 files changed
+692
-107
lines changed- server
- polar
- customer_portal/endpoints
- customer_seat
- member
- tests/customer_seat
8 files changed
+692
-107
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
142 | 142 | | |
143 | 143 | | |
144 | 144 | | |
| 145 | + | |
145 | 146 | | |
146 | 147 | | |
147 | 148 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
168 | 168 | | |
169 | 169 | | |
170 | 170 | | |
171 | | - | |
| 171 | + | |
172 | 172 | | |
173 | 173 | | |
174 | 174 | | |
175 | 175 | | |
176 | | - | |
| 176 | + | |
177 | 177 | | |
178 | 178 | | |
179 | 179 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
341 | 341 | | |
342 | 342 | | |
343 | 343 | | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
344 | 354 | | |
345 | 355 | | |
346 | 356 | | |
347 | 357 | | |
348 | 358 | | |
349 | | - | |
| 359 | + | |
350 | 360 | | |
351 | 361 | | |
352 | 362 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
59 | 59 | | |
60 | 60 | | |
61 | 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 | + | |
62 | 115 | | |
63 | 116 | | |
64 | 117 | | |
| |||
358 | 411 | | |
359 | 412 | | |
360 | 413 | | |
361 | | - | |
| 414 | + | |
362 | 415 | | |
363 | 416 | | |
364 | 417 | | |
| 418 | + | |
365 | 419 | | |
366 | 420 | | |
367 | 421 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
98 | | - | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
99 | 112 | | |
100 | 113 | | |
101 | 114 | | |
| |||
110 | 123 | | |
111 | 124 | | |
112 | 125 | | |
113 | | - | |
114 | | - | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
115 | 132 | | |
116 | 133 | | |
117 | 134 | | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
127 | 150 | | |
128 | 151 | | |
129 | 152 | | |
| |||
0 commit comments