Skip to content

feat: permanent console user deletion for self-hosted (#11393)#3117

Open
schneidermr wants to merge 3 commits into
appwrite:mainfrom
schneidermr:feat-11393-permanent-console-user-delete
Open

feat: permanent console user deletion for self-hosted (#11393)#3117
schneidermr wants to merge 3 commits into
appwrite:mainfrom
schneidermr:feat-11393-permanent-console-user-delete

Conversation

@schneidermr

@schneidermr schneidermr commented Jul 11, 2026

Copy link
Copy Markdown

Summary

Fixes appwrite/appwrite#11393.

Self-hosted administrators could only remove members from an organization. The console account remained and could sign in and create new organizations ("shadow accounts").

This PR adds GUI support for permanent platform account deletion on self-hosted instances:

  1. Members → Remove — optional checkbox: Also permanently delete their account from the entire system
  2. Organization → Platform users tab (owners only) — list all console accounts and permanently delete them
  3. SDK helper sdk.forConsoleInOrganization(orgId) — sets X-Appwrite-Organization so the Users API receives users.write on the console project

Cloud is unchanged (no permanent-delete UI, no Platform users tab).

Why this works

The backend already supports permanent deletion:

DELETE /v1/users/{userId}
X-Appwrite-Project: console
X-Appwrite-Organization: {orgId}

A prior attempt (appwrite/appwrite#11587) only added a legacy SDK stub and closed without GUI changes. The console already has @appwrite.io/console Users service — the missing piece was UI + organization-scoped client.

Related backend PR

Companion safeguards: appwrite/appwrite#12850 — block self-delete via Users API and deletion of the last console user.

Test plan

  • Unit tests for permanent-delete gating (consoleUsers.test.ts — 8 tests)
  • Local Appwrite 1.9.5 reproduction:
    • Shadow user can log in and create own org after existing as orphaned account
    • DELETE /v1/users/{id} with org context → 204, login fails afterward
    • Without org context → 401 missing users.write
  • bun run check — 0 errors on changed files
  • Manual GUI: Platform users tab visible on self-hosted only
  • Manual GUI: permanent delete from Members checkbox
  • Manual GUI: permanent delete from Platform users page
  • Confirm cloud build does not show Platform users / permanent checkbox

Security notes

  • Permanent delete UI is self-hosted only (isSelfHosted)
  • Self-delete is blocked in the UI (fail closed if actor id missing)
  • Last-user / self-delete API guards are in the companion backend PR
  • Organization context is required for scopes (backend already enforces membership in the org header)

Fixes appwrite/appwrite#11393

Self-hosted organization owners can permanently delete platform
(console) accounts, not only remove org memberships. Adds a Platform
users page and an optional permanent-delete path when removing members.
@greptile-apps

greptile-apps Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds GUI support for permanent console-account deletion on self-hosted Appwrite instances — filling the gap where removed members could still sign in as "shadow accounts." The feature is correctly gated behind isSelfHosted throughout, and the companion backend PR provides last-user/self-delete API guards.

  • deleteMember.svelte gains an optional "permanently delete" checkbox (self-hosted + owner only); the implementation correctly makes a single Users.delete call instead of deleting the membership first, avoiding partial-failure states.
  • platform-users/ is a new route (load function + page + dialog) listing all console accounts with per-user permanent-delete actions; the route guard redirects non-self-hosted and non-owner visitors before making any API calls.
  • sdk.forConsoleUsersInOrganization creates a narrow Users client stamped with X-Appwrite-Organization on each call, matching the existing organization() helper pattern.

Confidence Score: 5/5

Safe to merge; all permanent-delete paths are correctly gated to self-hosted owners and the single-call deletion strategy avoids partial-failure shadow accounts

The logic across all three delete surfaces (member checkbox, platform-users page, route guard) is consistent and fail-closed. The helper functions have complete unit-test coverage. No data-loss or auth-bypass paths were found in the new code. The trade-offs in the SDK client (per-call allocation, impersonation registration) are acknowledged by the author and match the existing organization() helper pattern.

No files require special attention beyond what has already been discussed in prior review threads.

Important Files Changed

Filename Overview
src/lib/helpers/consoleUsers.ts New pure-function helpers for gating permanent deletion; fully covered by unit tests; logic is correct and fail-closed
src/lib/helpers/consoleUsers.test.ts 8 unit tests covering cloud/self-hosted gating, self-delete block, missing-id cases, and deletion mode resolution — complete coverage
src/lib/stores/sdk.ts Adds forConsoleUsersInOrganization — creates a fresh Client per call and stamps X-Appwrite-Organization; narrower than the full console SDK; not registered with registerImpersonationClients (same trade-off as the existing organization() helper)
src/routes/(console)/organization-[organization]/deleteMember.svelte Substantial rework to Svelte 5 runes; adds permanent-delete checkbox guarded by canPermanentlyDeleteConsoleUser; ordering (single API call before membership invalidation) and notification logic are correct
src/routes/(console)/organization-[organization]/platform-users/+page.ts Route guard redirects non-self-hosted and non-owner visitors; loads paginated user list with search; error handling uses standard SvelteKit error() pattern
src/routes/(console)/organization-[organization]/platform-users/+page.svelte New Platform users page; uses Svelte 5 runes for script-block state but retains Svelte 4 slot syntax (let:root, svelte:fragment slot) and on:click event directives from @appwrite.io/pink-svelte components
src/routes/(console)/organization-[organization]/platform-users/deleteConsoleUser.svelte New permanent-delete confirmation dialog; fully uses Svelte 5 runes; correctly guarded by canPermanentlyDeleteConsoleUser with a disabled prop and an early-return function guard
src/routes/(console)/organization-[organization]/header.svelte Adds 'Platform users' nav tab, correctly disabled unless isSelfHosted && $isOwner; minimal, safe change
src/lib/actions/analytics.ts Adds ConsoleUserDelete analytics event enum value; trivial, correct
src/lib/constants.ts Adds CONSOLE_USERS dependency key for cache invalidation; correct, follows existing pattern

Reviews (3): Last reviewed commit: "fix(sdk): use fresh client for org-scope..." | Re-trigger Greptile

Comment thread src/routes/(console)/organization-[organization]/platform-users/+page.ts Outdated
Comment thread src/lib/stores/sdk.ts Outdated
- Gate platform-users load on owner role (clean redirect)
- Migrate new/touched components to Svelte 5 runes
- Narrow org-scoped Users helper with reused Client
Comment thread src/lib/stores/sdk.ts Outdated
Avoid shared-client header staleness with impersonation by building a
new Client per call (matching organization()), while still returning
only a narrow Users instance.
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.

No (GUI?) method for deleting (another) user permanently from entire/all AppWrite system/environments.

1 participant