fix(admin): licence and plan features serialise as [], never null
Server Deploy / deploy (push) Successful in 5m22s
Server Deploy / deploy (push) Successful in 5m22s
Free has no features, so a nil Go slice served "features": null. The portal's type said string[], called .length on it, and took the page down. The guarantee lives on a named Features type with its own MarshalJSON rather than at each of the six places a licence or plan is serialised, because the seventh is the one that would have been forgotten. Applying it at marshal time also fixes rows already holding null in Mongo, which a write-side fix alone would not. Same class, found while checking the rest: staffListInstances built its expiring filter from a nil []string, marshalling to $in: null, which Mongo rejects — so the quiet week when nothing is expiring is precisely when the staff Operations page's own query would have failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -97,7 +97,7 @@ func Issue(ctx context.Context, in IssueInput) (*models.License, error) {
|
||||
// Snapshotted, not referenced: editing a plan tomorrow must not change
|
||||
// what this licence grants.
|
||||
Limits: plan.Limits,
|
||||
Features: plan.Features,
|
||||
Features: plan.Features.OrEmpty(),
|
||||
}
|
||||
|
||||
blob, err := license.Sign(payload, signingKey)
|
||||
@@ -112,7 +112,7 @@ func Issue(ctx context.Context, in IssueInput) (*models.License, error) {
|
||||
Tier: plan.Tier,
|
||||
Deployment: plan.Deployment,
|
||||
Limits: plan.Limits,
|
||||
Features: plan.Features,
|
||||
Features: plan.Features.OrEmpty(),
|
||||
IssuedAt: now,
|
||||
ExpiresAt: expires,
|
||||
Blob: blob,
|
||||
|
||||
Reference in New Issue
Block a user