You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
'[billing] planDefinitions object shape is deprecated, switch to array — see docs/migrations/2026-05-01-billing-plan-definitions-array.md. Will be removed ~2026-07.',
During PR-N6 (#3555), the `enterprise` plan was present in `billing.plans` but missing from `billing.planDefinitions`. This silent divergence would have caused `ensureSeeded()` to skip seeding the enterprise plan, resulting in a `null` return from `getActivePlan('enterprise')` and a 503 for all metered enterprise users.
6
+
7
+
The root cause: `plans` (enum array) and `planDefinitions` (definition map) were two separate declarations that had to be kept in sync manually. The fix is to make `planDefinitions` the single source of truth — `plans` is now derived at boot.
8
+
9
+
## Before / After
10
+
11
+
**Before (object-keyed — deprecated):**
12
+
13
+
```js
14
+
billing: {
15
+
plans: ['free', 'starter', 'pro', 'enterprise'], // must match planDefinitions keys — drift risk
`config.billing.plans` is still available at runtime (derived by `config/index.js`) — `z.enum(config.billing.plans)` and all Zod/Mongoose schemas keep working unchanged.
40
+
41
+
## Downstream migration steps
42
+
43
+
For each downstream project that overrides `billing.planDefinitions` (e.g. `modules/billing/config/billing.{project}.config.js`):
44
+
45
+
1. Pull the latest devkit: `npm run update-stack` (or merge the upstream devkit branch).
46
+
2. Open `modules/billing/config/billing.{project}.config.js`.
47
+
3. Convert `planDefinitions` from object to array form (see Before/After above). Remove the `plans: [...]` line — leaving it is harmless (the derivation in `config/index.js` runs after deepMerge and overwrites it), but remove it to avoid confusion.
48
+
4. Run unit tests: `NODE_ENV={project} npm run test:unit -- billing`.
49
+
5. Smoke test the plans endpoint: `curl https://api.{project}.example.com/api/billing/plans`.
50
+
51
+
No database migration is required — the `BillingPlan` collection is unchanged.
52
+
53
+
## Validation
54
+
55
+
After migration, confirm:
56
+
57
+
- Boot logs show **no**`[billing] planDefinitions object shape is deprecated` warning (shim did not trigger).
58
+
-`NODE_ENV={project} npm run test:unit -- billing` passes.
59
+
-`[billing] Subscription.plan value "..." not in planDefinitions` warning is **absent** in boot logs (no orphaned subscriptions).
60
+
61
+
## Shim removal timeline
62
+
63
+
The backward-compat shim in `config/index.js` converts legacy object-keyed `planDefinitions` to array form with a `console.warn`. It will be removed **~2026-07-01**, contingent on:
64
+
65
+
- Zero deprecation warnings observed in any downstream prod log for ≥ 30 days.
66
+
- All downstream projects confirmed migrated to array form.
67
+
68
+
Track removal in a follow-up issue once all downstreams are migrated.
0 commit comments