Skip to main content
Version: Latest

10. Internal Apply Bridge

10.1 Purpose

Shumoul.MultiTenancyApi generates the settings patch but cannot write it — only Shumoul.BackEnd can resolve a tenant's own database and call IAppSettingService. The internal apply bridge is the one narrow HTTP call that connects them.

Shumoul.MultiTenancyApi (HttpOnboardingTenantSettingsApplier)
→ POST {BackEndBaseUrl}/api/internal/onboarding/apply-settings-patch
Header: X-Shumoul-Internal-Key: {shared secret}
Header: X-Correlation-Id: {guid}
Header: TenantId: {tenant identifier}
→ Shumoul.BackEnd (OnboardingInternalController)
→ InternalOnboardingSettingsPatchService.ApplyAsync(...)
→ IAppSettingService

This endpoint is service-to-service only. It is not part of the public API surface, must never be called by Angular, and is deliberately unreachable by any user JWT — it doesn't accept one at all.

10.2 Request contract

{
"tenantId": "555001",
"tenantIdentifier": null,
"sessionId": "9f250000-9d35-f628-3eb5-08dedcf802a3",
"settingsPatchJson": "{\"CashierAppsSettings\":{\"Enable_Cash_Sales\":true}}",
"requestSource": "Shumoul.MultiTenancyApi",
"correlationId": "0d4c21c8-5ed5-4c19-9862-89c410bdf2a3"
}

tenantIdentifier is reserved/unused in this codebase — tenant resolution is entirely driven by the TenantId header (see §10.4) and the tenantId field is only used for the hard-fail consistency check.

10.3 Response contract

{
"succeeded": true,
"sessionId": "9f250000-9d35-f628-3eb5-08dedcf802a3",
"tenantId": "555001",
"beforeSettingsJson": "{...}",
"afterSettingsJson": "{...}",
"appliedPatchJson": "{\"CashierAppsSettings\":{\"Enable_Cash_Sales\":true}}",
"appliedGroups": ["CashierAppsSettings"],
"ignoredGroups": [],
"warnings": [],
"errors": [],
"correlationId": "0d4c21c8-5ed5-4c19-9862-89c410bdf2a3"
}

10.4 Security model

CheckBehavior
Missing X-Shumoul-Internal-Key header401 Unauthorized
Header present but doesn't match InternalServiceAuthSettings:OnboardingApplyApiKey403 Forbidden
Key valid, but the resolved tenant (from the TenantId header, via Shumoul.BackEnd's own HeaderStrategy) doesn't match the request body's tenantId502 Bad Gateway, "Tenant could not be resolved."before IAppSettingService is ever touched
sessionId empty or tenantId blank400 Bad Request

The tenant-mismatch check exists specifically so a bad or missing TenantId header can never silently fall through to the wrong tenant's — or the host's own — database. This is enforced by InternalOnboardingSettingsPatchService.ApplyAsync's very first check: _tenantInfo is null || _tenantInfo.Id != request.TenantId.

10.5 Hidden from Swagger

OnboardingInternalController carries [ApiExplorerSettings(IgnoreApi = true)] — it never appears in Shumoul.Api's generated swagger.json, so it won't show up for API consumers browsing the documented surface. This was independently re-verified (0 matches for apply-settings-patch in the full generated document) as part of the Phase 1.4–1.6 security hardening passes.

10.6 Correlation

Every call carries an X-Correlation-Id (generated by the caller if not already present); both hosts log it alongside tenant id, session id, applied/ignored group counts, and warning/error counts — use it to trace a single apply attempt across both hosts' logs.