Skip to content

feat: add Premium Geo DB addon to project settings#2981

Open
lohanidamodar wants to merge 23 commits into
mainfrom
feat/project-premium-geo-db-addon
Open

feat: add Premium Geo DB addon to project settings#2981
lohanidamodar wants to merge 23 commits into
mainfrom
feat/project-premium-geo-db-addon

Conversation

@lohanidamodar
Copy link
Copy Markdown
Member

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:

  • Upgrade prompt when the current plan does not support the addon
  • Enable flow with optional 3DS payment authentication
  • Pending state with cancel & retry option (if payment was interrupted)
  • Active state with disable action
  • Scheduled-for-removal state with re-enable action

Uses the new project-scoped SDK methods shipped with the cloud update: listAddons, createPremiumGeoDBAddon, and deleteAddon. Bumps the @appwrite.io/console SDK pin accordingly.

Test plan

  • Navigate to a cloud project's settings as an org owner on a plan that supports Premium Geo DB → section appears with Enable CTA
  • Click Enable → modal confirms and enables the addon (3DS where required); section transitions to Active
  • Click Disable → confirms removal at end of billing cycle; section transitions to Scheduled-for-removal
  • Click Keep Premium Geo DB while Scheduled-for-removal → returns to Active
  • On a plan that doesn't support the addon → shows Upgrade plan CTA / "not available" copy
  • On self-hosted mode → section is hidden

🤖 Generated with Claude Code

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-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 18, 2026

Greptile Summary

This PR adds a Premium Geo DB addon section to the project settings page, enabling users to enable, disable, and manage the addon's full lifecycle (pending, active, scheduled-for-removal). It also bumps the @appwrite.io/console SDK pin and updates several address/billing components from Models.Locale to Models.CloudLocale.

  • New premiumGeoDB.svelte component and its enable/disable modals mirror the existing BAA pattern, including an onMount handler for 3DS redirect return and graceful degradation when addon/price APIs fail.
  • planSummary.svelte removes the hardcoded billingAddonNames map and adds per-project addon charge rows to the project breakdown section.
  • Six unrelated address/billing Svelte files receive a mechanical Models.Locale \u2192 Models.CloudLocale type-only update.

Confidence Score: 3/5

The addon state detection may silently fail if the API key casing does not match the camelCase string used in the filter, combined with unresolved payment flow gaps in the enable modal.

The core addon state detection in premiumGeoDB.svelte filters by a camelCase key string inconsistent with the all-lowercase key used by the established BAA component. If the API returns a lowercase key, both the reactive state derivation and the onMount fallback lookup would silently produce undefined, making isPending, isActive, and isScheduledForRemoval always false. The enable modal also has several open gaps from prior review rounds.

premiumGeoDB.svelte (addon key string) and premiumGeoDBEnableModal.svelte (payment flow gaps) need the most attention before this ships.

Important Files Changed

Filename Overview
src/routes/(console)/project-[region]-[project]/settings/premiumGeoDB.svelte New component implementing the Premium Geo DB addon lifecycle; has an onMount 3DS return handler, but the addon key string 'premiumGeoDB' is camelCase and may not match what the API returns (BAA uses lowercase 'baa'), which would silently break all addon state detection.
src/routes/(console)/project-[region]-[project]/settings/premiumGeoDBEnableModal.svelte New enable modal; missing redirectIfRequired: true in confirmPayment and does not inspect the outcome; also missing the !addonPrice guard on the submit button that BAAEnableModal uses to prevent enabling before the price is loaded.
src/routes/(console)/project-[region]-[project]/settings/premiumGeoDBDisableModal.svelte New disable modal; straightforward implementation calling deleteAddon and invalidating dependencies on success. No issues found.
src/routes/(console)/project-[region]-[project]/settings/+page.ts Adds listAddons and getAddonPrice calls guarded by isCloud, using .catch to null for graceful degradation. Removed helpful comments explaining why read-only permission errors are silenced.
src/routes/(console)/project-[region]-[project]/settings/+page.svelte Adds PremiumGeoDB section inside isCloud and canWriteProjects guard. Clean integration.
src/routes/(console)/organization-[organization]/billing/planSummary.svelte Removes hardcoded billingAddonNames map in favour of addon.name (risks blank label if API omits name), and adds per-project addon rows that may double-count charges already present in the top-level addons aggregation.
src/routes/(console)/organization-[organization]/settings/Soc2.svelte Type update from Models.Locale to Models.CloudLocale, matching the same change made to all other address/billing Svelte files in this PR.

Reviews (20): Last reviewed commit: "fix: rename Models.Locale to Models.Clou..." | Re-trigger Greptile

lohanidamodar and others added 4 commits April 19, 2026 11:13
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
…geo-db-addon

# Conflicts:
#	src/routes/(console)/project-[region]-[project]/settings/+page.svelte
#	src/routes/(console)/project-[region]-[project]/settings/+page.ts
Comment on lines +399 to +410
...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
})
),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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).

…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.
The console SDK bump in this PR renamed Locale to CloudLocale,
breaking svelte-check with 7 errors across billing/Soc2/address
components.
Comment on lines +33 to +35
);
$: isPending = premiumGeoDBAddon?.status === 'pending';
$: isActive = premiumGeoDBAddon?.status === 'active';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Addon key casing inconsistency with BAA pattern

The BAA.svelte filter uses the all-lowercase string 'baa', consistent with Appwrite's API key convention. Here 'premiumGeoDB' (camelCase) is used. If the API returns the addon with a lowercase key (following the same pattern as BAA), this find will never match — premiumGeoDBAddon would always be undefined and the component would always render the Enable CTA even when the addon is already active or pending. The same camelCase string is also used in the onMount fallback lookup at line 65, so both detection paths would silently fail. Please confirm the exact key string the API returns for this addon. What string does the API's listAddons response return for the key field of the Premium Geo DB addon — 'premiumGeoDB', 'premiumgeodb', or something else? BAA uses 'baa' (all lowercase), so camelCase here looks inconsistent with that established pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant