feat: add Premium Geo DB addon to project settings#2981
Conversation
Adds a Premium Geo DB section to the project settings page so users can enable and disable the premium geolocation addon per-project on cloud. The section supports the full addon lifecycle: - Upgrade prompt when the current plan does not support the addon - Enable flow with optional 3DS payment authentication - Pending state with cancel & retry option - Active state with disable action - Scheduled-for-removal state with re-enable action Uses the new project-scoped SDK methods: listAddons, createPremiumGeoDBAddon, and deleteAddon. Bumps the @appwrite.io/console SDK pin accordingly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR adds a Premium Geo DB addon section to the project settings page, mirroring the existing BAA flow at the org level. The load function, settings page, and three new components wire up the full enable/active/pending/scheduled-for-removal lifecycle.
Confidence Score: 3/5The payment lifecycle in premiumGeoDBEnableModal and premiumGeoDB is incomplete relative to the BAA reference, leaving several real-money flows without proper feedback or recovery paths. The SvelteKit load function and page-mount integration are solid. However, the Stripe payment handling in the enable modal and the re-enable path in the main component omit critical steps that the BAA implementation handles correctly — outcome inspection, confirmAddonPayment finalisation, and error recovery. Until those gaps are closed, users can pay without the addon activating, or receive false-success notifications while the addon remains in a pending or unconfirmed state. premiumGeoDBEnableModal.svelte and premiumGeoDB.svelte carry the payment flow gaps; planSummary.svelte deserves a second look once the billing API behaviour around per-project addon resources is confirmed. Important Files Changed
Reviews (19): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile |
Mirrors the BAA addon UX by fetching the addon price via organizations.getAddonPrice(Addon.Premiumgeodb) from the settings page loader, passing it through to the Premium Geo DB card and enable modal, and rendering the monthly/prorated breakdown with formatCurrency alongside the Enable CTA. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…name - Each project row in the organization billing breakdown now iterates its resources for addon_* entries (amount > 0) and renders them as child rows (e.g. Premium Geo DB under the project it was enabled on). The backend already filters project-scoped addons out of the team-level resources response, so the org "Addons" section shows only org-scoped addons (BAA, premiumGeoDBOrg) while project-scoped ones surface where they belong. - Org-level addon labels now read addon.name from the UsageResource payload that the getAggregation endpoint populates from billingAddons config. Dropped the hard-coded billingAddonNames map so new addons surface with their proper name without a console update. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…geo-db-addon # Conflicts: # bun.lock # package.json # src/routes/(console)/project-[region]-[project]/settings/+page.svelte
…geo-db-addon # Conflicts: # bun.lock # package.json
…DK methods" This reverts commit 304142c.
…geo-db-addon # Conflicts: # src/routes/(console)/project-[region]-[project]/settings/+page.svelte # src/routes/(console)/project-[region]-[project]/settings/+page.ts
| ...resources | ||
| .filter((r) => r.resourceId?.startsWith('addon_') && (r.amount ?? 0) > 0) | ||
| .map((addon) => | ||
| createRow({ | ||
| id: `addon-${addon.resourceId}`, | ||
| label: addon.name || addon.resourceId, | ||
| resource: addon, | ||
| usageFormatter: ({ value }) => formatNum(value), | ||
| priceFormatter: ({ amount }) => formatCurrency(amount), | ||
| includeProgress: false | ||
| }) | ||
| ), |
There was a problem hiding this comment.
Possible double-counting of addon charges in plan summary
The top-level addons section (line 252–275) already creates a billing row for every addon_-prefixed resource found in currentAggregation.resources. If the billing API also surfaces those same addon resources inside projectData.resources (the per-project breakdown), each project-scoped addon (e.g. Premium Geo DB) will appear as both a top-level line item and a child row — showing the same charge twice to the user.
Before shipping, confirm whether the cloud billing API places project-level addon charges exclusively in breakdown[].resources (making the top-level filter skip them) or in both places. If the former, this code is correct; if the latter, the top-level addons filter needs to exclude resources that are already accounted for at the project level (or vice-versa).
…geo-db-addon # Conflicts: # bun.lock # package.json
…geo-db-addon # Conflicts: # bun.lock # package.json
…h for premium geoDB Two missing pieces vs the BAA addon flow: 1. After Stripe redirects back from 3DS with ?type=confirm-addon&addonId=..., the page didn't read the query params or call the confirmations endpoint, so the addon stayed pending forever. Port the onMount handler from BAA.svelte. 2. The pending-state action was "Cancel & retry" which deleted the addon and forced a fresh 3DS flow. That's wasteful when the payment just needs a server-side status sync. Replace with "Refresh" — calls the confirmations endpoint, which live-queries Stripe and activates the addon if the PaymentIntent has transitioned to succeeded. Backend cleans up on 402.
Summary
Adds a Premium Geo DB section to the project settings page so users can enable and disable the premium geolocation addon per-project on cloud.
The section supports the full addon lifecycle, mirroring the BAA pattern at the organization level:
Uses the new project-scoped SDK methods shipped with the cloud update:
listAddons,createPremiumGeoDBAddon, anddeleteAddon. Bumps the@appwrite.io/consoleSDK pin accordingly.Test plan
🤖 Generated with Claude Code