Skip to content

feat(tenants): first-class tenant maintenance (registry, admin API, UI)#220

Open
angela-helios wants to merge 9 commits into
mainfrom
feat/tenant-maintenance
Open

feat(tenants): first-class tenant maintenance (registry, admin API, UI)#220
angela-helios wants to merge 9 commits into
mainfrom
feat/tenant-maintenance

Conversation

@angela-helios

@angela-helios angela-helios commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

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)

  • 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; 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 and 409s on duplicates. Delete is deregister-only unless ?purge=true also tears down data (destructive, opt-in).
  • Mounted in the console admin tier — system-context scope + authentication — and audit-logged. Returns 501 when the backend has no registry.
  • 8 integration tests (list/add/delete, data-only discovery, purge, 404, invalid ids, conflict).

Web UI (helios-ui)

  • Server-rendered, htmx-driven /ui/tenants in 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; hfs shares the SQLite backend Arc via the new create_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

  • Registry + purge are implemented for SQLite (the default). Postgres/Mongo/composite keep the default-off registry (API returns 501); wiring their list/register/purge (and the schema-/database-per-tenant drop_* helpers) is a follow-up.
  • The hfs binary wires the UI tenant read/write path on the SQLite serve path; other backends pass None (page shows "registry unavailable"). Threading storage through their serve paths is a follow-up.
  • Auto-registering a tenant on first write (so created_at is captured for organically-created tenants) is deliberately out of scope here — the hot write path is untouched.

Closes the tenant-maintenance issue.
Screenshot 2026-07-08 105134
Screenshot 2026-07-08 105147

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

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

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