Tenant and System Bootstrap Reset
Dev-cycle reset from shell scripts through to system-admin UI
Table of Contents
Background
During development iteration it is necessary to re-run the provisioning wizards without recreating the entire database. Three distinct reset levels are needed:
- Party-level reset (
ores_iam_reset_tenant_fn) — soft-deletes admin-created data (counterparties, org units, books, report definitions) and flips Operational parties back toInactiveso thePartyProvisioningWizardfires on next login. This function already exists. - Tenant bootstrap reset — same as party-level reset, plus re-enables
system.bootstrap_modefor the tenant so theTenantProvisioningWizardalso fires on next login. - System bootstrap reset — purges all non-system tenants, removes the
system admin account, and re-enables
system.bootstrap_modefor the system tenant so theSystemProvisionerWizardfires on next startup.
Shell scripts (reset_tenant.sh, reset_system.sh) and their
underlying SQL functions (ores_iam_reset_tenant_bootstrap_fn,
ores_iam_reset_system_fn) were implemented on branch
feature/dq-publish-pattern, but revealed two issues when smoke-tested:
- The
change_reason_codesystem.admin_resetused in the functions does not exist inores_dq_change_reasons_tbl. - The functions are not
SECURITY DEFINER, so they cannot be invoked by a service DB user that lacks DML rights onores_variability_system_settings_tbl— a service isolation violation waiting to happen when we add the NATS handler.
This plan addresses both issues and completes the reset feature end-to-end:
from a correctly seeded change reason and hardened SQL functions through to
a NATS handler in ores.iam.core and a UI action in the system admin area.
Architecture
Why IAM owns the reset operation
The tenant lifecycle functions (provision, terminate, deprovision,
purge, reset) all live in ores.iam.core and are called from the
IAM service. Bootstrap reset is a tenant lifecycle operation, so it
belongs in the same service.
The SQL functions write across service boundaries (IAM tables and
ores_variability_system_settings_tbl). This is handled the same way
as the existing ores_iam_create_initial_admin_fn provisioner: the
functions are declared SECURITY DEFINER SET search_path = public,
pg_temp so they execute with DDL-owner privileges. The IAM service DB
user only needs EXECUTE on the function — no cross-service DML grant
is required.
Change reason code
system.admin_reset is seeded as a new system change reason in the DQ
change reasons population script. Using system.initial_load would
be semantically incorrect (it means first-ever creation, not re-trigger
by an administrator). A dedicated code gives a clear audit trail.
NATS subjects
Two new subjects in the iam.v1.system namespace:
| Subject | Handler |
|---|---|
iam.v1.system.reset-tenant |
reset_tenant_handler |
iam.v1.system.reset |
reset_system_handler |
Only a user with the SuperAdmin role may invoke these subjects. The
handler validates the role before executing the SQL function.
UI placement
- Reset Tenant — context menu on the tenant row in the system admin
tenant list (the existing
TenantsWindowor equivalent). Opens a confirmation dialog, then runs the NATS call through the workflow steps widget pattern so progress is visible. - Reset System — a dedicated action in the system settings / admin area, behind a second confirmation (type "yes" style) given its destructive scope.
Implementation Plan
Phase 1 — Seed system.admin_reset change reason [DONE]
Tasks
- Add
system.admin_resetto the system change reasons population script (projects/ores.sql/populate/dq/). The reason should be seeded for the system tenant only; other tenants inherit system change reasons via the shared-governance lookup inores_dq_validate_change_reason_fn. - Apply to the running database.
Verify the reason is visible:
SELECT code FROM ores_dq_change_reasons_tbl WHERE code = 'system.admin_reset' AND tenant_id = ores_utility_system_tenant_id_fn() AND valid_to = ores_utility_infinity_timestamp_fn();
Phase 2 — Harden SQL functions [DONE]
Tasks
- Add
SECURITY DEFINER SET search_path = public, pg_tempto bothores_iam_reset_tenant_bootstrap_fnandores_iam_reset_system_fnin their respectivecreate/iam/SQL files. - Change
change_reason_codeargument fromsystem.initial_load(placeholder) tosystem.admin_resetin both functions. - Re-apply both functions to the running database.
Smoke-test via shell scripts:
./projects/ores.sql/reset_tenant.sh -t barclays_plc -y
Phase 3 — IAM messaging protocol [DONE]
Tasks
- Add protocol types to
ores.iam.api:reset_tenant_command(field:tenant_code: string)reset_tenant_result(fields:success: bool,message: string)reset_system_command(no fields)reset_system_result(fields:success: bool,message: string)
- Declare NATS subjects in the IAM API protocol header:
iam.v1.system.reset-tenantandiam.v1.system.reset. - No CMakeLists changes needed; handlers are header-only and
GLOB_RECURSEpicks them up automatically.
Phase 4 — IAM service handlers [DONE]
Tasks
- Implement
reset_handlerinores.iam.core(header-only,include/ores.iam.core/messaging/reset_handler.hpp):reset_tenant(): decodereset_tenant_command, checkiam::system:reset-tenantpermission, callores_iam_reset_tenant_bootstrap_fn($1)in system tenant contextreset_system(): decodereset_system_command, checkiam::system:resetpermission, callores_iam_reset_system_fn()
- Subscribe both handlers in
registrar.cpp. - Build verified green.
Phase 5 — Qt UI [DONE]
Tasks
- Reset Tenant action:
- Added "Reset" toolbar button to
TenantMdiWindow(enabled on selection,ArrowRotateCounterclockwiseicon). - Confirmation dialog explains what is wiped vs. preserved.
- Sends
reset_tenant_commandviaQtConcurrent::run+QFutureWatcher; refreshes model and emitstenantReseton success. TenantControllerwirestenantResetto a status bar message.
- Added "Reset" toolbar button to
- Reset System action:
- Added "Reset &System…" to the System menu in
AdminPlugin, separated from the Configuration submenu by a separator. - Two-step confirmation: explanatory dialog + typed
YESrequired. - Sends
reset_system_commandviaQtConcurrent::run+QFutureWatcher; shows information dialog on success instructing the user to restart.
- Added "Reset &System…" to the System menu in
- Signals emitted on success; tenant list refreshes automatically after Reset Tenant.
Files Affected
| File | Change |
|---|---|
projects/ores.sql/populate/dq/dq_change_reasons_populate.sql |
Add system.admin_reset reason |
projects/ores.sql/create/iam/iam_tenant_bootstrap_reset_create.sql |
SECURITY DEFINER + correct reason code |
projects/ores.sql/create/iam/iam_system_reset_create.sql |
SECURITY DEFINER + correct reason code |
projects/ores.sql/reset_tenant.sh |
Already created; shell script |
projects/ores.sql/reset_system.sh |
Already created; shell script |
projects/ores.iam.api/include/ores.iam.api/messaging/reset_protocol.hpp |
New protocol types |
projects/ores.iam.core/include/ores.iam.core/messaging/reset_handler.hpp |
Header-only handler (both reset_tenant + reset_system) |
projects/ores.iam.core/src/messaging/registrar.cpp |
Subscribe both handlers |
projects/ores.qt.admin/include/ores.qt/TenantMdiWindow.hpp |
Add resetAction_, resetSelected(), tenantReset signal |
projects/ores.qt.admin/src/TenantMdiWindow.cpp |
Implement Reset toolbar button + NATS call |
projects/ores.qt.admin/include/ores.qt/TenantController.hpp |
Add onTenantReset slot |
projects/ores.qt.admin/src/TenantController.cpp |
Wire tenantReset signal |
projects/ores.qt.admin/include/ores.qt/AdminPlugin.hpp |
Add act_reset_system_, on_reset_system() |
projects/ores.qt.admin/src/AdminPlugin.cpp |
Implement Reset System menu item + NATS call |