feat(tenants): first-class tenant maintenance (registry, admin API, UI)#220
Open
angela-helios wants to merge 9 commits into
Open
feat(tenants): first-class tenant maintenance (registry, admin API, UI)#220angela-helios wants to merge 9 commits into
angela-helios wants to merge 9 commits into
Conversation
Make tenants first-class managed entities. Until now a "tenant" was only an implicit identifier string, resolved per request; there was no registry, no metadata, and no lifecycle API. This adds list / add / delete across the stack. Persistence (helios-persistence): - ResourceStorage gains a tenant-registry surface (default-off, so other backends are unaffected): supports_tenant_registry, list_tenants, get_tenant, register_tenant, deregister_tenant, purge_tenant_data, plus the TenantRecord type (id, optional display_name, created_at). - SQLite: schema v13 adds a `tenants` table; the methods are implemented and covered by unit tests (registry CRUD + data purge). REST API (helios-rest): - GET/POST/DELETE /admin/tenants. List merges the registry with live per-tenant resource counts (count_by_tenant) so data-only tenants are surfaced too (registered:false, created_at:null). Add validates the id and 409s on duplicates; delete is deregister-only unless ?purge=true tears down data. Mounted in the console *admin* tier: system-context scope + auth, and audit-logged. 501 when the backend has no registry. - create_app_with_auth_arc so the binary can share the backend Arc with the UI read path without giving up the FHIR app's handle. - 8 integration tests (list/add/delete, data-only discovery, purge, 404). Web UI (helios-ui): - Server-rendered, htmx-driven /ui/tenants page in the Dashboard V1.1 style: two stat cards (tenants, resources), search, an add slide-over, and a per-row delete with confirm. Reflects the reviewed scope — no status / provisioning / storage / routing columns; id shown under the display name; Created from the registry. New i18n keys in en/es/de. - mount() now takes the storage handle; hfs wires it on the SQLite path. Implements the tenant-maintenance issue. Verified end to end against a running hfs (API + UI add/delete/search).
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
# Conflicts: # crates/hfs/src/main.rs # crates/persistence/src/backends/sqlite/schema.rs # crates/ui/assets/app.css
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makes tenants first-class managed entities — list / add / delete across persistence, the REST API, and the web UI. Until now a "tenant" was only an implicit identifier string resolved per request; there was no registry, no metadata, and no lifecycle API. Implements the tenant-maintenance issue.
Built to the reviewed scope (the mockup feedback): the page keeps search, resources, created, and delete; it drops the status / provisioning / storage-backend cards and the routing column (all server-global or non-existent, not per-tenant), and distinguishes the id (used in the API) from an optional human-friendly display name.
Persistence (
helios-persistence)ResourceStoragegains a tenant-registry surface, default-off so other backends are unaffected:supports_tenant_registry,list_tenants,get_tenant,register_tenant,deregister_tenant,purge_tenant_data, plus theTenantRecordtype (id, optionaldisplay_name,created_at).tenantstable; methods implemented, with unit tests (registry CRUD + tenant-data purge).REST API (
helios-rest)GET/POST/DELETE /admin/tenants. List merges the registry with live per-tenant counts (count_by_tenant), so tenants that only have data still appear (registered:false,created_at:null). Add validates the id and409s on duplicates. Delete is deregister-only unless?purge=truealso tears down data (destructive, opt-in).501when the backend has no registry.Web UI (
helios-ui)/ui/tenantsin the Dashboard V1.1 style: two stat cards, search, an add slide-over, and a per-row delete with confirm. Every mutation returns the refreshed table fragment (works with or without the swap). New nav item; i18n keys added across en/es/de (parity test green).mount()now takes the storage handle;hfsshares the SQLite backend Arc via the newcreate_app_with_auth_arc.Verified end to end
Against a running
hfs(default SQLite): create tenants via the API and the UI form, data-only tenants discovered with counts, search filtering, delete/deregister, and the JSON API reflecting UI mutations. Screenshot below.Scope notes / follow-ups
501); wiring theirlist/register/purge(and the schema-/database-per-tenantdrop_*helpers) is a follow-up.hfsbinary wires the UI tenant read/write path on the SQLite serve path; other backends passNone(page shows "registry unavailable"). Threading storage through their serve paths is a follow-up.created_atis captured for organically-created tenants) is deliberately out of scope here — the hot write path is untouched.Closes the tenant-maintenance issue.

