feat: limit free users to 1 phone API key#894
Conversation
Add entitlement check to the phone API key creation endpoint so free users can only create 1 phone API key. Paid users remain unlimited. Self-hosted setups are unaffected (controlled by ENTITLEMENT_ENABLED). Reuses the existing EntitlementService pattern from send schedules: - Add PhoneAPIKey to entityLimits map (free: 1) - Add CountByUser to PhoneAPIKeyRepository and service - Inject EntitlementService into PhoneAPIKeyHandler - Check entitlement before creating, return 402 if exceeded Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 0 |
| Duplication | 3 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
Greptile SummaryThis PR gates phone API key creation behind the existing
Confidence Score: 3/5The entitlement limit is wired correctly end-to-end, but the user-facing error message will be garbled for all free users who hit the cap, a visible regression that surfaces immediately in production. The core limit enforcement logic is sound, but the entity name "PhoneAPIKey" interacts badly with formatEntityName's character-by-character uppercase split, producing a clearly broken error string for every user who exceeds the free-tier cap. The fix is small (rename the key to "PhoneApiKey" in two places), but without it the feature ships with broken UX on its most visible user-facing output. api/pkg/services/entitlement_service.go and api/pkg/handlers/phone_api_key_handler.go both need the entity name corrected to "PhoneApiKey". Important Files Changed
Reviews (1): Last reviewed commit: "feat: limit free users to 1 phone API ke..." | Re-trigger Greptile |
| "PhoneAPIKey": { | ||
| entities.SubscriptionNameFree: 1, | ||
| }, |
There was a problem hiding this comment.
The entity name
"PhoneAPIKey" contains consecutive uppercase letters, which breaks formatEntityName. The function splits on every uppercase character boundary individually, so "PhoneAPIKey" becomes the words ["phone", "a", "p", "i", "key"], producing the error message: "Upgrade to a paid plan to create more than [1] phone a p i keys." — which is clearly unreadable. Using "PhoneApiKey" splits correctly into ["phone", "api", "key"] → "phone api keys".
| "PhoneAPIKey": { | |
| entities.SubscriptionNameFree: 1, | |
| }, | |
| "PhoneApiKey": { | |
| entities.SubscriptionNameFree: 1, | |
| }, |
|
|
||
| userID := h.userIDFomContext(c) | ||
|
|
||
| result, err := h.entitlementService.Check(ctx, userID, "PhoneAPIKey", func() (int, error) { |
There was a problem hiding this comment.
The entity name must match the key in
entityLimits. If the key is renamed to "PhoneApiKey" in entitlement_service.go (to fix the malformed error message), this lookup must be updated too — otherwise the entitlement check always returns Allowed: true because the key isn't found in the map.
| result, err := h.entitlementService.Check(ctx, userID, "PhoneAPIKey", func() (int, error) { | |
| result, err := h.entitlementService.Check(ctx, userID, "PhoneApiKey", func() (int, error) { |
Summary
Add entitlement check to the phone API key creation endpoint so free users can only create 1 phone API key. Paid users remain unlimited. Self-hosted setups are unaffected (controlled by \ENTITLEMENT_ENABLED\ env var).
Changes
Reuses the existing \EntitlementService\ pattern from send schedules:
Behavior
No frontend changes needed — the existing error toast already displays the API response message.